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"
29 #include "../libcli/auth/libcli_auth.h"
32 #define DBGC_CLASS DBGC_WINBIND
34 #define WINBINDD_CACHE_VERSION 1
35 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
37 extern struct winbindd_methods reconnect_methods
;
39 extern struct winbindd_methods ads_methods
;
41 extern struct winbindd_methods builtin_passdb_methods
;
44 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
45 * Here are the list of entry types that are *not* stored
46 * as form struct cache_entry in the cache.
49 static const char *non_centry_keys
[] = {
54 WINBINDD_CACHE_VERSION_KEYSTR
,
58 /************************************************************************
59 Is this key a non-centry type ?
60 ************************************************************************/
62 static bool is_non_centry_key(TDB_DATA kbuf
)
66 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
69 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
70 size_t namelen
= strlen(non_centry_keys
[i
]);
71 if (kbuf
.dsize
< namelen
) {
74 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
81 /* Global online/offline state - False when online. winbindd starts up online
82 and sets this to true if the first query fails and there's an entry in
83 the cache tdb telling us to stay offline. */
85 static bool global_winbindd_offline_state
;
87 struct winbind_cache
{
93 uint32 sequence_number
;
98 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
100 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
102 static struct winbind_cache
*wcache
;
104 void winbindd_check_cache_size(time_t t
)
106 static time_t last_check_time
;
109 if (last_check_time
== (time_t)0)
112 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
115 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
116 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
120 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
121 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
125 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
126 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
127 (unsigned long)st
.st_size
,
128 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
129 wcache_flush_cache();
133 /* get the winbind_cache structure */
134 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
136 struct winbind_cache
*ret
= wcache
;
138 /* We have to know what type of domain we are dealing with first. */
140 if (domain
->internal
) {
141 domain
->backend
= &builtin_passdb_methods
;
142 domain
->initialized
= True
;
144 if ( !domain
->initialized
) {
145 init_dc_connection( domain
);
149 OK. listen up becasue I'm only going to say this once.
150 We have the following scenarios to consider
151 (a) trusted AD domains on a Samba DC,
152 (b) trusted AD domains and we are joined to a non-kerberos domain
153 (c) trusted AD domains and we are joined to a kerberos (AD) domain
155 For (a) we can always contact the trusted domain using krb5
156 since we have the domain trust account password
158 For (b) we can only use RPC since we have no way of
159 getting a krb5 ticket in our own domain
161 For (c) we can always use krb5 since we have a kerberos trust
166 if (!domain
->backend
) {
168 struct winbindd_domain
*our_domain
= domain
;
170 /* find our domain first so we can figure out if we
171 are joined to a kerberized domain */
173 if ( !domain
->primary
)
174 our_domain
= find_our_domain();
176 if ((our_domain
->active_directory
|| IS_DC
)
177 && domain
->active_directory
178 && !lp_winbind_rpc_only()) {
179 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
180 domain
->backend
= &ads_methods
;
182 #endif /* HAVE_ADS */
183 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
184 domain
->backend
= &reconnect_methods
;
187 #endif /* HAVE_ADS */
193 ret
= SMB_XMALLOC_P(struct winbind_cache
);
197 wcache_flush_cache();
203 free a centry structure
205 static void centry_free(struct cache_entry
*centry
)
209 SAFE_FREE(centry
->data
);
213 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
215 if (centry
->len
- centry
->ofs
< nbytes
) {
216 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
217 (unsigned int)nbytes
,
218 centry
->len
- centry
->ofs
));
225 pull a uint32 from a cache entry
227 static uint32
centry_uint32(struct cache_entry
*centry
)
231 if (!centry_check_bytes(centry
, 4)) {
232 smb_panic_fn("centry_uint32");
234 ret
= IVAL(centry
->data
, centry
->ofs
);
240 pull a uint16 from a cache entry
242 static uint16
centry_uint16(struct cache_entry
*centry
)
245 if (!centry_check_bytes(centry
, 2)) {
246 smb_panic_fn("centry_uint16");
248 ret
= CVAL(centry
->data
, centry
->ofs
);
254 pull a uint8 from a cache entry
256 static uint8
centry_uint8(struct cache_entry
*centry
)
259 if (!centry_check_bytes(centry
, 1)) {
260 smb_panic_fn("centry_uint8");
262 ret
= CVAL(centry
->data
, centry
->ofs
);
268 pull a NTTIME from a cache entry
270 static NTTIME
centry_nttime(struct cache_entry
*centry
)
273 if (!centry_check_bytes(centry
, 8)) {
274 smb_panic_fn("centry_nttime");
276 ret
= IVAL(centry
->data
, centry
->ofs
);
278 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
284 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
286 static time_t centry_time(struct cache_entry
*centry
)
288 return (time_t)centry_nttime(centry
);
291 /* pull a string from a cache entry, using the supplied
294 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
299 len
= centry_uint8(centry
);
302 /* a deliberate NULL string */
306 if (!centry_check_bytes(centry
, (size_t)len
)) {
307 smb_panic_fn("centry_string");
310 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
312 smb_panic_fn("centry_string out of memory\n");
314 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
320 /* pull a hash16 from a cache entry, using the supplied
323 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
328 len
= centry_uint8(centry
);
331 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
336 if (!centry_check_bytes(centry
, 16)) {
340 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
342 smb_panic_fn("centry_hash out of memory\n");
344 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
349 /* pull a sid from a cache entry, using the supplied
352 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
357 sid_string
= centry_string(centry
, talloc_tos());
358 if (sid_string
== NULL
) {
361 ret
= string_to_sid(sid
, sid_string
);
362 TALLOC_FREE(sid_string
);
368 pull a NTSTATUS from a cache entry
370 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
374 status
= NT_STATUS(centry_uint32(centry
));
379 /* the server is considered down if it can't give us a sequence number */
380 static bool wcache_server_down(struct winbindd_domain
*domain
)
387 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
390 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
395 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
396 uint32_t *last_seq_check
)
401 if (wcache
->tdb
== NULL
) {
402 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
406 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
408 DEBUG(10, ("talloc failed\n"));
412 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
415 if (data
.dptr
== NULL
) {
416 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
420 if (data
.dsize
!= 8) {
421 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
423 SAFE_FREE(data
.dptr
);
427 *seqnum
= IVAL(data
.dptr
, 0);
428 *last_seq_check
= IVAL(data
.dptr
, 4);
429 SAFE_FREE(data
.dptr
);
434 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
436 uint32 last_check
, time_diff
;
438 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
440 return NT_STATUS_UNSUCCESSFUL
;
442 domain
->last_seq_check
= last_check
;
444 /* have we expired? */
446 time_diff
= now
- domain
->last_seq_check
;
447 if ( time_diff
> lp_winbind_cache_time() ) {
448 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
449 domain
->name
, domain
->sequence_number
,
450 (uint32
)domain
->last_seq_check
));
451 return NT_STATUS_UNSUCCESSFUL
;
454 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
455 domain
->name
, domain
->sequence_number
,
456 (uint32
)domain
->last_seq_check
));
461 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
462 time_t last_seq_check
)
468 if (wcache
->tdb
== NULL
) {
469 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
473 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
474 if (key_str
== NULL
) {
475 DEBUG(10, ("talloc_asprintf failed\n"));
479 SIVAL(buf
, 0, seqnum
);
480 SIVAL(buf
, 4, last_seq_check
);
482 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
483 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
484 TALLOC_FREE(key_str
);
486 DEBUG(10, ("tdb_store_bystring failed: %s\n",
487 tdb_errorstr(wcache
->tdb
)));
488 TALLOC_FREE(key_str
);
492 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
493 domain_name
, seqnum
, (unsigned)last_seq_check
));
498 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
500 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
501 domain
->last_seq_check
);
505 refresh the domain sequence number. If force is true
506 then always refresh it, no matter how recently we fetched it
509 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
513 time_t t
= time(NULL
);
514 unsigned cache_time
= lp_winbind_cache_time();
516 if ( IS_DOMAIN_OFFLINE(domain
) ) {
522 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
523 /* trying to reconnect is expensive, don't do it too often */
524 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
529 time_diff
= t
- domain
->last_seq_check
;
531 /* see if we have to refetch the domain sequence number */
532 if (!force
&& (time_diff
< cache_time
) &&
533 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
534 NT_STATUS_IS_OK(domain
->last_status
)) {
535 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
539 /* try to get the sequence number from the tdb cache first */
540 /* this will update the timestamp as well */
542 status
= fetch_cache_seqnum( domain
, t
);
543 if (NT_STATUS_IS_OK(status
) &&
544 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
545 NT_STATUS_IS_OK(domain
->last_status
)) {
549 /* important! make sure that we know if this is a native
550 mode domain or not. And that we can contact it. */
552 if ( winbindd_can_contact_domain( domain
) ) {
553 status
= domain
->backend
->sequence_number(domain
,
554 &domain
->sequence_number
);
556 /* just use the current time */
557 status
= NT_STATUS_OK
;
558 domain
->sequence_number
= time(NULL
);
562 /* the above call could have set our domain->backend to NULL when
563 * coming from offline to online mode, make sure to reinitialize the
564 * backend - Guenther */
567 if (!NT_STATUS_IS_OK(status
)) {
568 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
569 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
572 domain
->last_status
= status
;
573 domain
->last_seq_check
= time(NULL
);
575 /* save the new sequence number in the cache */
576 store_cache_seqnum( domain
);
579 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
580 domain
->name
, domain
->sequence_number
));
586 decide if a cache entry has expired
588 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
590 /* If we've been told to be offline - stay in that state... */
591 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
592 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
593 keystr
, domain
->name
));
597 /* when the domain is offline return the cached entry.
598 * This deals with transient offline states... */
600 if (!domain
->online
) {
601 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
602 keystr
, domain
->name
));
606 /* if the server is OK and our cache entry came from when it was down then
607 the entry is invalid */
608 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
609 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
610 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
611 keystr
, domain
->name
));
615 /* if the server is down or the cache entry is not older than the
616 current sequence number then it is OK */
617 if (wcache_server_down(domain
) ||
618 centry
->sequence_number
== domain
->sequence_number
) {
619 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
620 keystr
, domain
->name
));
624 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
625 keystr
, domain
->name
));
631 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
634 struct cache_entry
*centry
;
637 key
= string_tdb_data(kstr
);
638 data
= tdb_fetch(wcache
->tdb
, key
);
644 centry
= SMB_XMALLOC_P(struct cache_entry
);
645 centry
->data
= (unsigned char *)data
.dptr
;
646 centry
->len
= data
.dsize
;
649 if (centry
->len
< 8) {
650 /* huh? corrupt cache? */
651 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
656 centry
->status
= centry_ntstatus(centry
);
657 centry
->sequence_number
= centry_uint32(centry
);
663 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
664 number and return status
666 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
667 struct winbindd_domain
*domain
,
668 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
669 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
670 struct winbindd_domain
*domain
,
671 const char *format
, ...)
675 struct cache_entry
*centry
;
677 if (!winbindd_use_cache()) {
681 refresh_sequence_number(domain
, false);
683 va_start(ap
, format
);
684 smb_xvasprintf(&kstr
, format
, ap
);
687 centry
= wcache_fetch_raw(kstr
);
688 if (centry
== NULL
) {
693 if (centry_expired(domain
, kstr
, centry
)) {
695 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
696 kstr
, domain
->name
));
703 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
704 kstr
, domain
->name
));
710 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
711 static void wcache_delete(const char *format
, ...)
717 va_start(ap
, format
);
718 smb_xvasprintf(&kstr
, format
, ap
);
721 key
= string_tdb_data(kstr
);
723 tdb_delete(wcache
->tdb
, key
);
728 make sure we have at least len bytes available in a centry
730 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
732 if (centry
->len
- centry
->ofs
>= len
)
735 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
738 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
739 smb_panic_fn("out of memory in centry_expand");
744 push a uint32 into a centry
746 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
748 centry_expand(centry
, 4);
749 SIVAL(centry
->data
, centry
->ofs
, v
);
754 push a uint16 into a centry
756 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
758 centry_expand(centry
, 2);
759 SIVAL(centry
->data
, centry
->ofs
, v
);
764 push a uint8 into a centry
766 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
768 centry_expand(centry
, 1);
769 SCVAL(centry
->data
, centry
->ofs
, v
);
774 push a string into a centry
776 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
781 /* null strings are marked as len 0xFFFF */
782 centry_put_uint8(centry
, 0xFF);
787 /* can't handle more than 254 char strings. Truncating is probably best */
789 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
792 centry_put_uint8(centry
, len
);
793 centry_expand(centry
, len
);
794 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
799 push a 16 byte hash into a centry - treat as 16 byte string.
801 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
803 centry_put_uint8(centry
, 16);
804 centry_expand(centry
, 16);
805 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
809 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
812 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
817 put NTSTATUS into a centry
819 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
821 uint32 status_value
= NT_STATUS_V(status
);
822 centry_put_uint32(centry
, status_value
);
827 push a NTTIME into a centry
829 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
831 centry_expand(centry
, 8);
832 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
834 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
839 push a time_t into a centry - use a 64 bit size.
840 NTTIME here is being used as a convenient 64-bit size.
842 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
844 NTTIME nt
= (NTTIME
)t
;
845 centry_put_nttime(centry
, nt
);
849 start a centry for output. When finished, call centry_end()
851 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
853 struct cache_entry
*centry
;
858 centry
= SMB_XMALLOC_P(struct cache_entry
);
860 centry
->len
= 8192; /* reasonable default */
861 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
863 centry
->sequence_number
= domain
->sequence_number
;
864 centry_put_ntstatus(centry
, status
);
865 centry_put_uint32(centry
, centry
->sequence_number
);
870 finish a centry and write it to the tdb
872 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
873 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
879 if (!winbindd_use_cache()) {
883 va_start(ap
, format
);
884 smb_xvasprintf(&kstr
, format
, ap
);
887 key
= string_tdb_data(kstr
);
888 data
.dptr
= centry
->data
;
889 data
.dsize
= centry
->ofs
;
891 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
895 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
896 NTSTATUS status
, const char *domain_name
,
897 const char *name
, const DOM_SID
*sid
,
898 enum lsa_SidType type
)
900 struct cache_entry
*centry
;
903 centry
= centry_start(domain
, status
);
906 centry_put_uint32(centry
, type
);
907 centry_put_sid(centry
, sid
);
908 fstrcpy(uname
, name
);
910 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
911 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
912 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
916 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
917 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
919 struct cache_entry
*centry
;
922 centry
= centry_start(domain
, status
);
926 if (NT_STATUS_IS_OK(status
)) {
927 centry_put_uint32(centry
, type
);
928 centry_put_string(centry
, domain_name
);
929 centry_put_string(centry
, name
);
932 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
933 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
934 name
, nt_errstr(status
)));
939 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
940 struct wbint_userinfo
*info
)
942 struct cache_entry
*centry
;
945 if (is_null_sid(&info
->user_sid
)) {
949 centry
= centry_start(domain
, status
);
952 centry_put_string(centry
, info
->acct_name
);
953 centry_put_string(centry
, info
->full_name
);
954 centry_put_string(centry
, info
->homedir
);
955 centry_put_string(centry
, info
->shell
);
956 centry_put_uint32(centry
, info
->primary_gid
);
957 centry_put_sid(centry
, &info
->user_sid
);
958 centry_put_sid(centry
, &info
->group_sid
);
959 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
961 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
965 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
967 struct samr_DomInfo12
*lockout_policy
)
969 struct cache_entry
*centry
;
971 centry
= centry_start(domain
, status
);
975 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
976 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
977 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
979 centry_end(centry
, "LOC_POL/%s", domain
->name
);
981 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
988 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
990 struct samr_DomInfo1
*policy
)
992 struct cache_entry
*centry
;
994 centry
= centry_start(domain
, status
);
998 centry_put_uint16(centry
, policy
->min_password_length
);
999 centry_put_uint16(centry
, policy
->password_history_length
);
1000 centry_put_uint32(centry
, policy
->password_properties
);
1001 centry_put_nttime(centry
, policy
->max_password_age
);
1002 centry_put_nttime(centry
, policy
->min_password_age
);
1004 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1006 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1008 centry_free(centry
);
1011 /***************************************************************************
1012 ***************************************************************************/
1014 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1016 const char *name
, const char *alias
)
1018 struct cache_entry
*centry
;
1021 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1024 centry_put_string( centry
, alias
);
1026 fstrcpy(uname
, name
);
1028 centry_end(centry
, "NSS/NA/%s", uname
);
1030 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1032 centry_free(centry
);
1035 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1037 const char *alias
, const char *name
)
1039 struct cache_entry
*centry
;
1042 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1045 centry_put_string( centry
, name
);
1047 fstrcpy(uname
, alias
);
1049 centry_end(centry
, "NSS/AN/%s", uname
);
1051 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1053 centry_free(centry
);
1056 /***************************************************************************
1057 ***************************************************************************/
1059 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1060 struct winbindd_domain
*domain
,
1061 const char *name
, char **alias
)
1063 struct winbind_cache
*cache
= get_cache(domain
);
1064 struct cache_entry
*centry
= NULL
;
1068 if ( domain
->internal
)
1069 return NT_STATUS_NOT_SUPPORTED
;
1074 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1075 return NT_STATUS_NO_MEMORY
;
1076 strupper_m(upper_name
);
1078 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1080 SAFE_FREE( upper_name
);
1085 status
= centry
->status
;
1087 if (!NT_STATUS_IS_OK(status
)) {
1088 centry_free(centry
);
1092 *alias
= centry_string( centry
, mem_ctx
);
1094 centry_free(centry
);
1096 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1097 name
, *alias
? *alias
: "(none)"));
1099 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1103 /* If its not in cache and we are offline, then fail */
1105 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1106 DEBUG(8,("resolve_username_to_alias: rejecting query "
1107 "in offline mode\n"));
1108 return NT_STATUS_NOT_FOUND
;
1111 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1113 if ( NT_STATUS_IS_OK( status
) ) {
1114 wcache_save_username_alias(domain
, status
, name
, *alias
);
1117 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1118 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1121 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1122 nt_errstr(status
)));
1124 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1125 set_domain_offline( domain
);
1131 /***************************************************************************
1132 ***************************************************************************/
1134 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1135 struct winbindd_domain
*domain
,
1136 const char *alias
, char **name
)
1138 struct winbind_cache
*cache
= get_cache(domain
);
1139 struct cache_entry
*centry
= NULL
;
1143 if ( domain
->internal
)
1144 return NT_STATUS_NOT_SUPPORTED
;
1149 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1150 return NT_STATUS_NO_MEMORY
;
1151 strupper_m(upper_name
);
1153 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1155 SAFE_FREE( upper_name
);
1160 status
= centry
->status
;
1162 if (!NT_STATUS_IS_OK(status
)) {
1163 centry_free(centry
);
1167 *name
= centry_string( centry
, mem_ctx
);
1169 centry_free(centry
);
1171 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1172 alias
, *name
? *name
: "(none)"));
1174 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1178 /* If its not in cache and we are offline, then fail */
1180 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1181 DEBUG(8,("resolve_alias_to_username: rejecting query "
1182 "in offline mode\n"));
1183 return NT_STATUS_NOT_FOUND
;
1186 /* an alias cannot contain a domain prefix or '@' */
1188 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1189 DEBUG(10,("resolve_alias_to_username: skipping fully "
1190 "qualified name %s\n", alias
));
1191 return NT_STATUS_OBJECT_NAME_INVALID
;
1194 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1196 if ( NT_STATUS_IS_OK( status
) ) {
1197 wcache_save_alias_username( domain
, status
, alias
, *name
);
1200 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1201 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1204 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1205 nt_errstr(status
)));
1207 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1208 set_domain_offline( domain
);
1214 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
1216 struct winbind_cache
*cache
= get_cache(domain
);
1218 fstring key_str
, tmp
;
1222 return NT_STATUS_INTERNAL_DB_ERROR
;
1225 if (is_null_sid(sid
)) {
1226 return NT_STATUS_INVALID_SID
;
1229 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1230 return NT_STATUS_INVALID_SID
;
1233 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1235 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1237 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1240 SAFE_FREE(data
.dptr
);
1241 return NT_STATUS_OK
;
1244 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1245 as new salted ones. */
1247 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1248 TALLOC_CTX
*mem_ctx
,
1250 const uint8
**cached_nt_pass
,
1251 const uint8
**cached_salt
)
1253 struct winbind_cache
*cache
= get_cache(domain
);
1254 struct cache_entry
*centry
= NULL
;
1261 return NT_STATUS_INTERNAL_DB_ERROR
;
1264 if (is_null_sid(sid
)) {
1265 return NT_STATUS_INVALID_SID
;
1268 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1269 return NT_STATUS_INVALID_SID
;
1272 /* Try and get a salted cred first. If we can't
1273 fall back to an unsalted cred. */
1275 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1276 sid_to_fstring(tmp
, sid
));
1278 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1279 sid_string_dbg(sid
)));
1280 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1283 t
= centry_time(centry
);
1285 /* In the salted case this isn't actually the nt_hash itself,
1286 but the MD5 of the salt + nt_hash. Let the caller
1287 sort this out. It can tell as we only return the cached_salt
1288 if we are returning a salted cred. */
1290 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1291 if (*cached_nt_pass
== NULL
) {
1294 sid_to_fstring(sidstr
, sid
);
1296 /* Bad (old) cred cache. Delete and pretend we
1298 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1300 wcache_delete("CRED/%s", sidstr
);
1301 centry_free(centry
);
1302 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1305 /* We only have 17 bytes more data in the salted cred case. */
1306 if (centry
->len
- centry
->ofs
== 17) {
1307 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1309 *cached_salt
= NULL
;
1312 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1314 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1317 status
= centry
->status
;
1319 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1320 sid_string_dbg(sid
), nt_errstr(status
) ));
1322 centry_free(centry
);
1326 /* Store creds for a SID - only writes out new salted ones. */
1328 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1329 TALLOC_CTX
*mem_ctx
,
1331 const uint8 nt_pass
[NT_HASH_LEN
])
1333 struct cache_entry
*centry
;
1336 uint8 cred_salt
[NT_HASH_LEN
];
1337 uint8 salted_hash
[NT_HASH_LEN
];
1339 if (is_null_sid(sid
)) {
1340 return NT_STATUS_INVALID_SID
;
1343 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1344 return NT_STATUS_INVALID_SID
;
1347 centry
= centry_start(domain
, NT_STATUS_OK
);
1349 return NT_STATUS_INTERNAL_DB_ERROR
;
1352 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1354 centry_put_time(centry
, time(NULL
));
1356 /* Create a salt and then salt the hash. */
1357 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1358 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1360 centry_put_hash16(centry
, salted_hash
);
1361 centry_put_hash16(centry
, cred_salt
);
1362 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1364 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1366 centry_free(centry
);
1368 return NT_STATUS_OK
;
1372 /* Query display info. This is the basic user list fn */
1373 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1374 TALLOC_CTX
*mem_ctx
,
1375 uint32
*num_entries
,
1376 struct wbint_userinfo
**info
)
1378 struct winbind_cache
*cache
= get_cache(domain
);
1379 struct cache_entry
*centry
= NULL
;
1381 unsigned int i
, retry
;
1386 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1390 *num_entries
= centry_uint32(centry
);
1392 if (*num_entries
== 0)
1395 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1397 smb_panic_fn("query_user_list out of memory");
1399 for (i
=0; i
<(*num_entries
); i
++) {
1400 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1401 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1402 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1403 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1404 centry_sid(centry
, &(*info
)[i
].user_sid
);
1405 centry_sid(centry
, &(*info
)[i
].group_sid
);
1409 status
= centry
->status
;
1411 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1412 domain
->name
, nt_errstr(status
) ));
1414 centry_free(centry
);
1421 /* Return status value returned by seq number check */
1423 if (!NT_STATUS_IS_OK(domain
->last_status
))
1424 return domain
->last_status
;
1426 /* Put the query_user_list() in a retry loop. There appears to be
1427 * some bug either with Windows 2000 or Samba's handling of large
1428 * rpc replies. This manifests itself as sudden disconnection
1429 * at a random point in the enumeration of a large (60k) user list.
1430 * The retry loop simply tries the operation again. )-: It's not
1431 * pretty but an acceptable workaround until we work out what the
1432 * real problem is. */
1437 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1440 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1441 if (!NT_STATUS_IS_OK(status
)) {
1442 DEBUG(3, ("query_user_list: returned 0x%08x, "
1443 "retrying\n", NT_STATUS_V(status
)));
1445 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1446 DEBUG(3, ("query_user_list: flushing "
1447 "connection cache\n"));
1448 invalidate_cm_connection(&domain
->conn
);
1451 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1455 refresh_sequence_number(domain
, false);
1456 centry
= centry_start(domain
, status
);
1459 centry_put_uint32(centry
, *num_entries
);
1460 for (i
=0; i
<(*num_entries
); i
++) {
1461 centry_put_string(centry
, (*info
)[i
].acct_name
);
1462 centry_put_string(centry
, (*info
)[i
].full_name
);
1463 centry_put_string(centry
, (*info
)[i
].homedir
);
1464 centry_put_string(centry
, (*info
)[i
].shell
);
1465 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1466 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1467 if (domain
->backend
&& domain
->backend
->consistent
) {
1468 /* when the backend is consistent we can pre-prime some mappings */
1469 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1471 (*info
)[i
].acct_name
,
1472 &(*info
)[i
].user_sid
,
1474 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1475 &(*info
)[i
].user_sid
,
1477 (*info
)[i
].acct_name
,
1479 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1482 centry_end(centry
, "UL/%s", domain
->name
);
1483 centry_free(centry
);
1489 /* list all domain groups */
1490 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1491 TALLOC_CTX
*mem_ctx
,
1492 uint32
*num_entries
,
1493 struct acct_info
**info
)
1495 struct winbind_cache
*cache
= get_cache(domain
);
1496 struct cache_entry
*centry
= NULL
;
1503 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1507 *num_entries
= centry_uint32(centry
);
1509 if (*num_entries
== 0)
1512 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1514 smb_panic_fn("enum_dom_groups out of memory");
1516 for (i
=0; i
<(*num_entries
); i
++) {
1517 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1518 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1519 (*info
)[i
].rid
= centry_uint32(centry
);
1523 status
= centry
->status
;
1525 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1526 domain
->name
, nt_errstr(status
) ));
1528 centry_free(centry
);
1535 /* Return status value returned by seq number check */
1537 if (!NT_STATUS_IS_OK(domain
->last_status
))
1538 return domain
->last_status
;
1540 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1543 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1546 refresh_sequence_number(domain
, false);
1547 centry
= centry_start(domain
, status
);
1550 centry_put_uint32(centry
, *num_entries
);
1551 for (i
=0; i
<(*num_entries
); i
++) {
1552 centry_put_string(centry
, (*info
)[i
].acct_name
);
1553 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1554 centry_put_uint32(centry
, (*info
)[i
].rid
);
1556 centry_end(centry
, "GL/%s/domain", domain
->name
);
1557 centry_free(centry
);
1563 /* list all domain groups */
1564 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1565 TALLOC_CTX
*mem_ctx
,
1566 uint32
*num_entries
,
1567 struct acct_info
**info
)
1569 struct winbind_cache
*cache
= get_cache(domain
);
1570 struct cache_entry
*centry
= NULL
;
1577 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1581 *num_entries
= centry_uint32(centry
);
1583 if (*num_entries
== 0)
1586 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1588 smb_panic_fn("enum_dom_groups out of memory");
1590 for (i
=0; i
<(*num_entries
); i
++) {
1591 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1592 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1593 (*info
)[i
].rid
= centry_uint32(centry
);
1598 /* If we are returning cached data and the domain controller
1599 is down then we don't know whether the data is up to date
1600 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1603 if (wcache_server_down(domain
)) {
1604 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1605 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1607 status
= centry
->status
;
1609 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1610 domain
->name
, nt_errstr(status
) ));
1612 centry_free(centry
);
1619 /* Return status value returned by seq number check */
1621 if (!NT_STATUS_IS_OK(domain
->last_status
))
1622 return domain
->last_status
;
1624 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1627 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1630 refresh_sequence_number(domain
, false);
1631 centry
= centry_start(domain
, status
);
1634 centry_put_uint32(centry
, *num_entries
);
1635 for (i
=0; i
<(*num_entries
); i
++) {
1636 centry_put_string(centry
, (*info
)[i
].acct_name
);
1637 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1638 centry_put_uint32(centry
, (*info
)[i
].rid
);
1640 centry_end(centry
, "GL/%s/local", domain
->name
);
1641 centry_free(centry
);
1647 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1648 const char *domain_name
,
1650 struct dom_sid
*sid
,
1651 enum lsa_SidType
*type
)
1653 struct winbind_cache
*cache
= get_cache(domain
);
1654 struct cache_entry
*centry
;
1658 if (cache
->tdb
== NULL
) {
1659 return NT_STATUS_NOT_FOUND
;
1662 uname
= talloc_strdup_upper(talloc_tos(), name
);
1663 if (uname
== NULL
) {
1664 return NT_STATUS_NO_MEMORY
;
1667 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1669 if (centry
== NULL
) {
1670 return NT_STATUS_NOT_FOUND
;
1673 status
= centry
->status
;
1674 if (NT_STATUS_IS_OK(status
)) {
1675 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1676 centry_sid(centry
, sid
);
1679 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1680 "%s\n", domain
->name
, nt_errstr(status
) ));
1682 centry_free(centry
);
1686 /* convert a single name to a sid in a domain */
1687 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1688 TALLOC_CTX
*mem_ctx
,
1689 const char *domain_name
,
1693 enum lsa_SidType
*type
)
1697 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1698 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1704 /* If the seq number check indicated that there is a problem
1705 * with this DC, then return that status... except for
1706 * access_denied. This is special because the dc may be in
1707 * "restrict anonymous = 1" mode, in which case it will deny
1708 * most unauthenticated operations, but *will* allow the LSA
1709 * name-to-sid that we try as a fallback. */
1711 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1712 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1713 return domain
->last_status
;
1715 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1718 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1719 name
, flags
, sid
, type
);
1722 refresh_sequence_number(domain
, false);
1724 if (domain
->online
&&
1725 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1726 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1728 /* Only save the reverse mapping if this was not a UPN */
1729 if (!strchr(name
, '@')) {
1730 strupper_m(CONST_DISCARD(char *,domain_name
));
1731 strlower_m(CONST_DISCARD(char *,name
));
1732 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1739 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1740 const struct dom_sid
*sid
,
1741 TALLOC_CTX
*mem_ctx
,
1744 enum lsa_SidType
*type
)
1746 struct winbind_cache
*cache
= get_cache(domain
);
1747 struct cache_entry
*centry
;
1751 if (cache
->tdb
== NULL
) {
1752 return NT_STATUS_NOT_FOUND
;
1755 sid_string
= sid_string_tos(sid
);
1756 if (sid_string
== NULL
) {
1757 return NT_STATUS_NO_MEMORY
;
1760 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1761 TALLOC_FREE(sid_string
);
1762 if (centry
== NULL
) {
1763 return NT_STATUS_NOT_FOUND
;
1766 if (NT_STATUS_IS_OK(centry
->status
)) {
1767 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1768 *domain_name
= centry_string(centry
, mem_ctx
);
1769 *name
= centry_string(centry
, mem_ctx
);
1772 status
= centry
->status
;
1773 centry_free(centry
);
1775 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1776 "%s\n", domain
->name
, nt_errstr(status
) ));
1781 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1783 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1784 TALLOC_CTX
*mem_ctx
,
1788 enum lsa_SidType
*type
)
1792 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1794 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1799 *domain_name
= NULL
;
1801 /* If the seq number check indicated that there is a problem
1802 * with this DC, then return that status... except for
1803 * access_denied. This is special because the dc may be in
1804 * "restrict anonymous = 1" mode, in which case it will deny
1805 * most unauthenticated operations, but *will* allow the LSA
1806 * sid-to-name that we try as a fallback. */
1808 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1809 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1810 return domain
->last_status
;
1812 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1815 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1818 refresh_sequence_number(domain
, false);
1819 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1821 /* We can't save the name to sid mapping here, as with sid history a
1822 * later name2sid would give the wrong sid. */
1827 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1828 TALLOC_CTX
*mem_ctx
,
1829 const DOM_SID
*domain_sid
,
1834 enum lsa_SidType
**types
)
1836 struct winbind_cache
*cache
= get_cache(domain
);
1838 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1842 *domain_name
= NULL
;
1850 if (num_rids
== 0) {
1851 return NT_STATUS_OK
;
1854 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1855 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1857 if ((*names
== NULL
) || (*types
== NULL
)) {
1858 result
= NT_STATUS_NO_MEMORY
;
1862 have_mapped
= have_unmapped
= false;
1864 for (i
=0; i
<num_rids
; i
++) {
1866 struct cache_entry
*centry
;
1869 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1870 result
= NT_STATUS_INTERNAL_ERROR
;
1874 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1875 sid_to_fstring(tmp
, &sid
));
1880 (*types
)[i
] = SID_NAME_UNKNOWN
;
1881 (*names
)[i
] = talloc_strdup(*names
, "");
1883 if (NT_STATUS_IS_OK(centry
->status
)) {
1886 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1888 dom
= centry_string(centry
, mem_ctx
);
1889 if (*domain_name
== NULL
) {
1895 (*names
)[i
] = centry_string(centry
, *names
);
1897 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
1898 have_unmapped
= true;
1901 /* something's definitely wrong */
1902 result
= centry
->status
;
1906 centry_free(centry
);
1910 return NT_STATUS_NONE_MAPPED
;
1912 if (!have_unmapped
) {
1913 return NT_STATUS_OK
;
1915 return STATUS_SOME_UNMAPPED
;
1919 TALLOC_FREE(*names
);
1920 TALLOC_FREE(*types
);
1922 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1923 rids
, num_rids
, domain_name
,
1927 None of the queried rids has been found so save all negative entries
1929 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
1930 for (i
= 0; i
< num_rids
; i
++) {
1932 const char *name
= "";
1933 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
1934 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
1936 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1937 return NT_STATUS_INTERNAL_ERROR
;
1940 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1948 Some or all of the queried rids have been found.
1950 if (!NT_STATUS_IS_OK(result
) &&
1951 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1955 refresh_sequence_number(domain
, false);
1957 for (i
=0; i
<num_rids
; i
++) {
1961 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1962 result
= NT_STATUS_INTERNAL_ERROR
;
1966 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1967 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1969 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1970 (*names
)[i
], (*types
)[i
]);
1976 TALLOC_FREE(*names
);
1977 TALLOC_FREE(*types
);
1981 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
1982 TALLOC_CTX
*mem_ctx
,
1983 const struct dom_sid
*user_sid
,
1984 struct wbint_userinfo
*info
)
1986 struct winbind_cache
*cache
= get_cache(domain
);
1987 struct cache_entry
*centry
= NULL
;
1991 if (cache
->tdb
== NULL
) {
1992 return NT_STATUS_NOT_FOUND
;
1995 sid_string
= sid_string_tos(user_sid
);
1996 if (sid_string
== NULL
) {
1997 return NT_STATUS_NO_MEMORY
;
2000 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2001 TALLOC_FREE(sid_string
);
2002 if (centry
== NULL
) {
2003 return NT_STATUS_NOT_FOUND
;
2007 * If we have an access denied cache entry and a cached info3
2008 * in the samlogon cache then do a query. This will force the
2009 * rpc back end to return the info3 data.
2012 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2013 netsamlogon_cache_have(user_sid
)) {
2014 DEBUG(10, ("query_user: cached access denied and have cached "
2016 domain
->last_status
= NT_STATUS_OK
;
2017 centry_free(centry
);
2018 return NT_STATUS_NOT_FOUND
;
2021 /* if status is not ok then this is a negative hit
2022 and the rest of the data doesn't matter */
2023 status
= centry
->status
;
2024 if (NT_STATUS_IS_OK(status
)) {
2025 info
->acct_name
= centry_string(centry
, mem_ctx
);
2026 info
->full_name
= centry_string(centry
, mem_ctx
);
2027 info
->homedir
= centry_string(centry
, mem_ctx
);
2028 info
->shell
= centry_string(centry
, mem_ctx
);
2029 info
->primary_gid
= centry_uint32(centry
);
2030 centry_sid(centry
, &info
->user_sid
);
2031 centry_sid(centry
, &info
->group_sid
);
2034 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2035 "%s\n", domain
->name
, nt_errstr(status
) ));
2037 centry_free(centry
);
2041 /* Lookup user information from a rid */
2042 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2043 TALLOC_CTX
*mem_ctx
,
2044 const DOM_SID
*user_sid
,
2045 struct wbint_userinfo
*info
)
2049 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2050 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2056 /* Return status value returned by seq number check */
2058 if (!NT_STATUS_IS_OK(domain
->last_status
))
2059 return domain
->last_status
;
2061 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2064 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2067 refresh_sequence_number(domain
, false);
2068 wcache_save_user(domain
, status
, info
);
2073 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2074 TALLOC_CTX
*mem_ctx
,
2075 const struct dom_sid
*user_sid
,
2076 uint32_t *pnum_sids
,
2077 struct dom_sid
**psids
)
2079 struct winbind_cache
*cache
= get_cache(domain
);
2080 struct cache_entry
*centry
= NULL
;
2082 uint32_t i
, num_sids
;
2083 struct dom_sid
*sids
;
2086 if (cache
->tdb
== NULL
) {
2087 return NT_STATUS_NOT_FOUND
;
2090 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2091 sid_to_fstring(sid_string
, user_sid
));
2092 if (centry
== NULL
) {
2093 return NT_STATUS_NOT_FOUND
;
2096 /* If we have an access denied cache entry and a cached info3 in the
2097 samlogon cache then do a query. This will force the rpc back end
2098 to return the info3 data. */
2100 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2101 && netsamlogon_cache_have(user_sid
)) {
2102 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2104 domain
->last_status
= NT_STATUS_OK
;
2105 centry_free(centry
);
2106 return NT_STATUS_NOT_FOUND
;
2109 num_sids
= centry_uint32(centry
);
2110 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2112 return NT_STATUS_NO_MEMORY
;
2115 for (i
=0; i
<num_sids
; i
++) {
2116 centry_sid(centry
, &sids
[i
]);
2119 status
= centry
->status
;
2121 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2122 "status: %s\n", domain
->name
, nt_errstr(status
)));
2124 centry_free(centry
);
2126 *pnum_sids
= num_sids
;
2131 /* Lookup groups a user is a member of. */
2132 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2133 TALLOC_CTX
*mem_ctx
,
2134 const DOM_SID
*user_sid
,
2135 uint32
*num_groups
, DOM_SID
**user_gids
)
2137 struct cache_entry
*centry
= NULL
;
2142 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2143 num_groups
, user_gids
);
2144 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2149 (*user_gids
) = NULL
;
2151 /* Return status value returned by seq number check */
2153 if (!NT_STATUS_IS_OK(domain
->last_status
))
2154 return domain
->last_status
;
2156 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2159 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2161 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2165 refresh_sequence_number(domain
, false);
2166 centry
= centry_start(domain
, status
);
2170 centry_put_uint32(centry
, *num_groups
);
2171 for (i
=0; i
<(*num_groups
); i
++) {
2172 centry_put_sid(centry
, &(*user_gids
)[i
]);
2175 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2176 centry_free(centry
);
2182 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2183 const struct dom_sid
*sids
)
2188 sidlist
= talloc_strdup(mem_ctx
, "");
2189 if (sidlist
== NULL
) {
2192 for (i
=0; i
<num_sids
; i
++) {
2194 sidlist
= talloc_asprintf_append_buffer(
2195 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2196 if (sidlist
== NULL
) {
2203 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2204 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2205 const struct dom_sid
*sids
,
2206 uint32_t *pnum_aliases
, uint32_t **paliases
)
2208 struct winbind_cache
*cache
= get_cache(domain
);
2209 struct cache_entry
*centry
= NULL
;
2210 uint32_t num_aliases
;
2216 if (cache
->tdb
== NULL
) {
2217 return NT_STATUS_NOT_FOUND
;
2220 if (num_sids
== 0) {
2223 return NT_STATUS_OK
;
2226 /* We need to cache indexed by the whole list of SIDs, the aliases
2227 * resulting might come from any of the SIDs. */
2229 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2230 if (sidlist
== NULL
) {
2231 return NT_STATUS_NO_MEMORY
;
2234 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2235 TALLOC_FREE(sidlist
);
2236 if (centry
== NULL
) {
2237 return NT_STATUS_NOT_FOUND
;
2240 num_aliases
= centry_uint32(centry
);
2241 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2242 if (aliases
== NULL
) {
2243 centry_free(centry
);
2244 return NT_STATUS_NO_MEMORY
;
2247 for (i
=0; i
<num_aliases
; i
++) {
2248 aliases
[i
] = centry_uint32(centry
);
2251 status
= centry
->status
;
2253 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2254 "status %s\n", domain
->name
, nt_errstr(status
)));
2256 centry_free(centry
);
2258 *pnum_aliases
= num_aliases
;
2259 *paliases
= aliases
;
2264 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2265 TALLOC_CTX
*mem_ctx
,
2266 uint32 num_sids
, const DOM_SID
*sids
,
2267 uint32
*num_aliases
, uint32
**alias_rids
)
2269 struct cache_entry
*centry
= NULL
;
2274 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2275 num_aliases
, alias_rids
);
2276 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2281 (*alias_rids
) = NULL
;
2283 if (!NT_STATUS_IS_OK(domain
->last_status
))
2284 return domain
->last_status
;
2286 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2287 "for domain %s\n", domain
->name
));
2289 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2290 if (sidlist
== NULL
) {
2291 return NT_STATUS_NO_MEMORY
;
2294 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2296 num_aliases
, alias_rids
);
2299 refresh_sequence_number(domain
, false);
2300 centry
= centry_start(domain
, status
);
2303 centry_put_uint32(centry
, *num_aliases
);
2304 for (i
=0; i
<(*num_aliases
); i
++)
2305 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2306 centry_end(centry
, "UA%s", sidlist
);
2307 centry_free(centry
);
2313 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2314 TALLOC_CTX
*mem_ctx
,
2315 const struct dom_sid
*group_sid
,
2316 uint32_t *num_names
,
2317 struct dom_sid
**sid_mem
, char ***names
,
2318 uint32_t **name_types
)
2320 struct winbind_cache
*cache
= get_cache(domain
);
2321 struct cache_entry
*centry
= NULL
;
2326 if (cache
->tdb
== NULL
) {
2327 return NT_STATUS_NOT_FOUND
;
2330 sid_string
= sid_string_tos(group_sid
);
2331 if (sid_string
== NULL
) {
2332 return NT_STATUS_NO_MEMORY
;
2335 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2336 TALLOC_FREE(sid_string
);
2337 if (centry
== NULL
) {
2338 return NT_STATUS_NOT_FOUND
;
2345 *num_names
= centry_uint32(centry
);
2346 if (*num_names
== 0) {
2347 centry_free(centry
);
2348 return NT_STATUS_OK
;
2351 *sid_mem
= talloc_array(mem_ctx
, DOM_SID
, *num_names
);
2352 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2353 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2355 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2356 TALLOC_FREE(*sid_mem
);
2357 TALLOC_FREE(*names
);
2358 TALLOC_FREE(*name_types
);
2359 centry_free(centry
);
2360 return NT_STATUS_NO_MEMORY
;
2363 for (i
=0; i
<(*num_names
); i
++) {
2364 centry_sid(centry
, &(*sid_mem
)[i
]);
2365 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2366 (*name_types
)[i
] = centry_uint32(centry
);
2369 status
= centry
->status
;
2371 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2372 "status: %s\n", domain
->name
, nt_errstr(status
)));
2374 centry_free(centry
);
2378 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2379 TALLOC_CTX
*mem_ctx
,
2380 const DOM_SID
*group_sid
, uint32
*num_names
,
2381 DOM_SID
**sid_mem
, char ***names
,
2382 uint32
**name_types
)
2384 struct cache_entry
*centry
= NULL
;
2389 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2390 sid_mem
, names
, name_types
);
2391 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2398 (*name_types
) = NULL
;
2400 /* Return status value returned by seq number check */
2402 if (!NT_STATUS_IS_OK(domain
->last_status
))
2403 return domain
->last_status
;
2405 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2408 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2409 sid_mem
, names
, name_types
);
2412 refresh_sequence_number(domain
, false);
2413 centry
= centry_start(domain
, status
);
2416 centry_put_uint32(centry
, *num_names
);
2417 for (i
=0; i
<(*num_names
); i
++) {
2418 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2419 centry_put_string(centry
, (*names
)[i
]);
2420 centry_put_uint32(centry
, (*name_types
)[i
]);
2422 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2423 centry_free(centry
);
2429 /* find the sequence number for a domain */
2430 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2432 refresh_sequence_number(domain
, false);
2434 *seq
= domain
->sequence_number
;
2436 return NT_STATUS_OK
;
2439 /* enumerate trusted domains
2440 * (we need to have the list of trustdoms in the cache when we go offline) -
2442 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2443 TALLOC_CTX
*mem_ctx
,
2444 uint32
*num_domains
,
2449 struct winbind_cache
*cache
= get_cache(domain
);
2450 struct cache_entry
*centry
= NULL
;
2457 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
2463 *num_domains
= centry_uint32(centry
);
2466 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2467 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2468 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
2470 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
2471 smb_panic_fn("trusted_domains out of memory");
2475 (*alt_names
) = NULL
;
2479 for (i
=0; i
<(*num_domains
); i
++) {
2480 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2481 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
2482 if (!centry_sid(centry
, &(*dom_sids
)[i
])) {
2483 sid_copy(&(*dom_sids
)[i
], &global_sid_NULL
);
2487 status
= centry
->status
;
2489 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2490 domain
->name
, *num_domains
, nt_errstr(status
) ));
2492 centry_free(centry
);
2499 (*alt_names
) = NULL
;
2501 /* Return status value returned by seq number check */
2503 if (!NT_STATUS_IS_OK(domain
->last_status
))
2504 return domain
->last_status
;
2506 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2509 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2510 names
, alt_names
, dom_sids
);
2512 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2513 * so that the generic centry handling still applies correctly -
2516 if (!NT_STATUS_IS_ERR(status
)) {
2517 status
= NT_STATUS_OK
;
2521 #if 0 /* Disabled as we want the trust dom list to be managed by
2522 the main parent and always to make the query. --jerry */
2525 refresh_sequence_number(domain
, false);
2527 centry
= centry_start(domain
, status
);
2531 centry_put_uint32(centry
, *num_domains
);
2533 for (i
=0; i
<(*num_domains
); i
++) {
2534 centry_put_string(centry
, (*names
)[i
]);
2535 centry_put_string(centry
, (*alt_names
)[i
]);
2536 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2539 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2541 centry_free(centry
);
2549 /* get lockout policy */
2550 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2551 TALLOC_CTX
*mem_ctx
,
2552 struct samr_DomInfo12
*policy
)
2554 struct winbind_cache
*cache
= get_cache(domain
);
2555 struct cache_entry
*centry
= NULL
;
2561 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2566 policy
->lockout_duration
= centry_nttime(centry
);
2567 policy
->lockout_window
= centry_nttime(centry
);
2568 policy
->lockout_threshold
= centry_uint16(centry
);
2570 status
= centry
->status
;
2572 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2573 domain
->name
, nt_errstr(status
) ));
2575 centry_free(centry
);
2579 ZERO_STRUCTP(policy
);
2581 /* Return status value returned by seq number check */
2583 if (!NT_STATUS_IS_OK(domain
->last_status
))
2584 return domain
->last_status
;
2586 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2589 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2592 refresh_sequence_number(domain
, false);
2593 wcache_save_lockout_policy(domain
, status
, policy
);
2598 /* get password policy */
2599 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2600 TALLOC_CTX
*mem_ctx
,
2601 struct samr_DomInfo1
*policy
)
2603 struct winbind_cache
*cache
= get_cache(domain
);
2604 struct cache_entry
*centry
= NULL
;
2610 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2615 policy
->min_password_length
= centry_uint16(centry
);
2616 policy
->password_history_length
= centry_uint16(centry
);
2617 policy
->password_properties
= centry_uint32(centry
);
2618 policy
->max_password_age
= centry_nttime(centry
);
2619 policy
->min_password_age
= centry_nttime(centry
);
2621 status
= centry
->status
;
2623 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2624 domain
->name
, nt_errstr(status
) ));
2626 centry_free(centry
);
2630 ZERO_STRUCTP(policy
);
2632 /* Return status value returned by seq number check */
2634 if (!NT_STATUS_IS_OK(domain
->last_status
))
2635 return domain
->last_status
;
2637 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2640 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2643 refresh_sequence_number(domain
, false);
2644 if (NT_STATUS_IS_OK(status
)) {
2645 wcache_save_password_policy(domain
, status
, policy
);
2652 /* Invalidate cached user and group lists coherently */
2654 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2657 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2658 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2659 tdb_delete(the_tdb
, kbuf
);
2664 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2666 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2667 struct netr_SamInfo3
*info3
)
2670 fstring key_str
, sid_string
;
2671 struct winbind_cache
*cache
;
2673 /* dont clear cached U/SID and UG/SID entries when we want to logon
2676 if (lp_winbind_offline_logon()) {
2683 cache
= get_cache(domain
);
2689 sid_copy(&sid
, info3
->base
.domain_sid
);
2690 sid_append_rid(&sid
, info3
->base
.rid
);
2692 /* Clear U/SID cache entry */
2693 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, &sid
));
2694 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2695 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2697 /* Clear UG/SID cache entry */
2698 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, &sid
));
2699 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2700 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2702 /* Samba/winbindd never needs this. */
2703 netsamlogon_clear_cached_user(info3
);
2706 bool wcache_invalidate_cache(void)
2708 struct winbindd_domain
*domain
;
2710 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2711 struct winbind_cache
*cache
= get_cache(domain
);
2713 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2714 "entries for %s\n", domain
->name
));
2717 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2726 bool init_wcache(void)
2728 if (wcache
== NULL
) {
2729 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2730 ZERO_STRUCTP(wcache
);
2733 if (wcache
->tdb
!= NULL
)
2736 /* when working offline we must not clear the cache on restart */
2737 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
2738 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2739 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2740 O_RDWR
|O_CREAT
, 0600);
2742 if (wcache
->tdb
== NULL
) {
2743 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2750 /************************************************************************
2751 This is called by the parent to initialize the cache file.
2752 We don't need sophisticated locking here as we know we're the
2754 ************************************************************************/
2756 bool initialize_winbindd_cache(void)
2758 bool cache_bad
= true;
2761 if (!init_wcache()) {
2762 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2766 /* Check version number. */
2767 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2768 vers
== WINBINDD_CACHE_VERSION
) {
2773 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2774 "and re-creating with version number %d\n",
2775 WINBINDD_CACHE_VERSION
));
2777 tdb_close(wcache
->tdb
);
2780 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2781 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2782 cache_path("winbindd_cache.tdb"),
2786 if (!init_wcache()) {
2787 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2788 "init_wcache failed.\n"));
2792 /* Write the version. */
2793 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2794 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2795 tdb_errorstr(wcache
->tdb
) ));
2800 tdb_close(wcache
->tdb
);
2805 void close_winbindd_cache(void)
2811 tdb_close(wcache
->tdb
);
2816 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2817 char **domain_name
, char **name
,
2818 enum lsa_SidType
*type
)
2820 struct winbindd_domain
*domain
;
2823 domain
= find_lookup_domain_from_sid(sid
);
2824 if (domain
== NULL
) {
2827 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
2829 return NT_STATUS_IS_OK(status
);
2832 bool lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2833 const char *domain_name
,
2836 enum lsa_SidType
*type
)
2838 struct winbindd_domain
*domain
;
2840 bool original_online_state
;
2842 domain
= find_lookup_domain_from_name(domain_name
);
2843 if (domain
== NULL
) {
2847 /* If we are doing a cached logon, temporarily set the domain
2848 offline so the cache won't expire the entry */
2850 original_online_state
= domain
->online
;
2851 domain
->online
= false;
2852 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
2853 domain
->online
= original_online_state
;
2855 return NT_STATUS_IS_OK(status
);
2858 void cache_name2sid(struct winbindd_domain
*domain
,
2859 const char *domain_name
, const char *name
,
2860 enum lsa_SidType type
, const DOM_SID
*sid
)
2862 refresh_sequence_number(domain
, false);
2863 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2868 * The original idea that this cache only contains centries has
2869 * been blurred - now other stuff gets put in here. Ensure we
2870 * ignore these things on cleanup.
2873 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2874 TDB_DATA dbuf
, void *state
)
2876 struct cache_entry
*centry
;
2878 if (is_non_centry_key(kbuf
)) {
2882 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2887 if (!NT_STATUS_IS_OK(centry
->status
)) {
2888 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2889 tdb_delete(the_tdb
, kbuf
);
2892 centry_free(centry
);
2896 /* flush the cache */
2897 void wcache_flush_cache(void)
2902 tdb_close(wcache
->tdb
);
2905 if (!winbindd_use_cache()) {
2909 /* when working offline we must not clear the cache on restart */
2910 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
2911 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2912 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2913 O_RDWR
|O_CREAT
, 0600);
2916 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2920 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2922 DEBUG(10,("wcache_flush_cache success\n"));
2925 /* Count cached creds */
2927 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2930 int *cred_count
= (int*)state
;
2932 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2938 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2940 struct winbind_cache
*cache
= get_cache(domain
);
2945 return NT_STATUS_INTERNAL_DB_ERROR
;
2948 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2950 return NT_STATUS_OK
;
2954 struct cred_list
*prev
, *next
;
2959 static struct cred_list
*wcache_cred_list
;
2961 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2964 struct cred_list
*cred
;
2966 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2968 cred
= SMB_MALLOC_P(struct cred_list
);
2970 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2976 /* save a copy of the key */
2978 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2979 DLIST_ADD(wcache_cred_list
, cred
);
2985 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2987 struct winbind_cache
*cache
= get_cache(domain
);
2990 struct cred_list
*cred
, *oldest
= NULL
;
2993 return NT_STATUS_INTERNAL_DB_ERROR
;
2996 /* we possibly already have an entry */
2997 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2999 fstring key_str
, tmp
;
3001 DEBUG(11,("we already have an entry, deleting that\n"));
3003 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3005 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3007 return NT_STATUS_OK
;
3010 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3012 return NT_STATUS_OK
;
3013 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
3014 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3017 ZERO_STRUCTP(oldest
);
3019 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3024 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3026 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3028 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3032 t
= IVAL(data
.dptr
, 0);
3033 SAFE_FREE(data
.dptr
);
3036 oldest
= SMB_MALLOC_P(struct cred_list
);
3037 if (oldest
== NULL
) {
3038 status
= NT_STATUS_NO_MEMORY
;
3042 fstrcpy(oldest
->name
, cred
->name
);
3043 oldest
->created
= t
;
3047 if (t
< oldest
->created
) {
3048 fstrcpy(oldest
->name
, cred
->name
);
3049 oldest
->created
= t
;
3053 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3054 status
= NT_STATUS_OK
;
3056 status
= NT_STATUS_UNSUCCESSFUL
;
3059 SAFE_FREE(wcache_cred_list
);
3065 /* Change the global online/offline state. */
3066 bool set_global_winbindd_state_offline(void)
3070 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3072 /* Only go offline if someone has created
3073 the key "WINBINDD_OFFLINE" in the cache tdb. */
3075 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3076 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3080 if (!lp_winbind_offline_logon()) {
3081 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3085 if (global_winbindd_offline_state
) {
3086 /* Already offline. */
3090 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3092 if (!data
.dptr
|| data
.dsize
!= 4) {
3093 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3094 SAFE_FREE(data
.dptr
);
3097 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3098 global_winbindd_offline_state
= true;
3099 SAFE_FREE(data
.dptr
);
3104 void set_global_winbindd_state_online(void)
3106 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3108 if (!lp_winbind_offline_logon()) {
3109 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3113 if (!global_winbindd_offline_state
) {
3114 /* Already online. */
3117 global_winbindd_offline_state
= false;
3123 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3124 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3127 bool get_global_winbindd_state_offline(void)
3129 return global_winbindd_offline_state
;
3132 /***********************************************************************
3133 Validate functions for all possible cache tdb keys.
3134 ***********************************************************************/
3136 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3137 struct tdb_validation_status
*state
)
3139 struct cache_entry
*centry
;
3141 centry
= SMB_XMALLOC_P(struct cache_entry
);
3142 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3143 if (!centry
->data
) {
3147 centry
->len
= data
.dsize
;
3150 if (centry
->len
< 8) {
3151 /* huh? corrupt cache? */
3152 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
3153 centry_free(centry
);
3154 state
->bad_entry
= true;
3155 state
->success
= false;
3159 centry
->status
= NT_STATUS(centry_uint32(centry
));
3160 centry
->sequence_number
= centry_uint32(centry
);
3164 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3165 struct tdb_validation_status
*state
)
3167 if (dbuf
.dsize
!= 8) {
3168 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3169 keystr
, (unsigned int)dbuf
.dsize
));
3170 state
->bad_entry
= true;
3176 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3177 struct tdb_validation_status
*state
)
3179 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3184 (void)centry_uint32(centry
);
3185 if (NT_STATUS_IS_OK(centry
->status
)) {
3187 (void)centry_sid(centry
, &sid
);
3190 centry_free(centry
);
3192 if (!(state
->success
)) {
3195 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3199 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3200 struct tdb_validation_status
*state
)
3202 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3207 if (NT_STATUS_IS_OK(centry
->status
)) {
3208 (void)centry_uint32(centry
);
3209 (void)centry_string(centry
, mem_ctx
);
3210 (void)centry_string(centry
, mem_ctx
);
3213 centry_free(centry
);
3215 if (!(state
->success
)) {
3218 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3222 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3223 struct tdb_validation_status
*state
)
3225 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3232 (void)centry_string(centry
, mem_ctx
);
3233 (void)centry_string(centry
, mem_ctx
);
3234 (void)centry_string(centry
, mem_ctx
);
3235 (void)centry_string(centry
, mem_ctx
);
3236 (void)centry_uint32(centry
);
3237 (void)centry_sid(centry
, &sid
);
3238 (void)centry_sid(centry
, &sid
);
3240 centry_free(centry
);
3242 if (!(state
->success
)) {
3245 DEBUG(10,("validate_u: %s ok\n", keystr
));
3249 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3250 struct tdb_validation_status
*state
)
3252 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3258 (void)centry_nttime(centry
);
3259 (void)centry_nttime(centry
);
3260 (void)centry_uint16(centry
);
3262 centry_free(centry
);
3264 if (!(state
->success
)) {
3267 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3271 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3272 struct tdb_validation_status
*state
)
3274 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3280 (void)centry_uint16(centry
);
3281 (void)centry_uint16(centry
);
3282 (void)centry_uint32(centry
);
3283 (void)centry_nttime(centry
);
3284 (void)centry_nttime(centry
);
3286 centry_free(centry
);
3288 if (!(state
->success
)) {
3291 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3295 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3296 struct tdb_validation_status
*state
)
3298 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3304 (void)centry_time(centry
);
3305 (void)centry_hash16(centry
, mem_ctx
);
3307 /* We only have 17 bytes more data in the salted cred case. */
3308 if (centry
->len
- centry
->ofs
== 17) {
3309 (void)centry_hash16(centry
, mem_ctx
);
3312 centry_free(centry
);
3314 if (!(state
->success
)) {
3317 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3321 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3322 struct tdb_validation_status
*state
)
3324 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3325 int32 num_entries
, i
;
3331 num_entries
= (int32
)centry_uint32(centry
);
3333 for (i
=0; i
< num_entries
; i
++) {
3335 (void)centry_string(centry
, mem_ctx
);
3336 (void)centry_string(centry
, mem_ctx
);
3337 (void)centry_string(centry
, mem_ctx
);
3338 (void)centry_string(centry
, mem_ctx
);
3339 (void)centry_sid(centry
, &sid
);
3340 (void)centry_sid(centry
, &sid
);
3343 centry_free(centry
);
3345 if (!(state
->success
)) {
3348 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3352 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3353 struct tdb_validation_status
*state
)
3355 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3356 int32 num_entries
, i
;
3362 num_entries
= centry_uint32(centry
);
3364 for (i
=0; i
< num_entries
; i
++) {
3365 (void)centry_string(centry
, mem_ctx
);
3366 (void)centry_string(centry
, mem_ctx
);
3367 (void)centry_uint32(centry
);
3370 centry_free(centry
);
3372 if (!(state
->success
)) {
3375 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3379 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3380 struct tdb_validation_status
*state
)
3382 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3383 int32 num_groups
, i
;
3389 num_groups
= centry_uint32(centry
);
3391 for (i
=0; i
< num_groups
; i
++) {
3393 centry_sid(centry
, &sid
);
3396 centry_free(centry
);
3398 if (!(state
->success
)) {
3401 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3405 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3406 struct tdb_validation_status
*state
)
3408 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3409 int32 num_aliases
, i
;
3415 num_aliases
= centry_uint32(centry
);
3417 for (i
=0; i
< num_aliases
; i
++) {
3418 (void)centry_uint32(centry
);
3421 centry_free(centry
);
3423 if (!(state
->success
)) {
3426 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3430 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3431 struct tdb_validation_status
*state
)
3433 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3440 num_names
= centry_uint32(centry
);
3442 for (i
=0; i
< num_names
; i
++) {
3444 centry_sid(centry
, &sid
);
3445 (void)centry_string(centry
, mem_ctx
);
3446 (void)centry_uint32(centry
);
3449 centry_free(centry
);
3451 if (!(state
->success
)) {
3454 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3458 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3459 struct tdb_validation_status
*state
)
3461 /* Can't say anything about this other than must be nonzero. */
3462 if (dbuf
.dsize
== 0) {
3463 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3465 state
->bad_entry
= true;
3466 state
->success
= false;
3470 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3474 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3475 struct tdb_validation_status
*state
)
3477 /* Can't say anything about this other than must be nonzero. */
3478 if (dbuf
.dsize
== 0) {
3479 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3481 state
->bad_entry
= true;
3482 state
->success
= false;
3486 DEBUG(10,("validate_de: %s ok\n", keystr
));
3490 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3491 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3493 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3499 (void)centry_string(centry
, mem_ctx
);
3500 (void)centry_string(centry
, mem_ctx
);
3501 (void)centry_string(centry
, mem_ctx
);
3502 (void)centry_uint32(centry
);
3504 centry_free(centry
);
3506 if (!(state
->success
)) {
3509 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3513 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3515 struct tdb_validation_status
*state
)
3517 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3523 (void)centry_string( centry
, mem_ctx
);
3525 centry_free(centry
);
3527 if (!(state
->success
)) {
3530 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3534 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3536 struct tdb_validation_status
*state
)
3538 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3544 (void)centry_string( centry
, mem_ctx
);
3546 centry_free(centry
);
3548 if (!(state
->success
)) {
3551 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3555 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3556 struct tdb_validation_status
*state
)
3558 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3559 int32 num_domains
, i
;
3565 num_domains
= centry_uint32(centry
);
3567 for (i
=0; i
< num_domains
; i
++) {
3569 (void)centry_string(centry
, mem_ctx
);
3570 (void)centry_string(centry
, mem_ctx
);
3571 (void)centry_sid(centry
, &sid
);
3574 centry_free(centry
);
3576 if (!(state
->success
)) {
3579 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3583 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3585 struct tdb_validation_status
*state
)
3587 if (dbuf
.dsize
== 0) {
3588 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3589 "key %s (len ==0) ?\n", keystr
));
3590 state
->bad_entry
= true;
3591 state
->success
= false;
3595 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3596 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3600 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3601 struct tdb_validation_status
*state
)
3603 if (dbuf
.dsize
!= 4) {
3604 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3605 keystr
, (unsigned int)dbuf
.dsize
));
3606 state
->bad_entry
= true;
3607 state
->success
= false;
3610 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3614 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3615 struct tdb_validation_status
*state
)
3617 if (dbuf
.dsize
!= 4) {
3618 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3619 "key %s (len %u != 4) ?\n",
3620 keystr
, (unsigned int)dbuf
.dsize
));
3621 state
->bad_entry
= true;
3622 state
->success
= false;
3626 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3630 /***********************************************************************
3631 A list of all possible cache tdb keys with associated validation
3633 ***********************************************************************/
3635 struct key_val_struct
{
3636 const char *keyname
;
3637 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3639 {"SEQNUM/", validate_seqnum
},
3640 {"NS/", validate_ns
},
3641 {"SN/", validate_sn
},
3643 {"LOC_POL/", validate_loc_pol
},
3644 {"PWD_POL/", validate_pwd_pol
},
3645 {"CRED/", validate_cred
},
3646 {"UL/", validate_ul
},
3647 {"GL/", validate_gl
},
3648 {"UG/", validate_ug
},
3649 {"UA", validate_ua
},
3650 {"GM/", validate_gm
},
3651 {"DR/", validate_dr
},
3652 {"DE/", validate_de
},
3653 {"NSS/PWINFO/", validate_pwinfo
},
3654 {"TRUSTDOMS/", validate_trustdoms
},
3655 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3656 {"NSS/NA/", validate_nss_na
},
3657 {"NSS/AN/", validate_nss_an
},
3658 {"WINBINDD_OFFLINE", validate_offline
},
3659 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3663 /***********************************************************************
3664 Function to look at every entry in the tdb and validate it as far as
3666 ***********************************************************************/
3668 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3671 unsigned int max_key_len
= 1024;
3672 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3674 /* Paranoia check. */
3675 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
3676 max_key_len
= 1024 * 1024;
3678 if (kbuf
.dsize
> max_key_len
) {
3679 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3681 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
3685 for (i
= 0; key_val
[i
].keyname
; i
++) {
3686 size_t namelen
= strlen(key_val
[i
].keyname
);
3687 if (kbuf
.dsize
>= namelen
&& (
3688 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3689 TALLOC_CTX
*mem_ctx
;
3693 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3697 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3698 keystr
[kbuf
.dsize
] = '\0';
3700 mem_ctx
= talloc_init("validate_ctx");
3706 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3710 talloc_destroy(mem_ctx
);
3715 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3716 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3717 DEBUG(0,("data :\n"));
3718 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3719 v_state
->unknown_key
= true;
3720 v_state
->success
= false;
3721 return 1; /* terminate. */
3724 static void validate_panic(const char *const why
)
3726 DEBUG(0,("validating cache: would panic %s\n", why
));
3727 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3731 /***********************************************************************
3732 Try and validate every entry in the winbindd cache. If we fail here,
3733 delete the cache tdb and return non-zero.
3734 ***********************************************************************/
3736 int winbindd_validate_cache(void)
3739 const char *tdb_path
= cache_path("winbindd_cache.tdb");
3740 TDB_CONTEXT
*tdb
= NULL
;
3742 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3743 smb_panic_fn
= validate_panic
;
3746 tdb
= tdb_open_log(tdb_path
,
3747 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3748 ( lp_winbind_offline_logon()
3750 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3754 DEBUG(0, ("winbindd_validate_cache: "
3755 "error opening/initializing tdb\n"));
3760 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
3763 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3764 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
3769 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3770 smb_panic_fn
= smb_panic
;
3774 /***********************************************************************
3775 Try and validate every entry in the winbindd cache.
3776 ***********************************************************************/
3778 int winbindd_validate_cache_nobackup(void)
3781 const char *tdb_path
= cache_path("winbindd_cache.tdb");
3783 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3784 smb_panic_fn
= validate_panic
;
3787 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3788 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
3790 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
3794 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3798 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3800 smb_panic_fn
= smb_panic
;
3804 bool winbindd_cache_validate_and_initialize(void)
3806 close_winbindd_cache();
3808 if (lp_winbind_offline_logon()) {
3809 if (winbindd_validate_cache() < 0) {
3810 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3811 "could be restored.\n"));
3815 return initialize_winbindd_cache();
3818 /*********************************************************************
3819 ********************************************************************/
3821 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3822 struct winbindd_tdc_domain
**domains
,
3823 size_t *num_domains
)
3825 struct winbindd_tdc_domain
*list
= NULL
;
3828 bool set_only
= false;
3830 /* don't allow duplicates */
3835 for ( i
=0; i
< (*num_domains
); i
++ ) {
3836 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3837 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3848 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3851 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3852 struct winbindd_tdc_domain
,
3857 ZERO_STRUCT( list
[idx
] );
3863 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3864 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3866 if ( !is_null_sid( &new_dom
->sid
) ) {
3867 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3869 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
3872 if ( new_dom
->domain_flags
!= 0x0 )
3873 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3875 if ( new_dom
->domain_type
!= 0x0 )
3876 list
[idx
].trust_type
= new_dom
->domain_type
;
3878 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3879 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3883 *num_domains
= idx
+ 1;
3889 /*********************************************************************
3890 ********************************************************************/
3892 static TDB_DATA
make_tdc_key( const char *domain_name
)
3894 char *keystr
= NULL
;
3895 TDB_DATA key
= { NULL
, 0 };
3897 if ( !domain_name
) {
3898 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3902 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
3905 key
= string_term_tdb_data(keystr
);
3910 /*********************************************************************
3911 ********************************************************************/
3913 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3915 unsigned char **buf
)
3917 unsigned char *buffer
= NULL
;
3922 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3930 /* Store the number of array items first */
3931 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3934 /* now pack each domain trust record */
3935 for ( i
=0; i
<num_domains
; i
++ ) {
3940 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3941 domains
[i
].domain_name
,
3942 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3945 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3946 domains
[i
].domain_name
,
3947 domains
[i
].dns_name
,
3948 sid_to_fstring(tmp
, &domains
[i
].sid
),
3949 domains
[i
].trust_flags
,
3950 domains
[i
].trust_attribs
,
3951 domains
[i
].trust_type
);
3954 if ( buflen
< len
) {
3956 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3957 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3971 /*********************************************************************
3972 ********************************************************************/
3974 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3975 struct winbindd_tdc_domain
**domains
)
3977 fstring domain_name
, dns_name
, sid_string
;
3978 uint32 type
, attribs
, flags
;
3982 struct winbindd_tdc_domain
*list
= NULL
;
3984 /* get the number of domains */
3985 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3987 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3991 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3993 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3997 for ( i
=0; i
<num_domains
; i
++ ) {
3998 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4007 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4008 TALLOC_FREE( list
);
4012 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4013 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4014 domain_name
, dns_name
, sid_string
,
4015 flags
, attribs
, type
));
4017 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4018 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4019 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4020 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4023 list
[i
].trust_flags
= flags
;
4024 list
[i
].trust_attribs
= attribs
;
4025 list
[i
].trust_type
= type
;
4033 /*********************************************************************
4034 ********************************************************************/
4036 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4038 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4039 TDB_DATA data
= { NULL
, 0 };
4045 /* See if we were asked to delete the cache entry */
4048 ret
= tdb_delete( wcache
->tdb
, key
);
4052 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4059 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4062 SAFE_FREE( data
.dptr
);
4063 SAFE_FREE( key
.dptr
);
4065 return ( ret
!= -1 );
4068 /*********************************************************************
4069 ********************************************************************/
4071 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4073 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4074 TDB_DATA data
= { NULL
, 0 };
4082 data
= tdb_fetch( wcache
->tdb
, key
);
4084 SAFE_FREE( key
.dptr
);
4089 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4091 SAFE_FREE( data
.dptr
);
4099 /*********************************************************************
4100 ********************************************************************/
4102 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4104 struct winbindd_tdc_domain
*dom_list
= NULL
;
4105 size_t num_domains
= 0;
4108 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4109 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4110 domain
->name
, domain
->alt_name
,
4111 sid_string_dbg(&domain
->sid
),
4112 domain
->domain_flags
,
4113 domain
->domain_trust_attribs
,
4114 domain
->domain_type
));
4116 if ( !init_wcache() ) {
4120 /* fetch the list */
4122 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4124 /* add the new domain */
4126 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4130 /* pack the domain */
4132 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4140 TALLOC_FREE( dom_list
);
4145 /*********************************************************************
4146 ********************************************************************/
4148 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4150 struct winbindd_tdc_domain
*dom_list
= NULL
;
4151 size_t num_domains
= 0;
4153 struct winbindd_tdc_domain
*d
= NULL
;
4155 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4157 if ( !init_wcache() ) {
4161 /* fetch the list */
4163 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4165 for ( i
=0; i
<num_domains
; i
++ ) {
4166 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4167 strequal(name
, dom_list
[i
].dns_name
) )
4169 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4172 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4176 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4177 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4178 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4179 d
->trust_flags
= dom_list
[i
].trust_flags
;
4180 d
->trust_type
= dom_list
[i
].trust_type
;
4181 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4187 TALLOC_FREE( dom_list
);
4193 /*********************************************************************
4194 ********************************************************************/
4196 void wcache_tdc_clear( void )
4198 if ( !init_wcache() )
4201 wcache_tdc_store_list( NULL
, 0 );
4207 /*********************************************************************
4208 ********************************************************************/
4210 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4212 const DOM_SID
*user_sid
,
4213 const char *homedir
,
4218 struct cache_entry
*centry
;
4221 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4224 centry_put_string( centry
, homedir
);
4225 centry_put_string( centry
, shell
);
4226 centry_put_string( centry
, gecos
);
4227 centry_put_uint32( centry
, gid
);
4229 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4231 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4233 centry_free(centry
);
4236 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4237 const DOM_SID
*user_sid
,
4239 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
4240 const char **homedir
, const char **shell
,
4241 const char **gecos
, gid_t
*p_gid
)
4243 struct winbind_cache
*cache
= get_cache(domain
);
4244 struct cache_entry
*centry
= NULL
;
4251 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4252 sid_to_fstring(tmp
, user_sid
));
4257 *homedir
= centry_string( centry
, ctx
);
4258 *shell
= centry_string( centry
, ctx
);
4259 *gecos
= centry_string( centry
, ctx
);
4260 *p_gid
= centry_uint32( centry
);
4262 centry_free(centry
);
4264 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4265 sid_string_dbg(user_sid
)));
4267 return NT_STATUS_OK
;
4271 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
4272 homedir
, shell
, gecos
, p_gid
);
4274 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4276 if ( NT_STATUS_IS_OK(nt_status
) ) {
4277 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4278 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4279 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4280 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4282 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4283 *homedir
, *shell
, *gecos
, *p_gid
);
4286 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4287 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4289 set_domain_offline( domain
);
4296 /* the cache backend methods are exposed via this structure */
4297 struct winbindd_methods cache_methods
= {
4315 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4316 uint32_t opnum
, const DATA_BLOB
*req
,
4322 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4326 keylen
= talloc_get_size(key
) - 1;
4328 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4332 memcpy(key
+ keylen
, req
->data
, req
->length
);
4334 pkey
->dptr
= (uint8_t *)key
;
4335 pkey
->dsize
= talloc_get_size(key
);
4339 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4340 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4345 if (wcache
->tdb
== NULL
) {
4349 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4352 data
= tdb_fetch(wcache
->tdb
, key
);
4353 TALLOC_FREE(key
.dptr
);
4355 if (data
.dptr
== NULL
) {
4358 if (data
.dsize
< 4) {
4362 if (IS_DOMAIN_ONLINE(domain
)) {
4363 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4365 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4369 entry_seqnum
= IVAL(data
.dptr
, 0);
4370 if (entry_seqnum
!= dom_seqnum
) {
4371 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4372 (int)entry_seqnum
));
4377 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 4,
4379 if (resp
->data
== NULL
) {
4380 DEBUG(10, ("talloc failed\n"));
4383 resp
->length
= data
.dsize
- 4;
4387 SAFE_FREE(data
.dptr
);
4391 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4392 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4395 uint32_t dom_seqnum
, last_check
;
4397 if (wcache
->tdb
== NULL
) {
4401 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4402 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4407 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4411 data
.dsize
= resp
->length
+ 4;
4412 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4413 if (data
.dptr
== NULL
) {
4417 SIVAL(data
.dptr
, 0, dom_seqnum
);
4418 memcpy(data
.dptr
+4, resp
->data
, resp
->length
);
4420 tdb_store(wcache
->tdb
, key
, data
, 0);
4423 TALLOC_FREE(key
.dptr
);