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 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
1813 have_unmapped = true;
1816 /* something's definitely wrong */
1817 result = centry->status;
1821 centry_free(centry);
1825 return NT_STATUS_NONE_MAPPED;
1827 if (!have_unmapped) {
1828 return NT_STATUS_OK;
1830 return STATUS_SOME_UNMAPPED;
1834 TALLOC_FREE(*names);
1835 TALLOC_FREE(*types);
1837 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1838 rids, num_rids, domain_name,
1842 None of the queried rids has been found so save all negative entries
1844 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1845 for (i = 0; i < num_rids; i++) {
1847 const char *name = "";
1848 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1849 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1851 if (!sid_compose(&sid, domain_sid, rids[i])) {
1852 return NT_STATUS_INTERNAL_ERROR;
1855 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1863 Some or all of the queried rids have been found.
1865 if (!NT_STATUS_IS_OK(result) &&
1866 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1870 refresh_sequence_number(domain, false);
1872 for (i=0; i<num_rids; i++) {
1876 if (!sid_compose(&sid, domain_sid, rids[i])) {
1877 result = NT_STATUS_INTERNAL_ERROR;
1881 status = (*types)[i] == SID_NAME_UNKNOWN ?
1882 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1884 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1885 (*names)[i], (*types)[i]);
1892 TALLOC_FREE(*names);
1893 TALLOC_FREE(*types);
1897 /* Lookup user information from a rid */
1898 static NTSTATUS query_user(struct winbindd_domain *domain,
1899 TALLOC_CTX *mem_ctx,
1900 const DOM_SID *user_sid,
1901 WINBIND_USERINFO *info)
1903 struct winbind_cache *cache = get_cache(domain);
1904 struct cache_entry *centry = NULL;
1911 centry = wcache_fetch(cache, domain, "U/%s",
1912 sid_to_fstring(tmp, user_sid));
1914 /* If we have an access denied cache entry and a cached info3 in the
1915 samlogon cache then do a query. This will force the rpc back end
1916 to return the info3 data. */
1918 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1919 netsamlogon_cache_have(user_sid)) {
1920 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1921 domain->last_status = NT_STATUS_OK;
1922 centry_free(centry);
1929 /* if status is not ok then this is a negative hit
1930 and the rest of the data doesn't matter */
1931 status = centry->status;
1932 if (NT_STATUS_IS_OK(status)) {
1933 info->acct_name = centry_string(centry, mem_ctx);
1934 info->full_name = centry_string(centry, mem_ctx);
1935 info->homedir = centry_string(centry, mem_ctx);
1936 info->shell = centry_string(centry, mem_ctx);
1937 info->primary_gid = centry_uint32(centry);
1938 centry_sid(centry, mem_ctx, &info->user_sid);
1939 centry_sid(centry, mem_ctx, &info->group_sid);
1942 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1943 domain->name, nt_errstr(status) ));
1945 centry_free(centry);
1951 /* Return status value returned by seq number check */
1953 if (!NT_STATUS_IS_OK(domain->last_status))
1954 return domain->last_status;
1956 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1959 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1962 refresh_sequence_number(domain, false);
1963 wcache_save_user(domain, status, info);
1969 /* Lookup groups a user is a member of. */
1970 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1971 TALLOC_CTX *mem_ctx,
1972 const DOM_SID *user_sid,
1973 uint32 *num_groups, DOM_SID **user_gids)
1975 struct winbind_cache *cache = get_cache(domain);
1976 struct cache_entry *centry = NULL;
1984 centry = wcache_fetch(cache, domain, "UG/%s",
1985 sid_to_fstring(sid_string, user_sid));
1987 /* If we have an access denied cache entry and a cached info3 in the
1988 samlogon cache then do a query. This will force the rpc back end
1989 to return the info3 data. */
1991 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1992 netsamlogon_cache_have(user_sid)) {
1993 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1994 domain->last_status = NT_STATUS_OK;
1995 centry_free(centry);
2002 *num_groups = centry_uint32(centry);
2004 if (*num_groups == 0)
2007 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
2008 if (! (*user_gids)) {
2009 smb_panic_fn("lookup_usergroups out of memory");
2011 for (i=0; i<(*num_groups); i++) {
2012 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
2016 status = centry->status;
2018 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
2019 domain->name, nt_errstr(status) ));
2021 centry_free(centry);
2026 (*user_gids) = NULL;
2028 /* Return status value returned by seq number check */
2030 if (!NT_STATUS_IS_OK(domain->last_status))
2031 return domain->last_status;
2033 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2036 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2038 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2042 refresh_sequence_number(domain, false);
2043 centry = centry_start(domain, status);
2047 centry_put_uint32(centry, *num_groups);
2048 for (i=0; i<(*num_groups); i++) {
2049 centry_put_sid(centry, &(*user_gids)[i]);
2052 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2053 centry_free(centry);
2059 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2060 TALLOC_CTX *mem_ctx,
2061 uint32 num_sids, const DOM_SID *sids,
2062 uint32 *num_aliases, uint32 **alias_rids)
2064 struct winbind_cache *cache = get_cache(domain);
2065 struct cache_entry *centry = NULL;
2067 char *sidlist = talloc_strdup(mem_ctx, "");
2073 if (num_sids == 0) {
2076 return NT_STATUS_OK;
2079 /* We need to cache indexed by the whole list of SIDs, the aliases
2080 * resulting might come from any of the SIDs. */
2082 for (i=0; i<num_sids; i++) {
2084 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
2085 sid_to_fstring(tmp, &sids[i]));
2086 if (sidlist == NULL)
2087 return NT_STATUS_NO_MEMORY;
2090 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2095 *num_aliases = centry_uint32(centry);
2099 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
2101 if ((*alias_rids) == NULL) {
2102 centry_free(centry);
2103 return NT_STATUS_NO_MEMORY;
2106 (*alias_rids) = NULL;
2109 for (i=0; i<(*num_aliases); i++)
2110 (*alias_rids)[i] = centry_uint32(centry);
2112 status = centry->status;
2114 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2115 "status %s\n", domain->name, nt_errstr(status)));
2117 centry_free(centry);
2122 (*alias_rids) = NULL;
2124 if (!NT_STATUS_IS_OK(domain->last_status))
2125 return domain->last_status;
2127 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2128 "for domain %s\n", domain->name ));
2130 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2132 num_aliases, alias_rids);
2135 refresh_sequence_number(domain, false);
2136 centry = centry_start(domain, status);
2139 centry_put_uint32(centry, *num_aliases);
2140 for (i=0; i<(*num_aliases); i++)
2141 centry_put_uint32(centry, (*alias_rids)[i]);
2142 centry_end(centry, "UA%s", sidlist);
2143 centry_free(centry);
2150 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2151 TALLOC_CTX *mem_ctx,
2152 const DOM_SID *group_sid, uint32 *num_names,
2153 DOM_SID **sid_mem, char ***names,
2154 uint32 **name_types)
2156 struct winbind_cache *cache = get_cache(domain);
2157 struct cache_entry *centry = NULL;
2165 centry = wcache_fetch(cache, domain, "GM/%s",
2166 sid_to_fstring(sid_string, group_sid));
2170 *num_names = centry_uint32(centry);
2172 if (*num_names == 0)
2175 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
2176 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
2177 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
2179 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
2180 smb_panic_fn("lookup_groupmem out of memory");
2183 for (i=0; i<(*num_names); i++) {
2184 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
2185 (*names)[i] = centry_string(centry, mem_ctx);
2186 (*name_types)[i] = centry_uint32(centry);
2190 status = centry->status;
2192 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2193 domain->name, nt_errstr(status)));
2195 centry_free(centry);
2202 (*name_types) = NULL;
2204 /* Return status value returned by seq number check */
2206 if (!NT_STATUS_IS_OK(domain->last_status))
2207 return domain->last_status;
2209 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2212 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2213 sid_mem, names, name_types);
2216 refresh_sequence_number(domain, false);
2217 centry = centry_start(domain, status);
2220 centry_put_uint32(centry, *num_names);
2221 for (i=0; i<(*num_names); i++) {
2222 centry_put_sid(centry, &(*sid_mem)[i]);
2223 centry_put_string(centry, (*names)[i]);
2224 centry_put_uint32(centry, (*name_types)[i]);
2226 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2227 centry_free(centry);
2233 /* find the sequence number for a domain */
2234 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2236 refresh_sequence_number(domain, false);
2238 *seq = domain->sequence_number;
2240 return NT_STATUS_OK;
2243 /* enumerate trusted domains
2244 * (we need to have the list of trustdoms in the cache when we go offline) -
2246 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2247 TALLOC_CTX *mem_ctx,
2248 uint32 *num_domains,
2253 struct winbind_cache *cache = get_cache(domain);
2254 struct cache_entry *centry = NULL;
2261 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2267 *num_domains = centry_uint32(centry);
2270 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2271 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2272 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2274 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2275 smb_panic_fn("trusted_domains out of memory");
2279 (*alt_names) = NULL;
2283 for (i=0; i<(*num_domains); i++) {
2284 (*names)[i] = centry_string(centry, mem_ctx);
2285 (*alt_names)[i] = centry_string(centry, mem_ctx);
2286 if (!centry_sid(centry, mem_ctx, &(*dom_sids)[i])) {
2287 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2291 status = centry->status;
2293 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2294 domain->name, *num_domains, nt_errstr(status) ));
2296 centry_free(centry);
2303 (*alt_names) = NULL;
2305 /* Return status value returned by seq number check */
2307 if (!NT_STATUS_IS_OK(domain->last_status))
2308 return domain->last_status;
2310 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2313 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2314 names, alt_names, dom_sids);
2316 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2317 * so that the generic centry handling still applies correctly -
2320 if (!NT_STATUS_IS_ERR(status)) {
2321 status = NT_STATUS_OK;
2325 #if 0 /* Disabled as we want the trust dom list to be managed by
2326 the main parent and always to make the query. --jerry */
2329 refresh_sequence_number(domain, false);
2331 centry = centry_start(domain, status);
2335 centry_put_uint32(centry, *num_domains);
2337 for (i=0; i<(*num_domains); i++) {
2338 centry_put_string(centry, (*names)[i]);
2339 centry_put_string(centry, (*alt_names)[i]);
2340 centry_put_sid(centry, &(*dom_sids)[i]);
2343 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2345 centry_free(centry);
2353 /* get lockout policy */
2354 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2355 TALLOC_CTX *mem_ctx,
2356 struct samr_DomInfo12 *policy)
2358 struct winbind_cache *cache = get_cache(domain);
2359 struct cache_entry *centry = NULL;
2365 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2370 policy->lockout_duration = centry_nttime(centry);
2371 policy->lockout_window = centry_nttime(centry);
2372 policy->lockout_threshold = centry_uint16(centry);
2374 status = centry->status;
2376 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2377 domain->name, nt_errstr(status) ));
2379 centry_free(centry);
2383 ZERO_STRUCTP(policy);
2385 /* Return status value returned by seq number check */
2387 if (!NT_STATUS_IS_OK(domain->last_status))
2388 return domain->last_status;
2390 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2393 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2396 refresh_sequence_number(domain, false);
2397 wcache_save_lockout_policy(domain, status, policy);
2402 /* get password policy */
2403 static NTSTATUS password_policy(struct winbindd_domain *domain,
2404 TALLOC_CTX *mem_ctx,
2405 struct samr_DomInfo1 *policy)
2407 struct winbind_cache *cache = get_cache(domain);
2408 struct cache_entry *centry = NULL;
2414 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2419 policy->min_password_length = centry_uint16(centry);
2420 policy->password_history_length = centry_uint16(centry);
2421 policy->password_properties = centry_uint32(centry);
2422 policy->max_password_age = centry_nttime(centry);
2423 policy->min_password_age = centry_nttime(centry);
2425 status = centry->status;
2427 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2428 domain->name, nt_errstr(status) ));
2430 centry_free(centry);
2434 ZERO_STRUCTP(policy);
2436 /* Return status value returned by seq number check */
2438 if (!NT_STATUS_IS_OK(domain->last_status))
2439 return domain->last_status;
2441 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2444 status = domain->backend->password_policy(domain, mem_ctx, policy);
2447 refresh_sequence_number(domain, false);
2448 if (NT_STATUS_IS_OK(status)) {
2449 wcache_save_password_policy(domain, status, policy);
2456 /* Invalidate cached user and group lists coherently */
2458 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2461 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2462 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2463 tdb_delete(the_tdb, kbuf);
2468 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2470 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2471 struct netr_SamInfo3 *info3)
2474 fstring key_str, sid_string;
2475 struct winbind_cache *cache;
2477 /* dont clear cached U/SID and UG/SID entries when we want to logon
2480 if (lp_winbind_offline_logon()) {
2487 cache = get_cache(domain);
2493 sid_copy(&sid, info3->base.domain_sid);
2494 sid_append_rid(&sid, info3->base.rid);
2496 /* Clear U/SID cache entry */
2497 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2498 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2499 tdb_delete(cache->tdb, string_tdb_data(key_str));
2501 /* Clear UG/SID cache entry */
2502 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2503 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2504 tdb_delete(cache->tdb, string_tdb_data(key_str));
2506 /* Samba/winbindd never needs this. */
2507 netsamlogon_clear_cached_user(info3);
2510 bool wcache_invalidate_cache(void)
2512 struct winbindd_domain *domain;
2514 for (domain = domain_list(); domain; domain = domain->next) {
2515 struct winbind_cache *cache = get_cache(domain);
2517 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2518 "entries for %s\n", domain->name));
2521 tdb_traverse(cache->tdb, traverse_fn, NULL);
2530 bool init_wcache(void)
2532 if (wcache == NULL) {
2533 wcache = SMB_XMALLOC_P(struct winbind_cache);
2534 ZERO_STRUCTP(wcache);
2537 if (wcache->tdb != NULL)
2540 /* when working offline we must not clear the cache on restart */
2541 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2542 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2543 ( lp_winbind_offline_logon()
2545 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
2546 O_RDWR|O_CREAT, 0600);
2548 if (wcache->tdb == NULL) {
2549 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2556 /************************************************************************
2557 This is called by the parent to initialize the cache file.
2558 We don't need sophisticated locking here as we know we're the
2560 ************************************************************************/
2562 bool initialize_winbindd_cache(void)
2564 bool cache_bad = true;
2567 if (!init_wcache()) {
2568 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2572 /* Check version number. */
2573 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2574 vers == WINBINDD_CACHE_VERSION) {
2579 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2580 "and re-creating with version number %d\n",
2581 WINBINDD_CACHE_VERSION ));
2583 tdb_close(wcache->tdb);
2586 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2587 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2588 cache_path("winbindd_cache.tdb"),
2592 if (!init_wcache()) {
2593 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2594 "init_wcache failed.\n"));
2598 /* Write the version. */
2599 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2600 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2601 tdb_errorstr(wcache->tdb) ));
2606 tdb_close(wcache->tdb);
2611 void close_winbindd_cache(void)
2617 tdb_close(wcache->tdb);
2622 void cache_store_response(pid_t pid, struct winbindd_response *response)
2629 DEBUG(10, ("Storing response for pid %d, len %d\n",
2630 (int)pid, response->length));
2632 fstr_sprintf(key_str, "DR/%d", (int)pid);
2633 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2634 make_tdb_data((uint8 *)response, sizeof(*response)),
2638 if (response->length == sizeof(*response))
2641 /* There's extra data */
2643 DEBUG(10, ("Storing extra data: len=%d\n",
2644 (int)(response->length - sizeof(*response))));
2646 fstr_sprintf(key_str, "DE/%d", (int)pid);
2647 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2648 make_tdb_data((uint8 *)response->extra_data.data,
2649 response->length - sizeof(*response)),
2653 /* We could not store the extra data, make sure the tdb does not
2654 * contain a main record with wrong dangling extra data */
2656 fstr_sprintf(key_str, "DR/%d", (int)pid);
2657 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2662 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2670 DEBUG(10, ("Retrieving response for pid %d\n", (int)pid));
2672 fstr_sprintf(key_str, "DR/%d", (int)pid);
2673 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2675 if (data.dptr == NULL)
2678 if (data.dsize != sizeof(*response))
2681 memcpy(response, data.dptr, data.dsize);
2682 SAFE_FREE(data.dptr);
2684 if (response->length == sizeof(*response)) {
2685 response->extra_data.data = NULL;
2689 /* There's extra data */
2691 DEBUG(10, ("Retrieving extra data length=%d\n",
2692 (int)(response->length - sizeof(*response))));
2694 fstr_sprintf(key_str, "DE/%d", (int)pid);
2695 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2697 if (data.dptr == NULL) {
2698 DEBUG(0, ("Did not find extra data\n"));
2702 if (data.dsize != (response->length - sizeof(*response))) {
2703 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2704 SAFE_FREE(data.dptr);
2708 dump_data(11, (uint8 *)data.dptr, data.dsize);
2710 response->extra_data.data = data.dptr;
2714 void cache_cleanup_response(pid_t pid)
2721 fstr_sprintf(key_str, "DR/%d", (int)pid);
2722 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2724 fstr_sprintf(key_str, "DE/%d", (int)pid);
2725 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2731 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2732 char **domain_name, char **name,
2733 enum lsa_SidType *type)
2735 struct winbindd_domain *domain;
2736 struct winbind_cache *cache;
2737 struct cache_entry *centry = NULL;
2741 domain = find_lookup_domain_from_sid(sid);
2742 if (domain == NULL) {
2746 cache = get_cache(domain);
2748 if (cache->tdb == NULL) {
2752 centry = wcache_fetch(cache, domain, "SN/%s",
2753 sid_to_fstring(tmp, sid));
2754 if (centry == NULL) {
2758 if (NT_STATUS_IS_OK(centry->status)) {
2759 *type = (enum lsa_SidType)centry_uint32(centry);
2760 *domain_name = centry_string(centry, mem_ctx);
2761 *name = centry_string(centry, mem_ctx);
2764 status = centry->status;
2765 centry_free(centry);
2766 return NT_STATUS_IS_OK(status);
2769 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2770 const char *domain_name,
2773 enum lsa_SidType *type)
2775 struct winbindd_domain *domain;
2776 struct winbind_cache *cache;
2777 struct cache_entry *centry = NULL;
2780 bool original_online_state;
2782 domain = find_lookup_domain_from_name(domain_name);
2783 if (domain == NULL) {
2787 cache = get_cache(domain);
2789 if (cache->tdb == NULL) {
2793 fstrcpy(uname, name);
2796 /* If we are doing a cached logon, temporarily set the domain
2797 offline so the cache won't expire the entry */
2799 original_online_state = domain->online;
2800 domain->online = false;
2801 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2802 domain->online = original_online_state;
2804 if (centry == NULL) {
2808 if (NT_STATUS_IS_OK(centry->status)) {
2809 *type = (enum lsa_SidType)centry_uint32(centry);
2810 centry_sid(centry, mem_ctx, sid);
2813 status = centry->status;
2814 centry_free(centry);
2816 return NT_STATUS_IS_OK(status);
2819 void cache_name2sid(struct winbindd_domain *domain,
2820 const char *domain_name, const char *name,
2821 enum lsa_SidType type, const DOM_SID *sid)
2823 refresh_sequence_number(domain, false);
2824 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2829 * The original idea that this cache only contains centries has
2830 * been blurred - now other stuff gets put in here. Ensure we
2831 * ignore these things on cleanup.
2834 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2835 TDB_DATA dbuf, void *state)
2837 struct cache_entry *centry;
2839 if (is_non_centry_key(kbuf)) {
2843 centry = wcache_fetch_raw((char *)kbuf.dptr);
2848 if (!NT_STATUS_IS_OK(centry->status)) {
2849 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2850 tdb_delete(the_tdb, kbuf);
2853 centry_free(centry);
2857 /* flush the cache */
2858 void wcache_flush_cache(void)
2863 tdb_close(wcache->tdb);
2866 if (!winbindd_use_cache()) {
2870 /* when working offline we must not clear the cache on restart */
2871 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2872 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2873 ( lp_winbind_offline_logon()
2875 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
2876 O_RDWR|O_CREAT, 0600);
2879 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2883 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2885 DEBUG(10,("wcache_flush_cache success\n"));
2888 /* Count cached creds */
2890 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2893 int *cred_count = (int*)state;
2895 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2901 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2903 struct winbind_cache *cache = get_cache(domain);
2908 return NT_STATUS_INTERNAL_DB_ERROR;
2911 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2913 return NT_STATUS_OK;
2917 struct cred_list *prev, *next;
2922 static struct cred_list *wcache_cred_list;
2924 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2927 struct cred_list *cred;
2929 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2931 cred = SMB_MALLOC_P(struct cred_list);
2933 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2939 /* save a copy of the key */
2941 fstrcpy(cred->name, (const char *)kbuf.dptr);
2942 DLIST_ADD(wcache_cred_list, cred);
2948 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2950 struct winbind_cache *cache = get_cache(domain);
2953 struct cred_list *cred, *oldest = NULL;
2956 return NT_STATUS_INTERNAL_DB_ERROR;
2959 /* we possibly already have an entry */
2960 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2962 fstring key_str, tmp;
2964 DEBUG(11,("we already have an entry, deleting that\n"));
2966 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2968 tdb_delete(cache->tdb, string_tdb_data(key_str));
2970 return NT_STATUS_OK;
2973 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2975 return NT_STATUS_OK;
2976 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2977 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2980 ZERO_STRUCTP(oldest);
2982 for (cred = wcache_cred_list; cred; cred = cred->next) {
2987 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2989 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2991 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2995 t = IVAL(data.dptr, 0);
2996 SAFE_FREE(data.dptr);
2999 oldest = SMB_MALLOC_P(struct cred_list);
3000 if (oldest == NULL) {
3001 status = NT_STATUS_NO_MEMORY;
3005 fstrcpy(oldest->name, cred->name);
3006 oldest->created = t;
3010 if (t < oldest->created) {
3011 fstrcpy(oldest->name, cred->name);
3012 oldest->created = t;
3016 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3017 status = NT_STATUS_OK;
3019 status = NT_STATUS_UNSUCCESSFUL;
3022 SAFE_FREE(wcache_cred_list);
3028 /* Change the global online/offline state. */
3029 bool set_global_winbindd_state_offline(void)
3033 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3035 /* Only go offline if someone has created
3036 the key "WINBINDD_OFFLINE" in the cache tdb. */
3038 if (wcache == NULL || wcache->tdb == NULL) {
3039 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3043 if (!lp_winbind_offline_logon()) {
3044 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3048 if (global_winbindd_offline_state) {
3049 /* Already offline. */
3053 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3055 if (!data.dptr || data.dsize != 4) {
3056 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3057 SAFE_FREE(data.dptr);
3060 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3061 global_winbindd_offline_state = true;
3062 SAFE_FREE(data.dptr);
3067 void set_global_winbindd_state_online(void)
3069 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3071 if (!lp_winbind_offline_logon()) {
3072 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3076 if (!global_winbindd_offline_state) {
3077 /* Already online. */
3080 global_winbindd_offline_state = false;
3086 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3087 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3090 bool get_global_winbindd_state_offline(void)
3092 return global_winbindd_offline_state;
3095 /***********************************************************************
3096 Validate functions for all possible cache tdb keys.
3097 ***********************************************************************/
3099 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3100 struct tdb_validation_status *state)
3102 struct cache_entry *centry;
3104 centry = SMB_XMALLOC_P(struct cache_entry);
3105 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3106 if (!centry->data) {
3110 centry->len = data.dsize;
3113 if (centry->len < 8) {
3114 /* huh? corrupt cache? */
3115 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3116 centry_free(centry);
3117 state->bad_entry = true;
3118 state->success = false;
3122 centry->status = NT_STATUS(centry_uint32(centry));
3123 centry->sequence_number = centry_uint32(centry);
3127 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3128 struct tdb_validation_status *state)
3130 if (dbuf.dsize != 8) {
3131 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3132 keystr, (unsigned int)dbuf.dsize ));
3133 state->bad_entry = true;
3139 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3140 struct tdb_validation_status *state)
3142 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3147 (void)centry_uint32(centry);
3148 if (NT_STATUS_IS_OK(centry->status)) {
3150 (void)centry_sid(centry, mem_ctx, &sid);
3153 centry_free(centry);
3155 if (!(state->success)) {
3158 DEBUG(10,("validate_ns: %s ok\n", keystr));
3162 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3163 struct tdb_validation_status *state)
3165 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3170 if (NT_STATUS_IS_OK(centry->status)) {
3171 (void)centry_uint32(centry);
3172 (void)centry_string(centry, mem_ctx);
3173 (void)centry_string(centry, mem_ctx);
3176 centry_free(centry);
3178 if (!(state->success)) {
3181 DEBUG(10,("validate_sn: %s ok\n", keystr));
3185 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3186 struct tdb_validation_status *state)
3188 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3195 (void)centry_string(centry, mem_ctx);
3196 (void)centry_string(centry, mem_ctx);
3197 (void)centry_string(centry, mem_ctx);
3198 (void)centry_string(centry, mem_ctx);
3199 (void)centry_uint32(centry);
3200 (void)centry_sid(centry, mem_ctx, &sid);
3201 (void)centry_sid(centry, mem_ctx, &sid);
3203 centry_free(centry);
3205 if (!(state->success)) {
3208 DEBUG(10,("validate_u: %s ok\n", keystr));
3212 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3213 struct tdb_validation_status *state)
3215 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3221 (void)centry_nttime(centry);
3222 (void)centry_nttime(centry);
3223 (void)centry_uint16(centry);
3225 centry_free(centry);
3227 if (!(state->success)) {
3230 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3234 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3235 struct tdb_validation_status *state)
3237 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3243 (void)centry_uint16(centry);
3244 (void)centry_uint16(centry);
3245 (void)centry_uint32(centry);
3246 (void)centry_nttime(centry);
3247 (void)centry_nttime(centry);
3249 centry_free(centry);
3251 if (!(state->success)) {
3254 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3258 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3259 struct tdb_validation_status *state)
3261 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3267 (void)centry_time(centry);
3268 (void)centry_hash16(centry, mem_ctx);
3270 /* We only have 17 bytes more data in the salted cred case. */
3271 if (centry->len - centry->ofs == 17) {
3272 (void)centry_hash16(centry, mem_ctx);
3275 centry_free(centry);
3277 if (!(state->success)) {
3280 DEBUG(10,("validate_cred: %s ok\n", keystr));
3284 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3285 struct tdb_validation_status *state)
3287 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3288 int32 num_entries, i;
3294 num_entries = (int32)centry_uint32(centry);
3296 for (i=0; i< num_entries; i++) {
3298 (void)centry_string(centry, mem_ctx);
3299 (void)centry_string(centry, mem_ctx);
3300 (void)centry_string(centry, mem_ctx);
3301 (void)centry_string(centry, mem_ctx);
3302 (void)centry_sid(centry, mem_ctx, &sid);
3303 (void)centry_sid(centry, mem_ctx, &sid);
3306 centry_free(centry);
3308 if (!(state->success)) {
3311 DEBUG(10,("validate_ul: %s ok\n", keystr));
3315 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3316 struct tdb_validation_status *state)
3318 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3319 int32 num_entries, i;
3325 num_entries = centry_uint32(centry);
3327 for (i=0; i< num_entries; i++) {
3328 (void)centry_string(centry, mem_ctx);
3329 (void)centry_string(centry, mem_ctx);
3330 (void)centry_uint32(centry);
3333 centry_free(centry);
3335 if (!(state->success)) {
3338 DEBUG(10,("validate_gl: %s ok\n", keystr));
3342 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3343 struct tdb_validation_status *state)
3345 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3346 int32 num_groups, i;
3352 num_groups = centry_uint32(centry);
3354 for (i=0; i< num_groups; i++) {
3356 centry_sid(centry, mem_ctx, &sid);
3359 centry_free(centry);
3361 if (!(state->success)) {
3364 DEBUG(10,("validate_ug: %s ok\n", keystr));
3368 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3369 struct tdb_validation_status *state)
3371 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3372 int32 num_aliases, i;
3378 num_aliases = centry_uint32(centry);
3380 for (i=0; i < num_aliases; i++) {
3381 (void)centry_uint32(centry);
3384 centry_free(centry);
3386 if (!(state->success)) {
3389 DEBUG(10,("validate_ua: %s ok\n", keystr));
3393 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3394 struct tdb_validation_status *state)
3396 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3403 num_names = centry_uint32(centry);
3405 for (i=0; i< num_names; i++) {
3407 centry_sid(centry, mem_ctx, &sid);
3408 (void)centry_string(centry, mem_ctx);
3409 (void)centry_uint32(centry);
3412 centry_free(centry);
3414 if (!(state->success)) {
3417 DEBUG(10,("validate_gm: %s ok\n", keystr));
3421 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3422 struct tdb_validation_status *state)
3424 /* Can't say anything about this other than must be nonzero. */
3425 if (dbuf.dsize == 0) {
3426 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3428 state->bad_entry = true;
3429 state->success = false;
3433 DEBUG(10,("validate_dr: %s ok\n", keystr));
3437 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3438 struct tdb_validation_status *state)
3440 /* Can't say anything about this other than must be nonzero. */
3441 if (dbuf.dsize == 0) {
3442 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3444 state->bad_entry = true;
3445 state->success = false;
3449 DEBUG(10,("validate_de: %s ok\n", keystr));
3453 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3454 TDB_DATA dbuf, struct tdb_validation_status *state)
3456 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3462 (void)centry_string(centry, mem_ctx);
3463 (void)centry_string(centry, mem_ctx);
3464 (void)centry_string(centry, mem_ctx);
3465 (void)centry_uint32(centry);
3467 centry_free(centry);
3469 if (!(state->success)) {
3472 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3476 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3478 struct tdb_validation_status *state)
3480 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3486 (void)centry_string( centry, mem_ctx );
3488 centry_free(centry);
3490 if (!(state->success)) {
3493 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3497 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3499 struct tdb_validation_status *state)
3501 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3507 (void)centry_string( centry, mem_ctx );
3509 centry_free(centry);
3511 if (!(state->success)) {
3514 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3518 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3519 struct tdb_validation_status *state)
3521 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3522 int32 num_domains, i;
3528 num_domains = centry_uint32(centry);
3530 for (i=0; i< num_domains; i++) {
3532 (void)centry_string(centry, mem_ctx);
3533 (void)centry_string(centry, mem_ctx);
3534 (void)centry_sid(centry, mem_ctx, &sid);
3537 centry_free(centry);
3539 if (!(state->success)) {
3542 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3546 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3548 struct tdb_validation_status *state)
3550 if (dbuf.dsize == 0) {
3551 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3552 "key %s (len ==0) ?\n", keystr));
3553 state->bad_entry = true;
3554 state->success = false;
3558 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3559 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3563 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3564 struct tdb_validation_status *state)
3566 if (dbuf.dsize != 4) {
3567 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3568 keystr, (unsigned int)dbuf.dsize ));
3569 state->bad_entry = true;
3570 state->success = false;
3573 DEBUG(10,("validate_offline: %s ok\n", keystr));
3577 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3578 struct tdb_validation_status *state)
3580 if (dbuf.dsize != 4) {
3581 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3582 "key %s (len %u != 4) ?\n",
3583 keystr, (unsigned int)dbuf.dsize));
3584 state->bad_entry = true;
3585 state->success = false;
3589 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3593 /***********************************************************************
3594 A list of all possible cache tdb keys with associated validation
3596 ***********************************************************************/
3598 struct key_val_struct {
3599 const char *keyname;
3600 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3602 {"SEQNUM/", validate_seqnum},
3603 {"NS/", validate_ns},
3604 {"SN/", validate_sn},
3606 {"LOC_POL/", validate_loc_pol},
3607 {"PWD_POL/", validate_pwd_pol},
3608 {"CRED/", validate_cred},
3609 {"UL/", validate_ul},
3610 {"GL/", validate_gl},
3611 {"UG/", validate_ug},
3612 {"UA", validate_ua},
3613 {"GM/", validate_gm},
3614 {"DR/", validate_dr},
3615 {"DE/", validate_de},
3616 {"NSS/PWINFO/", validate_pwinfo},
3617 {"TRUSTDOMS/", validate_trustdoms},
3618 {"TRUSTDOMCACHE/", validate_trustdomcache},
3619 {"NSS/NA/", validate_nss_na},
3620 {"NSS/AN/", validate_nss_an},
3621 {"WINBINDD_OFFLINE", validate_offline},
3622 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3626 /***********************************************************************
3627 Function to look at every entry in the tdb and validate it as far as
3629 ***********************************************************************/
3631 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3634 unsigned int max_key_len = 1024;
3635 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3637 /* Paranoia check. */
3638 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3639 max_key_len = 1024 * 1024;
3641 if (kbuf.dsize > max_key_len) {
3642 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3644 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3648 for (i = 0; key_val[i].keyname; i++) {
3649 size_t namelen = strlen(key_val[i].keyname);
3650 if (kbuf.dsize >= namelen && (
3651 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3652 TALLOC_CTX *mem_ctx;
3656 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3660 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3661 keystr[kbuf.dsize] = '\0';
3663 mem_ctx = talloc_init("validate_ctx");
3669 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3673 talloc_destroy(mem_ctx);
3678 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3679 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3680 DEBUG(0,("data :\n"));
3681 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3682 v_state->unknown_key = true;
3683 v_state->success = false;
3684 return 1; /* terminate. */
3687 static void validate_panic(const char *const why)
3689 DEBUG(0,("validating cache: would panic %s\n", why ));
3690 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3694 /***********************************************************************
3695 Try and validate every entry in the winbindd cache. If we fail here,
3696 delete the cache tdb and return non-zero.
3697 ***********************************************************************/
3699 int winbindd_validate_cache(void)
3702 const char *tdb_path = cache_path("winbindd_cache.tdb");
3703 TDB_CONTEXT *tdb = NULL;
3705 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3706 smb_panic_fn = validate_panic;
3709 tdb = tdb_open_log(tdb_path,
3710 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3711 ( lp_winbind_offline_logon()
3713 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST | TDB_INCOMPATIBLE_HASH ),
3717 DEBUG(0, ("winbindd_validate_cache: "
3718 "error opening/initializing tdb\n"));
3723 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3726 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3727 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3732 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3733 smb_panic_fn = smb_panic;
3737 /***********************************************************************
3738 Try and validate every entry in the winbindd cache.
3739 ***********************************************************************/
3741 int winbindd_validate_cache_nobackup(void)
3744 const char *tdb_path = cache_path("winbindd_cache.tdb");
3746 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3747 smb_panic_fn = validate_panic;
3750 if (wcache == NULL || wcache->tdb == NULL) {
3751 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3753 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3757 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3761 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3763 smb_panic_fn = smb_panic;
3767 bool winbindd_cache_validate_and_initialize(void)
3769 close_winbindd_cache();
3771 if (lp_winbind_offline_logon()) {
3772 if (winbindd_validate_cache() < 0) {
3773 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3774 "could be restored.\n"));
3778 return initialize_winbindd_cache();
3781 /*********************************************************************
3782 ********************************************************************/
3784 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3785 struct winbindd_tdc_domain **domains,
3786 size_t *num_domains )
3788 struct winbindd_tdc_domain *list = NULL;
3791 bool set_only = false;
3793 /* don't allow duplicates */
3798 for ( i=0; i< (*num_domains); i++ ) {
3799 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3800 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3811 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3814 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3815 struct winbindd_tdc_domain,
3820 ZERO_STRUCT( list[idx] );
3826 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3827 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3829 if ( !is_null_sid( &new_dom->sid ) ) {
3830 sid_copy( &list[idx].sid, &new_dom->sid );
3832 sid_copy(&list[idx].sid, &global_sid_NULL);
3835 if ( new_dom->domain_flags != 0x0 )
3836 list[idx].trust_flags = new_dom->domain_flags;
3838 if ( new_dom->domain_type != 0x0 )
3839 list[idx].trust_type = new_dom->domain_type;
3841 if ( new_dom->domain_trust_attribs != 0x0 )
3842 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3846 *num_domains = idx + 1;
3852 /*********************************************************************
3853 ********************************************************************/
3855 static TDB_DATA make_tdc_key( const char *domain_name )
3857 char *keystr = NULL;
3858 TDB_DATA key = { NULL, 0 };
3860 if ( !domain_name ) {
3861 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3866 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3869 key = string_term_tdb_data(keystr);
3874 /*********************************************************************
3875 ********************************************************************/
3877 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3879 unsigned char **buf )
3881 unsigned char *buffer = NULL;
3886 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3894 /* Store the number of array items first */
3895 len += tdb_pack( buffer+len, buflen-len, "d",
3898 /* now pack each domain trust record */
3899 for ( i=0; i<num_domains; i++ ) {
3904 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3905 domains[i].domain_name,
3906 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3909 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3910 domains[i].domain_name,
3911 domains[i].dns_name,
3912 sid_to_fstring(tmp, &domains[i].sid),
3913 domains[i].trust_flags,
3914 domains[i].trust_attribs,
3915 domains[i].trust_type );
3918 if ( buflen < len ) {
3920 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3921 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3935 /*********************************************************************
3936 ********************************************************************/
3938 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3939 struct winbindd_tdc_domain **domains )
3941 fstring domain_name, dns_name, sid_string;
3942 uint32 type, attribs, flags;
3946 struct winbindd_tdc_domain *list = NULL;
3948 /* get the number of domains */
3949 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3951 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3955 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3957 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3961 for ( i=0; i<num_domains; i++ ) {
3962 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3971 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3972 TALLOC_FREE( list );
3976 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3977 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3978 domain_name, dns_name, sid_string,
3979 flags, attribs, type));
3981 list[i].domain_name = talloc_strdup( list, domain_name );
3982 list[i].dns_name = talloc_strdup( list, dns_name );
3983 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3984 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3987 list[i].trust_flags = flags;
3988 list[i].trust_attribs = attribs;
3989 list[i].trust_type = type;
3997 /*********************************************************************
3998 ********************************************************************/
4000 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4002 TDB_DATA key = make_tdc_key( lp_workgroup() );
4003 TDB_DATA data = { NULL, 0 };
4009 /* See if we were asked to delete the cache entry */
4012 ret = tdb_delete( wcache->tdb, key );
4016 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4023 ret = tdb_store( wcache->tdb, key, data, 0 );
4026 SAFE_FREE( data.dptr );
4027 SAFE_FREE( key.dptr );
4029 return ( ret != -1 );
4032 /*********************************************************************
4033 ********************************************************************/
4035 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4037 TDB_DATA key = make_tdc_key( lp_workgroup() );
4038 TDB_DATA data = { NULL, 0 };
4046 data = tdb_fetch( wcache->tdb, key );
4048 SAFE_FREE( key.dptr );
4053 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4055 SAFE_FREE( data.dptr );
4063 /*********************************************************************
4064 ********************************************************************/
4066 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4068 struct winbindd_tdc_domain *dom_list = NULL;
4069 size_t num_domains = 0;
4072 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4073 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4074 domain->name, domain->alt_name,
4075 sid_string_dbg(&domain->sid),
4076 domain->domain_flags,
4077 domain->domain_trust_attribs,
4078 domain->domain_type));
4080 if ( !init_wcache() ) {
4084 /* fetch the list */
4086 wcache_tdc_fetch_list( &dom_list, &num_domains );
4088 /* add the new domain */
4090 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4094 /* pack the domain */
4096 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4104 TALLOC_FREE( dom_list );
4109 /*********************************************************************
4110 ********************************************************************/
4112 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4114 struct winbindd_tdc_domain *dom_list = NULL;
4115 size_t num_domains = 0;
4117 struct winbindd_tdc_domain *d = NULL;
4119 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4121 if ( !init_wcache() ) {
4125 /* fetch the list */
4127 wcache_tdc_fetch_list( &dom_list, &num_domains );
4129 for ( i=0; i<num_domains; i++ ) {
4130 if ( strequal(name, dom_list[i].domain_name) ||
4131 strequal(name, dom_list[i].dns_name) )
4133 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4136 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4140 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4141 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4142 sid_copy( &d->sid, &dom_list[i].sid );
4143 d->trust_flags = dom_list[i].trust_flags;
4144 d->trust_type = dom_list[i].trust_type;
4145 d->trust_attribs = dom_list[i].trust_attribs;
4151 TALLOC_FREE( dom_list );
4157 /*********************************************************************
4158 ********************************************************************/
4160 void wcache_tdc_clear( void )
4162 if ( !init_wcache() )
4165 wcache_tdc_store_list( NULL, 0 );
4171 /*********************************************************************
4172 ********************************************************************/
4174 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4176 const DOM_SID *user_sid,
4177 const char *homedir,
4182 struct cache_entry *centry;
4185 if ( (centry = centry_start(domain, status)) == NULL )
4188 centry_put_string( centry, homedir );
4189 centry_put_string( centry, shell );
4190 centry_put_string( centry, gecos );
4191 centry_put_uint32( centry, gid );
4193 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4195 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4197 centry_free(centry);
4200 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4201 const DOM_SID *user_sid,
4203 ADS_STRUCT *ads, LDAPMessage *msg,
4204 char **homedir, char **shell, char **gecos,
4207 struct winbind_cache *cache = get_cache(domain);
4208 struct cache_entry *centry = NULL;
4215 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4216 sid_to_fstring(tmp, user_sid));
4221 *homedir = centry_string( centry, ctx );
4222 *shell = centry_string( centry, ctx );
4223 *gecos = centry_string( centry, ctx );
4224 *p_gid = centry_uint32( centry );
4226 centry_free(centry);
4228 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4229 sid_string_dbg(user_sid)));
4231 return NT_STATUS_OK;
4235 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4236 homedir, shell, gecos, p_gid );
4238 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4240 if ( NT_STATUS_IS_OK(nt_status) ) {
4241 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4242 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4243 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4244 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4246 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4247 *homedir, *shell, *gecos, *p_gid );
4250 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4251 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4253 set_domain_offline( domain );
4260 /* the cache backend methods are exposed via this structure */
4261 struct winbindd_methods cache_methods = {