2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "tdb_validate.h"
31 #define DBGC_CLASS DBGC_WINBIND
33 #define WINBINDD_CACHE_VERSION 1
34 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
36 extern struct winbindd_methods reconnect_methods;
38 extern struct winbindd_methods ads_methods;
40 extern struct winbindd_methods builtin_passdb_methods;
43 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
44 * Here are the list of entry types that are *not* stored
45 * as form struct cache_entry in the cache.
48 static const char *non_centry_keys[] = {
53 WINBINDD_CACHE_VERSION_KEYSTR,
57 /************************************************************************
58 Is this key a non-centry type ?
59 ************************************************************************/
61 static bool is_non_centry_key(TDB_DATA kbuf)
65 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
68 for (i = 0; non_centry_keys[i] != NULL; i++) {
69 size_t namelen = strlen(non_centry_keys[i]);
70 if (kbuf.dsize < namelen) {
73 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
80 /* Global online/offline state - False when online. winbindd starts up online
81 and sets this to true if the first query fails and there's an entry in
82 the cache tdb telling us to stay offline. */
84 static bool global_winbindd_offline_state;
86 struct winbind_cache {
92 uint32 sequence_number;
97 void (*smb_panic_fn)(const char *const why) = smb_panic;
99 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
101 static struct winbind_cache *wcache;
103 void winbindd_check_cache_size(time_t t)
105 static time_t last_check_time;
108 if (last_check_time == (time_t)0)
111 if (t - last_check_time < 60 && t - last_check_time > 0)
114 if (wcache == NULL || wcache->tdb == NULL) {
115 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
119 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
120 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
124 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
125 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
126 (unsigned long)st.st_size,
127 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
128 wcache_flush_cache();
132 /* get the winbind_cache structure */
133 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
135 struct winbind_cache *ret = wcache;
137 /* We have to know what type of domain we are dealing with first. */
139 if (domain->internal) {
140 domain->backend = &builtin_passdb_methods;
141 domain->initialized = True;
143 if ( !domain->initialized ) {
144 init_dc_connection( domain );
148 OK. listen up becasue I'm only going to say this once.
149 We have the following scenarios to consider
150 (a) trusted AD domains on a Samba DC,
151 (b) trusted AD domains and we are joined to a non-kerberos domain
152 (c) trusted AD domains and we are joined to a kerberos (AD) domain
154 For (a) we can always contact the trusted domain using krb5
155 since we have the domain trust account password
157 For (b) we can only use RPC since we have no way of
158 getting a krb5 ticket in our own domain
160 For (c) we can always use krb5 since we have a kerberos trust
165 if (!domain->backend) {
167 struct winbindd_domain *our_domain = domain;
169 /* find our domain first so we can figure out if we
170 are joined to a kerberized domain */
172 if ( !domain->primary )
173 our_domain = find_our_domain();
175 if ((our_domain->active_directory || IS_DC)
176 && domain->active_directory
177 && !lp_winbind_rpc_only()) {
178 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
179 domain->backend = &ads_methods;
181 #endif /* HAVE_ADS */
182 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
183 domain->backend = &reconnect_methods;
186 #endif /* HAVE_ADS */
192 ret = SMB_XMALLOC_P(struct winbind_cache);
196 wcache_flush_cache();
202 free a centry structure
204 static void centry_free(struct cache_entry *centry)
208 SAFE_FREE(centry->data);
212 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
214 if (centry->len - centry->ofs < nbytes) {
215 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
216 (unsigned int)nbytes,
217 centry->len - centry->ofs));
224 pull a uint32 from a cache entry
226 static uint32 centry_uint32(struct cache_entry *centry)
230 if (!centry_check_bytes(centry, 4)) {
231 smb_panic_fn("centry_uint32");
233 ret = IVAL(centry->data, centry->ofs);
239 pull a uint16 from a cache entry
241 static uint16 centry_uint16(struct cache_entry *centry)
244 if (!centry_check_bytes(centry, 2)) {
245 smb_panic_fn("centry_uint16");
247 ret = CVAL(centry->data, centry->ofs);
253 pull a uint8 from a cache entry
255 static uint8 centry_uint8(struct cache_entry *centry)
258 if (!centry_check_bytes(centry, 1)) {
259 smb_panic_fn("centry_uint8");
261 ret = CVAL(centry->data, centry->ofs);
267 pull a NTTIME from a cache entry
269 static NTTIME centry_nttime(struct cache_entry *centry)
272 if (!centry_check_bytes(centry, 8)) {
273 smb_panic_fn("centry_nttime");
275 ret = IVAL(centry->data, centry->ofs);
277 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
283 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
285 static time_t centry_time(struct cache_entry *centry)
287 return (time_t)centry_nttime(centry);
290 /* pull a string from a cache entry, using the supplied
293 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
298 len = centry_uint8(centry);
301 /* a deliberate NULL string */
305 if (!centry_check_bytes(centry, (size_t)len)) {
306 smb_panic_fn("centry_string");
309 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
311 smb_panic_fn("centry_string out of memory\n");
313 memcpy(ret,centry->data + centry->ofs, len);
319 /* pull a hash16 from a cache entry, using the supplied
322 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
327 len = centry_uint8(centry);
330 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
335 if (!centry_check_bytes(centry, 16)) {
339 ret = TALLOC_ARRAY(mem_ctx, char, 16);
341 smb_panic_fn("centry_hash out of memory\n");
343 memcpy(ret,centry->data + centry->ofs, 16);
348 /* pull a sid from a cache entry, using the supplied
351 static bool centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
354 sid_string = centry_string(centry, mem_ctx);
355 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
363 pull a NTSTATUS from a cache entry
365 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
369 status = NT_STATUS(centry_uint32(centry));
374 /* the server is considered down if it can't give us a sequence number */
375 static bool wcache_server_down(struct winbindd_domain *domain)
382 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
385 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
390 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
397 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
398 return NT_STATUS_UNSUCCESSFUL;
401 fstr_sprintf( key, "SEQNUM/%s", domain->name );
403 data = tdb_fetch_bystring( wcache->tdb, key );
404 if ( !data.dptr || data.dsize!=8 ) {
405 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
406 return NT_STATUS_UNSUCCESSFUL;
409 domain->sequence_number = IVAL(data.dptr, 0);
410 domain->last_seq_check = IVAL(data.dptr, 4);
412 SAFE_FREE(data.dptr);
414 /* have we expired? */
416 time_diff = now - domain->last_seq_check;
417 if ( time_diff > lp_winbind_cache_time() ) {
418 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
419 domain->name, domain->sequence_number,
420 (uint32)domain->last_seq_check));
421 return NT_STATUS_UNSUCCESSFUL;
424 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
425 domain->name, domain->sequence_number,
426 (uint32)domain->last_seq_check));
431 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
438 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
439 return NT_STATUS_UNSUCCESSFUL;
442 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
444 SIVAL(buf, 0, domain->sequence_number);
445 SIVAL(buf, 4, domain->last_seq_check);
449 if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
450 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
451 return NT_STATUS_UNSUCCESSFUL;
454 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
455 domain->name, domain->sequence_number,
456 (uint32)domain->last_seq_check));
462 refresh the domain sequence number. If force is true
463 then always refresh it, no matter how recently we fetched it
466 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
470 time_t t = time(NULL);
471 unsigned cache_time = lp_winbind_cache_time();
473 if ( IS_DOMAIN_OFFLINE(domain) ) {
479 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
480 /* trying to reconnect is expensive, don't do it too often */
481 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
486 time_diff = t - domain->last_seq_check;
488 /* see if we have to refetch the domain sequence number */
489 if (!force && (time_diff < cache_time) &&
490 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
491 NT_STATUS_IS_OK(domain->last_status)) {
492 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
496 /* try to get the sequence number from the tdb cache first */
497 /* this will update the timestamp as well */
499 status = fetch_cache_seqnum( domain, t );
500 if (NT_STATUS_IS_OK(status) &&
501 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
502 NT_STATUS_IS_OK(domain->last_status)) {
506 /* important! make sure that we know if this is a native
507 mode domain or not. And that we can contact it. */
509 if ( winbindd_can_contact_domain( domain ) ) {
510 status = domain->backend->sequence_number(domain,
511 &domain->sequence_number);
513 /* just use the current time */
514 status = NT_STATUS_OK;
515 domain->sequence_number = time(NULL);
519 /* the above call could have set our domain->backend to NULL when
520 * coming from offline to online mode, make sure to reinitialize the
521 * backend - Guenther */
524 if (!NT_STATUS_IS_OK(status)) {
525 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
526 domain->sequence_number = DOM_SEQUENCE_NONE;
529 domain->last_status = status;
530 domain->last_seq_check = time(NULL);
532 /* save the new sequence number in the cache */
533 store_cache_seqnum( domain );
536 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
537 domain->name, domain->sequence_number));
543 decide if a cache entry has expired
545 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
547 /* If we've been told to be offline - stay in that state... */
548 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
549 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
550 keystr, domain->name ));
554 /* when the domain is offline return the cached entry.
555 * This deals with transient offline states... */
557 if (!domain->online) {
558 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
559 keystr, domain->name ));
563 /* if the server is OK and our cache entry came from when it was down then
564 the entry is invalid */
565 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
566 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
567 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
568 keystr, domain->name ));
572 /* if the server is down or the cache entry is not older than the
573 current sequence number then it is OK */
574 if (wcache_server_down(domain) ||
575 centry->sequence_number == domain->sequence_number) {
576 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
577 keystr, domain->name ));
581 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
582 keystr, domain->name ));
588 static struct cache_entry *wcache_fetch_raw(char *kstr)
591 struct cache_entry *centry;
594 key = string_tdb_data(kstr);
595 data = tdb_fetch(wcache->tdb, key);
601 centry = SMB_XMALLOC_P(struct cache_entry);
602 centry->data = (unsigned char *)data.dptr;
603 centry->len = data.dsize;
606 if (centry->len < 8) {
607 /* huh? corrupt cache? */
608 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
613 centry->status = centry_ntstatus(centry);
614 centry->sequence_number = centry_uint32(centry);
620 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
621 number and return status
623 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
624 struct winbindd_domain *domain,
625 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
626 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
627 struct winbindd_domain *domain,
628 const char *format, ...)
632 struct cache_entry *centry;
634 if (!winbindd_use_cache()) {
638 refresh_sequence_number(domain, false);
640 va_start(ap, format);
641 smb_xvasprintf(&kstr, format, ap);
644 centry = wcache_fetch_raw(kstr);
645 if (centry == NULL) {
650 if (centry_expired(domain, kstr, centry)) {
652 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
653 kstr, domain->name ));
660 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
661 kstr, domain->name ));
667 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
668 static void wcache_delete(const char *format, ...)
674 va_start(ap, format);
675 smb_xvasprintf(&kstr, format, ap);
678 key = string_tdb_data(kstr);
680 tdb_delete(wcache->tdb, key);
685 make sure we have at least len bytes available in a centry
687 static void centry_expand(struct cache_entry *centry, uint32 len)
689 if (centry->len - centry->ofs >= len)
692 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
695 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
696 smb_panic_fn("out of memory in centry_expand");
701 push a uint32 into a centry
703 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
705 centry_expand(centry, 4);
706 SIVAL(centry->data, centry->ofs, v);
711 push a uint16 into a centry
713 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
715 centry_expand(centry, 2);
716 SIVAL(centry->data, centry->ofs, v);
721 push a uint8 into a centry
723 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
725 centry_expand(centry, 1);
726 SCVAL(centry->data, centry->ofs, v);
731 push a string into a centry
733 static void centry_put_string(struct cache_entry *centry, const char *s)
738 /* null strings are marked as len 0xFFFF */
739 centry_put_uint8(centry, 0xFF);
744 /* can't handle more than 254 char strings. Truncating is probably best */
746 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
749 centry_put_uint8(centry, len);
750 centry_expand(centry, len);
751 memcpy(centry->data + centry->ofs, s, len);
756 push a 16 byte hash into a centry - treat as 16 byte string.
758 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
760 centry_put_uint8(centry, 16);
761 centry_expand(centry, 16);
762 memcpy(centry->data + centry->ofs, val, 16);
766 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
769 centry_put_string(centry, sid_to_fstring(sid_string, sid));
774 put NTSTATUS into a centry
776 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
778 uint32 status_value = NT_STATUS_V(status);
779 centry_put_uint32(centry, status_value);
784 push a NTTIME into a centry
786 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
788 centry_expand(centry, 8);
789 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
791 SIVAL(centry->data, centry->ofs, nt >> 32);
796 push a time_t into a centry - use a 64 bit size.
797 NTTIME here is being used as a convenient 64-bit size.
799 static void centry_put_time(struct cache_entry *centry, time_t t)
801 NTTIME nt = (NTTIME)t;
802 centry_put_nttime(centry, nt);
806 start a centry for output. When finished, call centry_end()
808 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
810 struct cache_entry *centry;
815 centry = SMB_XMALLOC_P(struct cache_entry);
817 centry->len = 8192; /* reasonable default */
818 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
820 centry->sequence_number = domain->sequence_number;
821 centry_put_ntstatus(centry, status);
822 centry_put_uint32(centry, centry->sequence_number);
827 finish a centry and write it to the tdb
829 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
830 static void centry_end(struct cache_entry *centry, const char *format, ...)
836 if (!winbindd_use_cache()) {
840 va_start(ap, format);
841 smb_xvasprintf(&kstr, format, ap);
844 key = string_tdb_data(kstr);
845 data.dptr = centry->data;
846 data.dsize = centry->ofs;
848 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
852 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
853 NTSTATUS status, const char *domain_name,
854 const char *name, const DOM_SID *sid,
855 enum lsa_SidType type)
857 struct cache_entry *centry;
860 centry = centry_start(domain, status);
863 centry_put_uint32(centry, type);
864 centry_put_sid(centry, sid);
865 fstrcpy(uname, name);
867 centry_end(centry, "NS/%s/%s", domain_name, uname);
868 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
869 uname, sid_string_dbg(sid), nt_errstr(status)));
873 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
874 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
876 struct cache_entry *centry;
879 centry = centry_start(domain, status);
883 if (NT_STATUS_IS_OK(status)) {
884 centry_put_uint32(centry, type);
885 centry_put_string(centry, domain_name);
886 centry_put_string(centry, name);
889 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
890 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
891 name, nt_errstr(status)));
896 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
898 struct cache_entry *centry;
901 if (is_null_sid(&info->user_sid)) {
905 centry = centry_start(domain, status);
908 centry_put_string(centry, info->acct_name);
909 centry_put_string(centry, info->full_name);
910 centry_put_string(centry, info->homedir);
911 centry_put_string(centry, info->shell);
912 centry_put_uint32(centry, info->primary_gid);
913 centry_put_sid(centry, &info->user_sid);
914 centry_put_sid(centry, &info->group_sid);
915 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
917 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
921 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
923 struct samr_DomInfo12 *lockout_policy)
925 struct cache_entry *centry;
927 centry = centry_start(domain, status);
931 centry_put_nttime(centry, lockout_policy->lockout_duration);
932 centry_put_nttime(centry, lockout_policy->lockout_window);
933 centry_put_uint16(centry, lockout_policy->lockout_threshold);
935 centry_end(centry, "LOC_POL/%s", domain->name);
937 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
944 static void wcache_save_password_policy(struct winbindd_domain *domain,
946 struct samr_DomInfo1 *policy)
948 struct cache_entry *centry;
950 centry = centry_start(domain, status);
954 centry_put_uint16(centry, policy->min_password_length);
955 centry_put_uint16(centry, policy->password_history_length);
956 centry_put_uint32(centry, policy->password_properties);
957 centry_put_nttime(centry, policy->max_password_age);
958 centry_put_nttime(centry, policy->min_password_age);
960 centry_end(centry, "PWD_POL/%s", domain->name);
962 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
967 /***************************************************************************
968 ***************************************************************************/
970 static void wcache_save_username_alias(struct winbindd_domain *domain,
972 const char *name, const char *alias)
974 struct cache_entry *centry;
977 if ( (centry = centry_start(domain, status)) == NULL )
980 centry_put_string( centry, alias );
982 fstrcpy(uname, name);
984 centry_end(centry, "NSS/NA/%s", uname);
986 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
991 static void wcache_save_alias_username(struct winbindd_domain *domain,
993 const char *alias, const char *name)
995 struct cache_entry *centry;
998 if ( (centry = centry_start(domain, status)) == NULL )
1001 centry_put_string( centry, name );
1003 fstrcpy(uname, alias);
1005 centry_end(centry, "NSS/AN/%s", uname);
1007 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1009 centry_free(centry);
1012 /***************************************************************************
1013 ***************************************************************************/
1015 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1016 struct winbindd_domain *domain,
1017 const char *name, char **alias )
1019 struct winbind_cache *cache = get_cache(domain);
1020 struct cache_entry *centry = NULL;
1024 if ( domain->internal )
1025 return NT_STATUS_NOT_SUPPORTED;
1030 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1031 return NT_STATUS_NO_MEMORY;
1032 strupper_m(upper_name);
1034 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1036 SAFE_FREE( upper_name );
1041 status = centry->status;
1043 if (!NT_STATUS_IS_OK(status)) {
1044 centry_free(centry);
1048 *alias = centry_string( centry, mem_ctx );
1050 centry_free(centry);
1052 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1053 name, *alias ? *alias : "(none)"));
1055 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1059 /* If its not in cache and we are offline, then fail */
1061 if ( get_global_winbindd_state_offline() || !domain->online ) {
1062 DEBUG(8,("resolve_username_to_alias: rejecting query "
1063 "in offline mode\n"));
1064 return NT_STATUS_NOT_FOUND;
1067 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1069 if ( NT_STATUS_IS_OK( status ) ) {
1070 wcache_save_username_alias(domain, status, name, *alias);
1073 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1074 wcache_save_username_alias(domain, status, name, "(NULL)");
1077 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1078 nt_errstr(status)));
1080 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1081 set_domain_offline( domain );
1087 /***************************************************************************
1088 ***************************************************************************/
1090 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1091 struct winbindd_domain *domain,
1092 const char *alias, char **name )
1094 struct winbind_cache *cache = get_cache(domain);
1095 struct cache_entry *centry = NULL;
1099 if ( domain->internal )
1100 return NT_STATUS_NOT_SUPPORTED;
1105 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1106 return NT_STATUS_NO_MEMORY;
1107 strupper_m(upper_name);
1109 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1111 SAFE_FREE( upper_name );
1116 status = centry->status;
1118 if (!NT_STATUS_IS_OK(status)) {
1119 centry_free(centry);
1123 *name = centry_string( centry, mem_ctx );
1125 centry_free(centry);
1127 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1128 alias, *name ? *name : "(none)"));
1130 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1134 /* If its not in cache and we are offline, then fail */
1136 if ( get_global_winbindd_state_offline() || !domain->online ) {
1137 DEBUG(8,("resolve_alias_to_username: rejecting query "
1138 "in offline mode\n"));
1139 return NT_STATUS_NOT_FOUND;
1142 /* an alias cannot contain a domain prefix or '@' */
1144 if (strchr(alias, '\\') || strchr(alias, '@')) {
1145 DEBUG(10,("resolve_alias_to_username: skipping fully "
1146 "qualified name %s\n", alias));
1147 return NT_STATUS_OBJECT_NAME_INVALID;
1150 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1152 if ( NT_STATUS_IS_OK( status ) ) {
1153 wcache_save_alias_username( domain, status, alias, *name );
1156 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1157 wcache_save_alias_username(domain, status, alias, "(NULL)");
1160 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1161 nt_errstr(status)));
1163 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1164 set_domain_offline( domain );
1170 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
1172 struct winbind_cache *cache = get_cache(domain);
1174 fstring key_str, tmp;
1178 return NT_STATUS_INTERNAL_DB_ERROR;
1181 if (is_null_sid(sid)) {
1182 return NT_STATUS_INVALID_SID;
1185 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1186 return NT_STATUS_INVALID_SID;
1189 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1191 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1193 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1196 SAFE_FREE(data.dptr);
1197 return NT_STATUS_OK;
1200 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1201 as new salted ones. */
1203 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1204 TALLOC_CTX *mem_ctx,
1206 const uint8 **cached_nt_pass,
1207 const uint8 **cached_salt)
1209 struct winbind_cache *cache = get_cache(domain);
1210 struct cache_entry *centry = NULL;
1217 return NT_STATUS_INTERNAL_DB_ERROR;
1220 if (is_null_sid(sid)) {
1221 return NT_STATUS_INVALID_SID;
1224 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1225 return NT_STATUS_INVALID_SID;
1228 /* Try and get a salted cred first. If we can't
1229 fall back to an unsalted cred. */
1231 centry = wcache_fetch(cache, domain, "CRED/%s",
1232 sid_to_fstring(tmp, sid));
1234 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1235 sid_string_dbg(sid)));
1236 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1239 t = centry_time(centry);
1241 /* In the salted case this isn't actually the nt_hash itself,
1242 but the MD5 of the salt + nt_hash. Let the caller
1243 sort this out. It can tell as we only return the cached_salt
1244 if we are returning a salted cred. */
1246 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1247 if (*cached_nt_pass == NULL) {
1250 sid_to_fstring(sidstr, sid);
1252 /* Bad (old) cred cache. Delete and pretend we
1254 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1256 wcache_delete("CRED/%s", sidstr);
1257 centry_free(centry);
1258 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1261 /* We only have 17 bytes more data in the salted cred case. */
1262 if (centry->len - centry->ofs == 17) {
1263 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1265 *cached_salt = NULL;
1268 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1270 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1273 status = centry->status;
1275 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1276 sid_string_dbg(sid), nt_errstr(status) ));
1278 centry_free(centry);
1282 /* Store creds for a SID - only writes out new salted ones. */
1284 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1285 TALLOC_CTX *mem_ctx,
1287 const uint8 nt_pass[NT_HASH_LEN])
1289 struct cache_entry *centry;
1292 uint8 cred_salt[NT_HASH_LEN];
1293 uint8 salted_hash[NT_HASH_LEN];
1295 if (is_null_sid(sid)) {
1296 return NT_STATUS_INVALID_SID;
1299 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1300 return NT_STATUS_INVALID_SID;
1303 centry = centry_start(domain, NT_STATUS_OK);
1305 return NT_STATUS_INTERNAL_DB_ERROR;
1308 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1310 centry_put_time(centry, time(NULL));
1312 /* Create a salt and then salt the hash. */
1313 generate_random_buffer(cred_salt, NT_HASH_LEN);
1314 E_md5hash(cred_salt, nt_pass, salted_hash);
1316 centry_put_hash16(centry, salted_hash);
1317 centry_put_hash16(centry, cred_salt);
1318 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1320 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1322 centry_free(centry);
1324 return NT_STATUS_OK;
1328 /* Query display info. This is the basic user list fn */
1329 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1330 TALLOC_CTX *mem_ctx,
1331 uint32 *num_entries,
1332 WINBIND_USERINFO **info)
1334 struct winbind_cache *cache = get_cache(domain);
1335 struct cache_entry *centry = NULL;
1337 unsigned int i, retry;
1342 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1346 *num_entries = centry_uint32(centry);
1348 if (*num_entries == 0)
1351 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1353 smb_panic_fn("query_user_list out of memory");
1355 for (i=0; i<(*num_entries); i++) {
1356 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1357 (*info)[i].full_name = centry_string(centry, mem_ctx);
1358 (*info)[i].homedir = centry_string(centry, mem_ctx);
1359 (*info)[i].shell = centry_string(centry, mem_ctx);
1360 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1361 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1365 status = centry->status;
1367 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1368 domain->name, nt_errstr(status) ));
1370 centry_free(centry);
1377 /* Return status value returned by seq number check */
1379 if (!NT_STATUS_IS_OK(domain->last_status))
1380 return domain->last_status;
1382 /* Put the query_user_list() in a retry loop. There appears to be
1383 * some bug either with Windows 2000 or Samba's handling of large
1384 * rpc replies. This manifests itself as sudden disconnection
1385 * at a random point in the enumeration of a large (60k) user list.
1386 * The retry loop simply tries the operation again. )-: It's not
1387 * pretty but an acceptable workaround until we work out what the
1388 * real problem is. */
1393 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1396 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1397 if (!NT_STATUS_IS_OK(status)) {
1398 DEBUG(3, ("query_user_list: returned 0x%08x, "
1399 "retrying\n", NT_STATUS_V(status)));
1401 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1402 DEBUG(3, ("query_user_list: flushing "
1403 "connection cache\n"));
1404 invalidate_cm_connection(&domain->conn);
1407 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1411 refresh_sequence_number(domain, false);
1412 centry = centry_start(domain, status);
1415 centry_put_uint32(centry, *num_entries);
1416 for (i=0; i<(*num_entries); i++) {
1417 centry_put_string(centry, (*info)[i].acct_name);
1418 centry_put_string(centry, (*info)[i].full_name);
1419 centry_put_string(centry, (*info)[i].homedir);
1420 centry_put_string(centry, (*info)[i].shell);
1421 centry_put_sid(centry, &(*info)[i].user_sid);
1422 centry_put_sid(centry, &(*info)[i].group_sid);
1423 if (domain->backend && domain->backend->consistent) {
1424 /* when the backend is consistent we can pre-prime some mappings */
1425 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1427 (*info)[i].acct_name,
1428 &(*info)[i].user_sid,
1430 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1431 &(*info)[i].user_sid,
1433 (*info)[i].acct_name,
1435 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1438 centry_end(centry, "UL/%s", domain->name);
1439 centry_free(centry);
1445 /* list all domain groups */
1446 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1447 TALLOC_CTX *mem_ctx,
1448 uint32 *num_entries,
1449 struct acct_info **info)
1451 struct winbind_cache *cache = get_cache(domain);
1452 struct cache_entry *centry = NULL;
1459 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1463 *num_entries = centry_uint32(centry);
1465 if (*num_entries == 0)
1468 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1470 smb_panic_fn("enum_dom_groups out of memory");
1472 for (i=0; i<(*num_entries); i++) {
1473 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1474 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1475 (*info)[i].rid = centry_uint32(centry);
1479 status = centry->status;
1481 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1482 domain->name, nt_errstr(status) ));
1484 centry_free(centry);
1491 /* Return status value returned by seq number check */
1493 if (!NT_STATUS_IS_OK(domain->last_status))
1494 return domain->last_status;
1496 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1499 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1502 refresh_sequence_number(domain, false);
1503 centry = centry_start(domain, status);
1506 centry_put_uint32(centry, *num_entries);
1507 for (i=0; i<(*num_entries); i++) {
1508 centry_put_string(centry, (*info)[i].acct_name);
1509 centry_put_string(centry, (*info)[i].acct_desc);
1510 centry_put_uint32(centry, (*info)[i].rid);
1512 centry_end(centry, "GL/%s/domain", domain->name);
1513 centry_free(centry);
1519 /* list all domain groups */
1520 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1521 TALLOC_CTX *mem_ctx,
1522 uint32 *num_entries,
1523 struct acct_info **info)
1525 struct winbind_cache *cache = get_cache(domain);
1526 struct cache_entry *centry = NULL;
1533 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1537 *num_entries = centry_uint32(centry);
1539 if (*num_entries == 0)
1542 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1544 smb_panic_fn("enum_dom_groups out of memory");
1546 for (i=0; i<(*num_entries); i++) {
1547 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1548 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1549 (*info)[i].rid = centry_uint32(centry);
1554 /* If we are returning cached data and the domain controller
1555 is down then we don't know whether the data is up to date
1556 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1559 if (wcache_server_down(domain)) {
1560 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1561 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1563 status = centry->status;
1565 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1566 domain->name, nt_errstr(status) ));
1568 centry_free(centry);
1575 /* Return status value returned by seq number check */
1577 if (!NT_STATUS_IS_OK(domain->last_status))
1578 return domain->last_status;
1580 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1583 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1586 refresh_sequence_number(domain, false);
1587 centry = centry_start(domain, status);
1590 centry_put_uint32(centry, *num_entries);
1591 for (i=0; i<(*num_entries); i++) {
1592 centry_put_string(centry, (*info)[i].acct_name);
1593 centry_put_string(centry, (*info)[i].acct_desc);
1594 centry_put_uint32(centry, (*info)[i].rid);
1596 centry_end(centry, "GL/%s/local", domain->name);
1597 centry_free(centry);
1603 /* convert a single name to a sid in a domain */
1604 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1605 TALLOC_CTX *mem_ctx,
1606 enum winbindd_cmd orig_cmd,
1607 const char *domain_name,
1610 enum lsa_SidType *type)
1612 struct winbind_cache *cache = get_cache(domain);
1613 struct cache_entry *centry = NULL;
1620 fstrcpy(uname, name);
1622 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1626 status = centry->status;
1627 if (NT_STATUS_IS_OK(status)) {
1628 *type = (enum lsa_SidType)centry_uint32(centry);
1629 centry_sid(centry, mem_ctx, sid);
1632 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1633 domain->name, nt_errstr(status) ));
1635 centry_free(centry);
1641 /* If the seq number check indicated that there is a problem
1642 * with this DC, then return that status... except for
1643 * access_denied. This is special because the dc may be in
1644 * "restrict anonymous = 1" mode, in which case it will deny
1645 * most unauthenticated operations, but *will* allow the LSA
1646 * name-to-sid that we try as a fallback. */
1648 if (!(NT_STATUS_IS_OK(domain->last_status)
1649 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1650 return domain->last_status;
1652 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1655 status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
1656 domain_name, name, sid, type);
1659 refresh_sequence_number(domain, false);
1661 if (domain->online &&
1662 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1663 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1665 /* Only save the reverse mapping if this was not a UPN */
1666 if (!strchr(name, '@')) {
1667 strupper_m(CONST_DISCARD(char *,domain_name));
1668 strlower_m(CONST_DISCARD(char *,name));
1669 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1676 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1678 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1679 TALLOC_CTX *mem_ctx,
1683 enum lsa_SidType *type)
1685 struct winbind_cache *cache = get_cache(domain);
1686 struct cache_entry *centry = NULL;
1693 centry = wcache_fetch(cache, domain, "SN/%s",
1694 sid_to_fstring(sid_string, sid));
1698 status = centry->status;
1699 if (NT_STATUS_IS_OK(status)) {
1700 *type = (enum lsa_SidType)centry_uint32(centry);
1701 *domain_name = centry_string(centry, mem_ctx);
1702 *name = centry_string(centry, mem_ctx);
1705 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1706 domain->name, nt_errstr(status) ));
1708 centry_free(centry);
1713 *domain_name = NULL;
1715 /* If the seq number check indicated that there is a problem
1716 * with this DC, then return that status... except for
1717 * access_denied. This is special because the dc may be in
1718 * "restrict anonymous = 1" mode, in which case it will deny
1719 * most unauthenticated operations, but *will* allow the LSA
1720 * sid-to-name that we try as a fallback. */
1722 if (!(NT_STATUS_IS_OK(domain->last_status)
1723 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1724 return domain->last_status;
1726 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1729 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1732 refresh_sequence_number(domain, false);
1733 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1735 /* We can't save the name to sid mapping here, as with sid history a
1736 * later name2sid would give the wrong sid. */
1741 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1742 TALLOC_CTX *mem_ctx,
1743 const DOM_SID *domain_sid,
1748 enum lsa_SidType **types)
1750 struct winbind_cache *cache = get_cache(domain);
1752 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1756 *domain_name = NULL;
1764 if (num_rids == 0) {
1765 return NT_STATUS_OK;
1768 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1769 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1771 if ((*names == NULL) || (*types == NULL)) {
1772 result = NT_STATUS_NO_MEMORY;
1776 have_mapped = have_unmapped = false;
1778 for (i=0; i<num_rids; i++) {
1780 struct cache_entry *centry;
1783 if (!sid_compose(&sid, domain_sid, rids[i])) {
1784 result = NT_STATUS_INTERNAL_ERROR;
1788 centry = wcache_fetch(cache, domain, "SN/%s",
1789 sid_to_fstring(tmp, &sid));
1794 (*types)[i] = SID_NAME_UNKNOWN;
1795 (*names)[i] = talloc_strdup(*names, "");
1797 if (NT_STATUS_IS_OK(centry->status)) {
1800 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1802 dom = centry_string(centry, mem_ctx);
1803 if (*domain_name == NULL) {
1809 (*names)[i] = centry_string(centry, *names);
1811 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1812 have_unmapped = true;
1815 /* something's definitely wrong */
1816 result = centry->status;
1820 centry_free(centry);
1824 return NT_STATUS_NONE_MAPPED;
1826 if (!have_unmapped) {
1827 return NT_STATUS_OK;
1829 return STATUS_SOME_UNMAPPED;
1833 TALLOC_FREE(*names);
1834 TALLOC_FREE(*types);
1836 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1837 rids, num_rids, domain_name,
1841 None of the queried rids has been found so save all negative entries
1843 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1844 for (i = 0; i < num_rids; i++) {
1846 const char *name = "";
1847 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1848 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1850 if (!sid_compose(&sid, domain_sid, rids[i])) {
1851 return NT_STATUS_INTERNAL_ERROR;
1854 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1862 Some or all of the queried rids have been found.
1864 if (!NT_STATUS_IS_OK(result) &&
1865 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1869 refresh_sequence_number(domain, false);
1871 for (i=0; i<num_rids; i++) {
1875 if (!sid_compose(&sid, domain_sid, rids[i])) {
1876 result = NT_STATUS_INTERNAL_ERROR;
1880 status = (*types)[i] == SID_NAME_UNKNOWN ?
1881 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1883 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1884 (*names)[i], (*types)[i]);
1891 TALLOC_FREE(*names);
1892 TALLOC_FREE(*types);
1896 /* Lookup user information from a rid */
1897 static NTSTATUS query_user(struct winbindd_domain *domain,
1898 TALLOC_CTX *mem_ctx,
1899 const DOM_SID *user_sid,
1900 WINBIND_USERINFO *info)
1902 struct winbind_cache *cache = get_cache(domain);
1903 struct cache_entry *centry = NULL;
1910 centry = wcache_fetch(cache, domain, "U/%s",
1911 sid_to_fstring(tmp, user_sid));
1913 /* If we have an access denied cache entry and a cached info3 in the
1914 samlogon cache then do a query. This will force the rpc back end
1915 to return the info3 data. */
1917 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1918 netsamlogon_cache_have(user_sid)) {
1919 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1920 domain->last_status = NT_STATUS_OK;
1921 centry_free(centry);
1928 /* if status is not ok then this is a negative hit
1929 and the rest of the data doesn't matter */
1930 status = centry->status;
1931 if (NT_STATUS_IS_OK(status)) {
1932 info->acct_name = centry_string(centry, mem_ctx);
1933 info->full_name = centry_string(centry, mem_ctx);
1934 info->homedir = centry_string(centry, mem_ctx);
1935 info->shell = centry_string(centry, mem_ctx);
1936 info->primary_gid = centry_uint32(centry);
1937 centry_sid(centry, mem_ctx, &info->user_sid);
1938 centry_sid(centry, mem_ctx, &info->group_sid);
1941 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1942 domain->name, nt_errstr(status) ));
1944 centry_free(centry);
1950 /* Return status value returned by seq number check */
1952 if (!NT_STATUS_IS_OK(domain->last_status))
1953 return domain->last_status;
1955 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1958 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1961 refresh_sequence_number(domain, false);
1962 wcache_save_user(domain, status, info);
1968 /* Lookup groups a user is a member of. */
1969 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1970 TALLOC_CTX *mem_ctx,
1971 const DOM_SID *user_sid,
1972 uint32 *num_groups, DOM_SID **user_gids)
1974 struct winbind_cache *cache = get_cache(domain);
1975 struct cache_entry *centry = NULL;
1983 centry = wcache_fetch(cache, domain, "UG/%s",
1984 sid_to_fstring(sid_string, user_sid));
1986 /* If we have an access denied cache entry and a cached info3 in the
1987 samlogon cache then do a query. This will force the rpc back end
1988 to return the info3 data. */
1990 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1991 netsamlogon_cache_have(user_sid)) {
1992 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1993 domain->last_status = NT_STATUS_OK;
1994 centry_free(centry);
2001 *num_groups = centry_uint32(centry);
2003 if (*num_groups == 0)
2006 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
2007 if (! (*user_gids)) {
2008 smb_panic_fn("lookup_usergroups out of memory");
2010 for (i=0; i<(*num_groups); i++) {
2011 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
2015 status = centry->status;
2017 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
2018 domain->name, nt_errstr(status) ));
2020 centry_free(centry);
2025 (*user_gids) = NULL;
2027 /* Return status value returned by seq number check */
2029 if (!NT_STATUS_IS_OK(domain->last_status))
2030 return domain->last_status;
2032 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2035 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2037 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2041 refresh_sequence_number(domain, false);
2042 centry = centry_start(domain, status);
2046 centry_put_uint32(centry, *num_groups);
2047 for (i=0; i<(*num_groups); i++) {
2048 centry_put_sid(centry, &(*user_gids)[i]);
2051 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2052 centry_free(centry);
2058 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2059 TALLOC_CTX *mem_ctx,
2060 uint32 num_sids, const DOM_SID *sids,
2061 uint32 *num_aliases, uint32 **alias_rids)
2063 struct winbind_cache *cache = get_cache(domain);
2064 struct cache_entry *centry = NULL;
2066 char *sidlist = talloc_strdup(mem_ctx, "");
2072 if (num_sids == 0) {
2075 return NT_STATUS_OK;
2078 /* We need to cache indexed by the whole list of SIDs, the aliases
2079 * resulting might come from any of the SIDs. */
2081 for (i=0; i<num_sids; i++) {
2083 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
2084 sid_to_fstring(tmp, &sids[i]));
2085 if (sidlist == NULL)
2086 return NT_STATUS_NO_MEMORY;
2089 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2094 *num_aliases = centry_uint32(centry);
2098 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
2100 if ((*alias_rids) == NULL) {
2101 centry_free(centry);
2102 return NT_STATUS_NO_MEMORY;
2105 (*alias_rids) = NULL;
2108 for (i=0; i<(*num_aliases); i++)
2109 (*alias_rids)[i] = centry_uint32(centry);
2111 status = centry->status;
2113 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2114 "status %s\n", domain->name, nt_errstr(status)));
2116 centry_free(centry);
2121 (*alias_rids) = NULL;
2123 if (!NT_STATUS_IS_OK(domain->last_status))
2124 return domain->last_status;
2126 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2127 "for domain %s\n", domain->name ));
2129 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2131 num_aliases, alias_rids);
2134 refresh_sequence_number(domain, false);
2135 centry = centry_start(domain, status);
2138 centry_put_uint32(centry, *num_aliases);
2139 for (i=0; i<(*num_aliases); i++)
2140 centry_put_uint32(centry, (*alias_rids)[i]);
2141 centry_end(centry, "UA%s", sidlist);
2142 centry_free(centry);
2149 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2150 TALLOC_CTX *mem_ctx,
2151 const DOM_SID *group_sid, uint32 *num_names,
2152 DOM_SID **sid_mem, char ***names,
2153 uint32 **name_types)
2155 struct winbind_cache *cache = get_cache(domain);
2156 struct cache_entry *centry = NULL;
2164 centry = wcache_fetch(cache, domain, "GM/%s",
2165 sid_to_fstring(sid_string, group_sid));
2169 *num_names = centry_uint32(centry);
2171 if (*num_names == 0)
2174 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
2175 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
2176 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
2178 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
2179 smb_panic_fn("lookup_groupmem out of memory");
2182 for (i=0; i<(*num_names); i++) {
2183 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
2184 (*names)[i] = centry_string(centry, mem_ctx);
2185 (*name_types)[i] = centry_uint32(centry);
2189 status = centry->status;
2191 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2192 domain->name, nt_errstr(status)));
2194 centry_free(centry);
2201 (*name_types) = NULL;
2203 /* Return status value returned by seq number check */
2205 if (!NT_STATUS_IS_OK(domain->last_status))
2206 return domain->last_status;
2208 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2211 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2212 sid_mem, names, name_types);
2215 refresh_sequence_number(domain, false);
2216 centry = centry_start(domain, status);
2219 centry_put_uint32(centry, *num_names);
2220 for (i=0; i<(*num_names); i++) {
2221 centry_put_sid(centry, &(*sid_mem)[i]);
2222 centry_put_string(centry, (*names)[i]);
2223 centry_put_uint32(centry, (*name_types)[i]);
2225 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2226 centry_free(centry);
2232 /* find the sequence number for a domain */
2233 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2235 refresh_sequence_number(domain, false);
2237 *seq = domain->sequence_number;
2239 return NT_STATUS_OK;
2242 /* enumerate trusted domains
2243 * (we need to have the list of trustdoms in the cache when we go offline) -
2245 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2246 TALLOC_CTX *mem_ctx,
2247 uint32 *num_domains,
2252 struct winbind_cache *cache = get_cache(domain);
2253 struct cache_entry *centry = NULL;
2260 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2266 *num_domains = centry_uint32(centry);
2269 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2270 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2271 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2273 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2274 smb_panic_fn("trusted_domains out of memory");
2278 (*alt_names) = NULL;
2282 for (i=0; i<(*num_domains); i++) {
2283 (*names)[i] = centry_string(centry, mem_ctx);
2284 (*alt_names)[i] = centry_string(centry, mem_ctx);
2285 if (!centry_sid(centry, mem_ctx, &(*dom_sids)[i])) {
2286 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2290 status = centry->status;
2292 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2293 domain->name, *num_domains, nt_errstr(status) ));
2295 centry_free(centry);
2302 (*alt_names) = NULL;
2304 /* Return status value returned by seq number check */
2306 if (!NT_STATUS_IS_OK(domain->last_status))
2307 return domain->last_status;
2309 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2312 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2313 names, alt_names, dom_sids);
2315 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2316 * so that the generic centry handling still applies correctly -
2319 if (!NT_STATUS_IS_ERR(status)) {
2320 status = NT_STATUS_OK;
2324 #if 0 /* Disabled as we want the trust dom list to be managed by
2325 the main parent and always to make the query. --jerry */
2328 refresh_sequence_number(domain, false);
2330 centry = centry_start(domain, status);
2334 centry_put_uint32(centry, *num_domains);
2336 for (i=0; i<(*num_domains); i++) {
2337 centry_put_string(centry, (*names)[i]);
2338 centry_put_string(centry, (*alt_names)[i]);
2339 centry_put_sid(centry, &(*dom_sids)[i]);
2342 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2344 centry_free(centry);
2352 /* get lockout policy */
2353 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2354 TALLOC_CTX *mem_ctx,
2355 struct samr_DomInfo12 *policy)
2357 struct winbind_cache *cache = get_cache(domain);
2358 struct cache_entry *centry = NULL;
2364 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2369 policy->lockout_duration = centry_nttime(centry);
2370 policy->lockout_window = centry_nttime(centry);
2371 policy->lockout_threshold = centry_uint16(centry);
2373 status = centry->status;
2375 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2376 domain->name, nt_errstr(status) ));
2378 centry_free(centry);
2382 ZERO_STRUCTP(policy);
2384 /* Return status value returned by seq number check */
2386 if (!NT_STATUS_IS_OK(domain->last_status))
2387 return domain->last_status;
2389 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2392 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2395 refresh_sequence_number(domain, false);
2396 wcache_save_lockout_policy(domain, status, policy);
2401 /* get password policy */
2402 static NTSTATUS password_policy(struct winbindd_domain *domain,
2403 TALLOC_CTX *mem_ctx,
2404 struct samr_DomInfo1 *policy)
2406 struct winbind_cache *cache = get_cache(domain);
2407 struct cache_entry *centry = NULL;
2413 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2418 policy->min_password_length = centry_uint16(centry);
2419 policy->password_history_length = centry_uint16(centry);
2420 policy->password_properties = centry_uint32(centry);
2421 policy->max_password_age = centry_nttime(centry);
2422 policy->min_password_age = centry_nttime(centry);
2424 status = centry->status;
2426 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2427 domain->name, nt_errstr(status) ));
2429 centry_free(centry);
2433 ZERO_STRUCTP(policy);
2435 /* Return status value returned by seq number check */
2437 if (!NT_STATUS_IS_OK(domain->last_status))
2438 return domain->last_status;
2440 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2443 status = domain->backend->password_policy(domain, mem_ctx, policy);
2446 refresh_sequence_number(domain, false);
2447 if (NT_STATUS_IS_OK(status)) {
2448 wcache_save_password_policy(domain, status, policy);
2455 /* Invalidate cached user and group lists coherently */
2457 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2460 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2461 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2462 tdb_delete(the_tdb, kbuf);
2467 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2469 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2470 struct netr_SamInfo3 *info3)
2473 fstring key_str, sid_string;
2474 struct winbind_cache *cache;
2476 /* dont clear cached U/SID and UG/SID entries when we want to logon
2479 if (lp_winbind_offline_logon()) {
2486 cache = get_cache(domain);
2492 sid_copy(&sid, info3->base.domain_sid);
2493 sid_append_rid(&sid, info3->base.rid);
2495 /* Clear U/SID cache entry */
2496 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2497 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2498 tdb_delete(cache->tdb, string_tdb_data(key_str));
2500 /* Clear UG/SID cache entry */
2501 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2502 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2503 tdb_delete(cache->tdb, string_tdb_data(key_str));
2505 /* Samba/winbindd never needs this. */
2506 netsamlogon_clear_cached_user(info3);
2509 bool wcache_invalidate_cache(void)
2511 struct winbindd_domain *domain;
2513 for (domain = domain_list(); domain; domain = domain->next) {
2514 struct winbind_cache *cache = get_cache(domain);
2516 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2517 "entries for %s\n", domain->name));
2520 tdb_traverse(cache->tdb, traverse_fn, NULL);
2529 bool init_wcache(void)
2531 if (wcache == NULL) {
2532 wcache = SMB_XMALLOC_P(struct winbind_cache);
2533 ZERO_STRUCTP(wcache);
2536 if (wcache->tdb != NULL)
2539 /* when working offline we must not clear the cache on restart */
2540 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2541 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2542 ( lp_winbind_offline_logon()
2544 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
2545 O_RDWR|O_CREAT, 0600);
2547 if (wcache->tdb == NULL) {
2548 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2555 /************************************************************************
2556 This is called by the parent to initialize the cache file.
2557 We don't need sophisticated locking here as we know we're the
2559 ************************************************************************/
2561 bool initialize_winbindd_cache(void)
2563 bool cache_bad = true;
2566 if (!init_wcache()) {
2567 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2571 /* Check version number. */
2572 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2573 vers == WINBINDD_CACHE_VERSION) {
2578 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2579 "and re-creating with version number %d\n",
2580 WINBINDD_CACHE_VERSION ));
2582 tdb_close(wcache->tdb);
2585 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2586 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2587 cache_path("winbindd_cache.tdb"),
2591 if (!init_wcache()) {
2592 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2593 "init_wcache failed.\n"));
2597 /* Write the version. */
2598 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2599 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2600 tdb_errorstr(wcache->tdb) ));
2605 tdb_close(wcache->tdb);
2610 void close_winbindd_cache(void)
2616 tdb_close(wcache->tdb);
2621 void cache_store_response(pid_t pid, struct winbindd_response *response)
2628 DEBUG(10, ("Storing response for pid %d, len %d\n",
2629 (int)pid, response->length));
2631 fstr_sprintf(key_str, "DR/%d", (int)pid);
2632 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2633 make_tdb_data((uint8 *)response, sizeof(*response)),
2637 if (response->length == sizeof(*response))
2640 /* There's extra data */
2642 DEBUG(10, ("Storing extra data: len=%d\n",
2643 (int)(response->length - sizeof(*response))));
2645 fstr_sprintf(key_str, "DE/%d", (int)pid);
2646 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2647 make_tdb_data((uint8 *)response->extra_data.data,
2648 response->length - sizeof(*response)),
2652 /* We could not store the extra data, make sure the tdb does not
2653 * contain a main record with wrong dangling extra data */
2655 fstr_sprintf(key_str, "DR/%d", (int)pid);
2656 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2661 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2669 DEBUG(10, ("Retrieving response for pid %d\n", (int)pid));
2671 fstr_sprintf(key_str, "DR/%d", (int)pid);
2672 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2674 if (data.dptr == NULL)
2677 if (data.dsize != sizeof(*response))
2680 memcpy(response, data.dptr, data.dsize);
2681 SAFE_FREE(data.dptr);
2683 if (response->length == sizeof(*response)) {
2684 response->extra_data.data = NULL;
2688 /* There's extra data */
2690 DEBUG(10, ("Retrieving extra data length=%d\n",
2691 (int)(response->length - sizeof(*response))));
2693 fstr_sprintf(key_str, "DE/%d", (int)pid);
2694 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2696 if (data.dptr == NULL) {
2697 DEBUG(0, ("Did not find extra data\n"));
2701 if (data.dsize != (response->length - sizeof(*response))) {
2702 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2703 SAFE_FREE(data.dptr);
2707 dump_data(11, (uint8 *)data.dptr, data.dsize);
2709 response->extra_data.data = data.dptr;
2713 void cache_cleanup_response(pid_t pid)
2720 fstr_sprintf(key_str, "DR/%d", (int)pid);
2721 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2723 fstr_sprintf(key_str, "DE/%d", (int)pid);
2724 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2730 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2731 char **domain_name, char **name,
2732 enum lsa_SidType *type)
2734 struct winbindd_domain *domain;
2735 struct winbind_cache *cache;
2736 struct cache_entry *centry = NULL;
2740 domain = find_lookup_domain_from_sid(sid);
2741 if (domain == NULL) {
2745 cache = get_cache(domain);
2747 if (cache->tdb == NULL) {
2751 centry = wcache_fetch(cache, domain, "SN/%s",
2752 sid_to_fstring(tmp, sid));
2753 if (centry == NULL) {
2757 if (NT_STATUS_IS_OK(centry->status)) {
2758 *type = (enum lsa_SidType)centry_uint32(centry);
2759 *domain_name = centry_string(centry, mem_ctx);
2760 *name = centry_string(centry, mem_ctx);
2763 status = centry->status;
2764 centry_free(centry);
2765 return NT_STATUS_IS_OK(status);
2768 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2769 const char *domain_name,
2772 enum lsa_SidType *type)
2774 struct winbindd_domain *domain;
2775 struct winbind_cache *cache;
2776 struct cache_entry *centry = NULL;
2779 bool original_online_state;
2781 domain = find_lookup_domain_from_name(domain_name);
2782 if (domain == NULL) {
2786 cache = get_cache(domain);
2788 if (cache->tdb == NULL) {
2792 fstrcpy(uname, name);
2795 /* If we are doing a cached logon, temporarily set the domain
2796 offline so the cache won't expire the entry */
2798 original_online_state = domain->online;
2799 domain->online = false;
2800 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2801 domain->online = original_online_state;
2803 if (centry == NULL) {
2807 if (NT_STATUS_IS_OK(centry->status)) {
2808 *type = (enum lsa_SidType)centry_uint32(centry);
2809 centry_sid(centry, mem_ctx, sid);
2812 status = centry->status;
2813 centry_free(centry);
2815 return NT_STATUS_IS_OK(status);
2818 void cache_name2sid(struct winbindd_domain *domain,
2819 const char *domain_name, const char *name,
2820 enum lsa_SidType type, const DOM_SID *sid)
2822 refresh_sequence_number(domain, false);
2823 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2828 * The original idea that this cache only contains centries has
2829 * been blurred - now other stuff gets put in here. Ensure we
2830 * ignore these things on cleanup.
2833 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2834 TDB_DATA dbuf, void *state)
2836 struct cache_entry *centry;
2838 if (is_non_centry_key(kbuf)) {
2842 centry = wcache_fetch_raw((char *)kbuf.dptr);
2847 if (!NT_STATUS_IS_OK(centry->status)) {
2848 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2849 tdb_delete(the_tdb, kbuf);
2852 centry_free(centry);
2856 /* flush the cache */
2857 void wcache_flush_cache(void)
2862 tdb_close(wcache->tdb);
2865 if (!winbindd_use_cache()) {
2869 /* when working offline we must not clear the cache on restart */
2870 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2871 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2872 ( lp_winbind_offline_logon()
2874 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
2875 O_RDWR|O_CREAT, 0600);
2878 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2882 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2884 DEBUG(10,("wcache_flush_cache success\n"));
2887 /* Count cached creds */
2889 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2892 int *cred_count = (int*)state;
2894 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2900 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2902 struct winbind_cache *cache = get_cache(domain);
2907 return NT_STATUS_INTERNAL_DB_ERROR;
2910 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2912 return NT_STATUS_OK;
2916 struct cred_list *prev, *next;
2921 static struct cred_list *wcache_cred_list;
2923 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2926 struct cred_list *cred;
2928 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2930 cred = SMB_MALLOC_P(struct cred_list);
2932 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2938 /* save a copy of the key */
2940 fstrcpy(cred->name, (const char *)kbuf.dptr);
2941 DLIST_ADD(wcache_cred_list, cred);
2947 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2949 struct winbind_cache *cache = get_cache(domain);
2952 struct cred_list *cred, *oldest = NULL;
2955 return NT_STATUS_INTERNAL_DB_ERROR;
2958 /* we possibly already have an entry */
2959 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2961 fstring key_str, tmp;
2963 DEBUG(11,("we already have an entry, deleting that\n"));
2965 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2967 tdb_delete(cache->tdb, string_tdb_data(key_str));
2969 return NT_STATUS_OK;
2972 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2974 return NT_STATUS_OK;
2975 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2976 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2979 ZERO_STRUCTP(oldest);
2981 for (cred = wcache_cred_list; cred; cred = cred->next) {
2986 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2988 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2990 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2994 t = IVAL(data.dptr, 0);
2995 SAFE_FREE(data.dptr);
2998 oldest = SMB_MALLOC_P(struct cred_list);
2999 if (oldest == NULL) {
3000 status = NT_STATUS_NO_MEMORY;
3004 fstrcpy(oldest->name, cred->name);
3005 oldest->created = t;
3009 if (t < oldest->created) {
3010 fstrcpy(oldest->name, cred->name);
3011 oldest->created = t;
3015 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3016 status = NT_STATUS_OK;
3018 status = NT_STATUS_UNSUCCESSFUL;
3021 SAFE_FREE(wcache_cred_list);
3027 /* Change the global online/offline state. */
3028 bool set_global_winbindd_state_offline(void)
3032 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3034 /* Only go offline if someone has created
3035 the key "WINBINDD_OFFLINE" in the cache tdb. */
3037 if (wcache == NULL || wcache->tdb == NULL) {
3038 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3042 if (!lp_winbind_offline_logon()) {
3043 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3047 if (global_winbindd_offline_state) {
3048 /* Already offline. */
3052 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3054 if (!data.dptr || data.dsize != 4) {
3055 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3056 SAFE_FREE(data.dptr);
3059 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3060 global_winbindd_offline_state = true;
3061 SAFE_FREE(data.dptr);
3066 void set_global_winbindd_state_online(void)
3068 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3070 if (!lp_winbind_offline_logon()) {
3071 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3075 if (!global_winbindd_offline_state) {
3076 /* Already online. */
3079 global_winbindd_offline_state = false;
3085 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3086 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3089 bool get_global_winbindd_state_offline(void)
3091 return global_winbindd_offline_state;
3094 /***********************************************************************
3095 Validate functions for all possible cache tdb keys.
3096 ***********************************************************************/
3098 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3099 struct tdb_validation_status *state)
3101 struct cache_entry *centry;
3103 centry = SMB_XMALLOC_P(struct cache_entry);
3104 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3105 if (!centry->data) {
3109 centry->len = data.dsize;
3112 if (centry->len < 8) {
3113 /* huh? corrupt cache? */
3114 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3115 centry_free(centry);
3116 state->bad_entry = true;
3117 state->success = false;
3121 centry->status = NT_STATUS(centry_uint32(centry));
3122 centry->sequence_number = centry_uint32(centry);
3126 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3127 struct tdb_validation_status *state)
3129 if (dbuf.dsize != 8) {
3130 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3131 keystr, (unsigned int)dbuf.dsize ));
3132 state->bad_entry = true;
3138 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3139 struct tdb_validation_status *state)
3141 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3146 (void)centry_uint32(centry);
3147 if (NT_STATUS_IS_OK(centry->status)) {
3149 (void)centry_sid(centry, mem_ctx, &sid);
3152 centry_free(centry);
3154 if (!(state->success)) {
3157 DEBUG(10,("validate_ns: %s ok\n", keystr));
3161 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3162 struct tdb_validation_status *state)
3164 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3169 if (NT_STATUS_IS_OK(centry->status)) {
3170 (void)centry_uint32(centry);
3171 (void)centry_string(centry, mem_ctx);
3172 (void)centry_string(centry, mem_ctx);
3175 centry_free(centry);
3177 if (!(state->success)) {
3180 DEBUG(10,("validate_sn: %s ok\n", keystr));
3184 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3185 struct tdb_validation_status *state)
3187 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3194 (void)centry_string(centry, mem_ctx);
3195 (void)centry_string(centry, mem_ctx);
3196 (void)centry_string(centry, mem_ctx);
3197 (void)centry_string(centry, mem_ctx);
3198 (void)centry_uint32(centry);
3199 (void)centry_sid(centry, mem_ctx, &sid);
3200 (void)centry_sid(centry, mem_ctx, &sid);
3202 centry_free(centry);
3204 if (!(state->success)) {
3207 DEBUG(10,("validate_u: %s ok\n", keystr));
3211 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3212 struct tdb_validation_status *state)
3214 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3220 (void)centry_nttime(centry);
3221 (void)centry_nttime(centry);
3222 (void)centry_uint16(centry);
3224 centry_free(centry);
3226 if (!(state->success)) {
3229 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3233 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3234 struct tdb_validation_status *state)
3236 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3242 (void)centry_uint16(centry);
3243 (void)centry_uint16(centry);
3244 (void)centry_uint32(centry);
3245 (void)centry_nttime(centry);
3246 (void)centry_nttime(centry);
3248 centry_free(centry);
3250 if (!(state->success)) {
3253 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3257 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3258 struct tdb_validation_status *state)
3260 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3266 (void)centry_time(centry);
3267 (void)centry_hash16(centry, mem_ctx);
3269 /* We only have 17 bytes more data in the salted cred case. */
3270 if (centry->len - centry->ofs == 17) {
3271 (void)centry_hash16(centry, mem_ctx);
3274 centry_free(centry);
3276 if (!(state->success)) {
3279 DEBUG(10,("validate_cred: %s ok\n", keystr));
3283 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3284 struct tdb_validation_status *state)
3286 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3287 int32 num_entries, i;
3293 num_entries = (int32)centry_uint32(centry);
3295 for (i=0; i< num_entries; i++) {
3297 (void)centry_string(centry, mem_ctx);
3298 (void)centry_string(centry, mem_ctx);
3299 (void)centry_string(centry, mem_ctx);
3300 (void)centry_string(centry, mem_ctx);
3301 (void)centry_sid(centry, mem_ctx, &sid);
3302 (void)centry_sid(centry, mem_ctx, &sid);
3305 centry_free(centry);
3307 if (!(state->success)) {
3310 DEBUG(10,("validate_ul: %s ok\n", keystr));
3314 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3315 struct tdb_validation_status *state)
3317 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3318 int32 num_entries, i;
3324 num_entries = centry_uint32(centry);
3326 for (i=0; i< num_entries; i++) {
3327 (void)centry_string(centry, mem_ctx);
3328 (void)centry_string(centry, mem_ctx);
3329 (void)centry_uint32(centry);
3332 centry_free(centry);
3334 if (!(state->success)) {
3337 DEBUG(10,("validate_gl: %s ok\n", keystr));
3341 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3342 struct tdb_validation_status *state)
3344 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3345 int32 num_groups, i;
3351 num_groups = centry_uint32(centry);
3353 for (i=0; i< num_groups; i++) {
3355 centry_sid(centry, mem_ctx, &sid);
3358 centry_free(centry);
3360 if (!(state->success)) {
3363 DEBUG(10,("validate_ug: %s ok\n", keystr));
3367 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3368 struct tdb_validation_status *state)
3370 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3371 int32 num_aliases, i;
3377 num_aliases = centry_uint32(centry);
3379 for (i=0; i < num_aliases; i++) {
3380 (void)centry_uint32(centry);
3383 centry_free(centry);
3385 if (!(state->success)) {
3388 DEBUG(10,("validate_ua: %s ok\n", keystr));
3392 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3393 struct tdb_validation_status *state)
3395 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3402 num_names = centry_uint32(centry);
3404 for (i=0; i< num_names; i++) {
3406 centry_sid(centry, mem_ctx, &sid);
3407 (void)centry_string(centry, mem_ctx);
3408 (void)centry_uint32(centry);
3411 centry_free(centry);
3413 if (!(state->success)) {
3416 DEBUG(10,("validate_gm: %s ok\n", keystr));
3420 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3421 struct tdb_validation_status *state)
3423 /* Can't say anything about this other than must be nonzero. */
3424 if (dbuf.dsize == 0) {
3425 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3427 state->bad_entry = true;
3428 state->success = false;
3432 DEBUG(10,("validate_dr: %s ok\n", keystr));
3436 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3437 struct tdb_validation_status *state)
3439 /* Can't say anything about this other than must be nonzero. */
3440 if (dbuf.dsize == 0) {
3441 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3443 state->bad_entry = true;
3444 state->success = false;
3448 DEBUG(10,("validate_de: %s ok\n", keystr));
3452 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3453 TDB_DATA dbuf, struct tdb_validation_status *state)
3455 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3461 (void)centry_string(centry, mem_ctx);
3462 (void)centry_string(centry, mem_ctx);
3463 (void)centry_string(centry, mem_ctx);
3464 (void)centry_uint32(centry);
3466 centry_free(centry);
3468 if (!(state->success)) {
3471 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3475 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3477 struct tdb_validation_status *state)
3479 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3485 (void)centry_string( centry, mem_ctx );
3487 centry_free(centry);
3489 if (!(state->success)) {
3492 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3496 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3498 struct tdb_validation_status *state)
3500 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3506 (void)centry_string( centry, mem_ctx );
3508 centry_free(centry);
3510 if (!(state->success)) {
3513 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3517 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3518 struct tdb_validation_status *state)
3520 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3521 int32 num_domains, i;
3527 num_domains = centry_uint32(centry);
3529 for (i=0; i< num_domains; i++) {
3531 (void)centry_string(centry, mem_ctx);
3532 (void)centry_string(centry, mem_ctx);
3533 (void)centry_sid(centry, mem_ctx, &sid);
3536 centry_free(centry);
3538 if (!(state->success)) {
3541 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3545 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3547 struct tdb_validation_status *state)
3549 if (dbuf.dsize == 0) {
3550 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3551 "key %s (len ==0) ?\n", keystr));
3552 state->bad_entry = true;
3553 state->success = false;
3557 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3558 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3562 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3563 struct tdb_validation_status *state)
3565 if (dbuf.dsize != 4) {
3566 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3567 keystr, (unsigned int)dbuf.dsize ));
3568 state->bad_entry = true;
3569 state->success = false;
3572 DEBUG(10,("validate_offline: %s ok\n", keystr));
3576 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3577 struct tdb_validation_status *state)
3579 if (dbuf.dsize != 4) {
3580 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3581 "key %s (len %u != 4) ?\n",
3582 keystr, (unsigned int)dbuf.dsize));
3583 state->bad_entry = true;
3584 state->success = false;
3588 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3592 /***********************************************************************
3593 A list of all possible cache tdb keys with associated validation
3595 ***********************************************************************/
3597 struct key_val_struct {
3598 const char *keyname;
3599 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3601 {"SEQNUM/", validate_seqnum},
3602 {"NS/", validate_ns},
3603 {"SN/", validate_sn},
3605 {"LOC_POL/", validate_loc_pol},
3606 {"PWD_POL/", validate_pwd_pol},
3607 {"CRED/", validate_cred},
3608 {"UL/", validate_ul},
3609 {"GL/", validate_gl},
3610 {"UG/", validate_ug},
3611 {"UA", validate_ua},
3612 {"GM/", validate_gm},
3613 {"DR/", validate_dr},
3614 {"DE/", validate_de},
3615 {"NSS/PWINFO/", validate_pwinfo},
3616 {"TRUSTDOMS/", validate_trustdoms},
3617 {"TRUSTDOMCACHE/", validate_trustdomcache},
3618 {"NSS/NA/", validate_nss_na},
3619 {"NSS/AN/", validate_nss_an},
3620 {"WINBINDD_OFFLINE", validate_offline},
3621 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3625 /***********************************************************************
3626 Function to look at every entry in the tdb and validate it as far as
3628 ***********************************************************************/
3630 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3633 unsigned int max_key_len = 1024;
3634 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3636 /* Paranoia check. */
3637 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3638 max_key_len = 1024 * 1024;
3640 if (kbuf.dsize > max_key_len) {
3641 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3643 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3647 for (i = 0; key_val[i].keyname; i++) {
3648 size_t namelen = strlen(key_val[i].keyname);
3649 if (kbuf.dsize >= namelen && (
3650 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3651 TALLOC_CTX *mem_ctx;
3655 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3659 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3660 keystr[kbuf.dsize] = '\0';
3662 mem_ctx = talloc_init("validate_ctx");
3668 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3672 talloc_destroy(mem_ctx);
3677 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3678 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3679 DEBUG(0,("data :\n"));
3680 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3681 v_state->unknown_key = true;
3682 v_state->success = false;
3683 return 1; /* terminate. */
3686 static void validate_panic(const char *const why)
3688 DEBUG(0,("validating cache: would panic %s\n", why ));
3689 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3693 /***********************************************************************
3694 Try and validate every entry in the winbindd cache. If we fail here,
3695 delete the cache tdb and return non-zero.
3696 ***********************************************************************/
3698 int winbindd_validate_cache(void)
3701 const char *tdb_path = cache_path("winbindd_cache.tdb");
3702 TDB_CONTEXT *tdb = NULL;
3704 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3705 smb_panic_fn = validate_panic;
3708 tdb = tdb_open_log(tdb_path,
3709 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3710 ( lp_winbind_offline_logon()
3712 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
3716 DEBUG(0, ("winbindd_validate_cache: "
3717 "error opening/initializing tdb\n"));
3722 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3725 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3726 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3731 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3732 smb_panic_fn = smb_panic;
3736 /***********************************************************************
3737 Try and validate every entry in the winbindd cache.
3738 ***********************************************************************/
3740 int winbindd_validate_cache_nobackup(void)
3743 const char *tdb_path = cache_path("winbindd_cache.tdb");
3745 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3746 smb_panic_fn = validate_panic;
3749 if (wcache == NULL || wcache->tdb == NULL) {
3750 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3752 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3756 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3760 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3762 smb_panic_fn = smb_panic;
3766 bool winbindd_cache_validate_and_initialize(void)
3768 close_winbindd_cache();
3770 if (lp_winbind_offline_logon()) {
3771 if (winbindd_validate_cache() < 0) {
3772 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3773 "could be restored.\n"));
3777 return initialize_winbindd_cache();
3780 /*********************************************************************
3781 ********************************************************************/
3783 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3784 struct winbindd_tdc_domain **domains,
3785 size_t *num_domains )
3787 struct winbindd_tdc_domain *list = NULL;
3790 bool set_only = false;
3792 /* don't allow duplicates */
3797 for ( i=0; i< (*num_domains); i++ ) {
3798 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3799 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3810 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3813 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3814 struct winbindd_tdc_domain,
3819 ZERO_STRUCT( list[idx] );
3825 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3826 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3828 if ( !is_null_sid( &new_dom->sid ) ) {
3829 sid_copy( &list[idx].sid, &new_dom->sid );
3831 sid_copy(&list[idx].sid, &global_sid_NULL);
3834 if ( new_dom->domain_flags != 0x0 )
3835 list[idx].trust_flags = new_dom->domain_flags;
3837 if ( new_dom->domain_type != 0x0 )
3838 list[idx].trust_type = new_dom->domain_type;
3840 if ( new_dom->domain_trust_attribs != 0x0 )
3841 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3845 *num_domains = idx + 1;
3851 /*********************************************************************
3852 ********************************************************************/
3854 static TDB_DATA make_tdc_key( const char *domain_name )
3856 char *keystr = NULL;
3857 TDB_DATA key = { NULL, 0 };
3859 if ( !domain_name ) {
3860 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3865 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3868 key = string_term_tdb_data(keystr);
3873 /*********************************************************************
3874 ********************************************************************/
3876 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3878 unsigned char **buf )
3880 unsigned char *buffer = NULL;
3885 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3893 /* Store the number of array items first */
3894 len += tdb_pack( buffer+len, buflen-len, "d",
3897 /* now pack each domain trust record */
3898 for ( i=0; i<num_domains; i++ ) {
3903 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3904 domains[i].domain_name,
3905 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3908 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3909 domains[i].domain_name,
3910 domains[i].dns_name,
3911 sid_to_fstring(tmp, &domains[i].sid),
3912 domains[i].trust_flags,
3913 domains[i].trust_attribs,
3914 domains[i].trust_type );
3917 if ( buflen < len ) {
3919 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3920 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3934 /*********************************************************************
3935 ********************************************************************/
3937 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3938 struct winbindd_tdc_domain **domains )
3940 fstring domain_name, dns_name, sid_string;
3941 uint32 type, attribs, flags;
3945 struct winbindd_tdc_domain *list = NULL;
3947 /* get the number of domains */
3948 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3950 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3954 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3956 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3960 for ( i=0; i<num_domains; i++ ) {
3961 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3970 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3971 TALLOC_FREE( list );
3975 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3976 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3977 domain_name, dns_name, sid_string,
3978 flags, attribs, type));
3980 list[i].domain_name = talloc_strdup( list, domain_name );
3981 list[i].dns_name = talloc_strdup( list, dns_name );
3982 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3983 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3986 list[i].trust_flags = flags;
3987 list[i].trust_attribs = attribs;
3988 list[i].trust_type = type;
3996 /*********************************************************************
3997 ********************************************************************/
3999 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4001 TDB_DATA key = make_tdc_key( lp_workgroup() );
4002 TDB_DATA data = { NULL, 0 };
4008 /* See if we were asked to delete the cache entry */
4011 ret = tdb_delete( wcache->tdb, key );
4015 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4022 ret = tdb_store( wcache->tdb, key, data, 0 );
4025 SAFE_FREE( data.dptr );
4026 SAFE_FREE( key.dptr );
4028 return ( ret != -1 );
4031 /*********************************************************************
4032 ********************************************************************/
4034 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4036 TDB_DATA key = make_tdc_key( lp_workgroup() );
4037 TDB_DATA data = { NULL, 0 };
4045 data = tdb_fetch( wcache->tdb, key );
4047 SAFE_FREE( key.dptr );
4052 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4054 SAFE_FREE( data.dptr );
4062 /*********************************************************************
4063 ********************************************************************/
4065 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4067 struct winbindd_tdc_domain *dom_list = NULL;
4068 size_t num_domains = 0;
4071 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4072 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4073 domain->name, domain->alt_name,
4074 sid_string_dbg(&domain->sid),
4075 domain->domain_flags,
4076 domain->domain_trust_attribs,
4077 domain->domain_type));
4079 if ( !init_wcache() ) {
4083 /* fetch the list */
4085 wcache_tdc_fetch_list( &dom_list, &num_domains );
4087 /* add the new domain */
4089 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4093 /* pack the domain */
4095 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4103 TALLOC_FREE( dom_list );
4108 /*********************************************************************
4109 ********************************************************************/
4111 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4113 struct winbindd_tdc_domain *dom_list = NULL;
4114 size_t num_domains = 0;
4116 struct winbindd_tdc_domain *d = NULL;
4118 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4120 if ( !init_wcache() ) {
4124 /* fetch the list */
4126 wcache_tdc_fetch_list( &dom_list, &num_domains );
4128 for ( i=0; i<num_domains; i++ ) {
4129 if ( strequal(name, dom_list[i].domain_name) ||
4130 strequal(name, dom_list[i].dns_name) )
4132 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4135 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4139 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4140 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4141 sid_copy( &d->sid, &dom_list[i].sid );
4142 d->trust_flags = dom_list[i].trust_flags;
4143 d->trust_type = dom_list[i].trust_type;
4144 d->trust_attribs = dom_list[i].trust_attribs;
4150 TALLOC_FREE( dom_list );
4156 /*********************************************************************
4157 ********************************************************************/
4159 void wcache_tdc_clear( void )
4161 if ( !init_wcache() )
4164 wcache_tdc_store_list( NULL, 0 );
4170 /*********************************************************************
4171 ********************************************************************/
4173 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4175 const DOM_SID *user_sid,
4176 const char *homedir,
4181 struct cache_entry *centry;
4184 if ( (centry = centry_start(domain, status)) == NULL )
4187 centry_put_string( centry, homedir );
4188 centry_put_string( centry, shell );
4189 centry_put_string( centry, gecos );
4190 centry_put_uint32( centry, gid );
4192 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4194 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4196 centry_free(centry);
4199 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4200 const DOM_SID *user_sid,
4202 ADS_STRUCT *ads, LDAPMessage *msg,
4203 char **homedir, char **shell, char **gecos,
4206 struct winbind_cache *cache = get_cache(domain);
4207 struct cache_entry *centry = NULL;
4214 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4215 sid_to_fstring(tmp, user_sid));
4220 *homedir = centry_string( centry, ctx );
4221 *shell = centry_string( centry, ctx );
4222 *gecos = centry_string( centry, ctx );
4223 *p_gid = centry_uint32( centry );
4225 centry_free(centry);
4227 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4228 sid_string_dbg(user_sid)));
4230 return NT_STATUS_OK;
4234 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4235 homedir, shell, gecos, p_gid );
4237 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4239 if ( NT_STATUS_IS_OK(nt_status) ) {
4240 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4241 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4242 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4243 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4245 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4246 *homedir, *shell, *gecos, *p_gid );
4249 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4250 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4252 set_domain_offline( domain );
4259 /* the cache backend methods are exposed via this structure */
4260 struct winbindd_methods cache_methods = {