Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Winbind cache backend functions
5 :
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
11 :
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.
16 :
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.
21 :
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/>.
24 : */
25 :
26 : #include "includes.h"
27 : #include "system/filesys.h"
28 : #include "winbindd.h"
29 : #include "tdb_validate.h"
30 : #include "../libcli/auth/libcli_auth.h"
31 : #include "../librpc/gen_ndr/ndr_winbind.h"
32 : #include "ads.h"
33 : #include "nss_info.h"
34 : #include "../libcli/security/security.h"
35 : #include "passdb/machine_sid.h"
36 : #include "util_tdb.h"
37 : #include "libsmb/samlogon_cache.h"
38 : #include "lib/namemap_cache.h"
39 : #include "lib/util/string_wrappers.h"
40 :
41 : #include "lib/crypto/gnutls_helpers.h"
42 : #include <gnutls/crypto.h>
43 :
44 : #undef DBGC_CLASS
45 : #define DBGC_CLASS DBGC_WINBIND
46 :
47 : #define WINBINDD_CACHE_VER1 1 /* initial db version */
48 : #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
49 :
50 : #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
51 : #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
52 :
53 : extern struct winbindd_methods reconnect_methods;
54 : #ifdef HAVE_ADS
55 : extern struct winbindd_methods reconnect_ads_methods;
56 : #endif
57 : extern struct winbindd_methods builtin_passdb_methods;
58 : extern struct winbindd_methods sam_passdb_methods;
59 :
60 : static void wcache_flush_cache(void);
61 :
62 : static bool opt_nocache = False;
63 :
64 : /*
65 : * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
66 : * Here are the list of entry types that are *not* stored
67 : * as form struct cache_entry in the cache.
68 : */
69 :
70 : static const char *non_centry_keys[] = {
71 : "NDR/",
72 : "SEQNUM/",
73 : "TRUSTDOMCACHE/",
74 : "WINBINDD_OFFLINE",
75 : WINBINDD_CACHE_VERSION_KEYSTR,
76 : NULL
77 : };
78 :
79 204598 : bool winbindd_use_idmap_cache(void)
80 : {
81 204598 : return !opt_nocache;
82 : }
83 :
84 0 : bool winbindd_use_cache(void)
85 : {
86 0 : return !opt_nocache;
87 : }
88 :
89 0 : void winbindd_set_use_cache(bool use_cache)
90 : {
91 0 : opt_nocache = !use_cache;
92 0 : }
93 :
94 86 : void winbindd_flush_caches(void)
95 : {
96 : /* We need to invalidate cached user list entries on a SIGHUP
97 : otherwise cached access denied errors due to restrict anonymous
98 : hang around until the sequence number changes. */
99 :
100 86 : if (!wcache_invalidate_cache()) {
101 0 : DBG_ERR("invalidating the cache failed; revalidate the cache\n");
102 0 : if (!winbindd_cache_validate_and_initialize()) {
103 0 : exit(1);
104 : }
105 : }
106 86 : }
107 :
108 : /************************************************************************
109 : Is this key a non-centry type ?
110 : ************************************************************************/
111 :
112 0 : static bool is_non_centry_key(TDB_DATA kbuf)
113 : {
114 0 : int i;
115 :
116 0 : if (kbuf.dptr == NULL || kbuf.dsize == 0) {
117 0 : return false;
118 : }
119 0 : for (i = 0; non_centry_keys[i] != NULL; i++) {
120 0 : size_t namelen = strlen(non_centry_keys[i]);
121 0 : if (kbuf.dsize < namelen) {
122 0 : continue;
123 : }
124 0 : if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
125 0 : return true;
126 : }
127 : }
128 0 : return false;
129 : }
130 :
131 : struct winbind_cache {
132 : TDB_CONTEXT *tdb;
133 : };
134 :
135 : struct cache_entry {
136 : NTSTATUS status;
137 : uint32_t sequence_number;
138 : uint64_t timeout;
139 : uint8_t *data;
140 : uint32_t len, ofs;
141 : };
142 :
143 : void (*smb_panic_fn)(const char *const why) = smb_panic;
144 :
145 : static struct winbind_cache *wcache;
146 :
147 172 : static char *wcache_path(void)
148 : {
149 : /*
150 : * Data needs to be kept persistent in state directory for
151 : * running with "winbindd offline logon".
152 : */
153 172 : return state_path(talloc_tos(), "winbindd_cache.tdb");
154 : }
155 :
156 1078 : static void winbindd_domain_init_backend(struct winbindd_domain *domain)
157 : {
158 1078 : if (domain->backend != NULL) {
159 1042 : return;
160 : }
161 :
162 36 : if (domain->internal) {
163 20 : domain->backend = &builtin_passdb_methods;
164 : }
165 :
166 36 : if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
167 10 : domain->initialized = true;
168 : }
169 :
170 46 : if (strequal(domain->name, get_global_sam_name()) &&
171 10 : sid_check_is_our_sam(&domain->sid))
172 : {
173 10 : domain->backend = &sam_passdb_methods;
174 : }
175 :
176 36 : if (!domain->initialized) {
177 : /* We do not need a connection to an RW DC for cache operation */
178 0 : init_dc_connection(domain, false);
179 : }
180 :
181 : #ifdef HAVE_ADS
182 34 : if (domain->backend == NULL) {
183 16 : struct winbindd_domain *our_domain = domain;
184 :
185 : /* find our domain first so we can figure out if we
186 : are joined to a kerberized domain */
187 :
188 16 : if (!domain->primary) {
189 4 : our_domain = find_our_domain();
190 : }
191 :
192 16 : if ((our_domain->active_directory || IS_DC)
193 16 : && domain->active_directory
194 16 : && !lp_winbind_rpc_only())
195 : {
196 16 : DBG_INFO("Setting ADS methods for domain %s\n",
197 : domain->name);
198 16 : domain->backend = &reconnect_ads_methods;
199 : }
200 : }
201 : #endif /* HAVE_ADS */
202 :
203 36 : if (domain->backend == NULL) {
204 0 : DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
205 0 : domain->backend = &reconnect_methods;
206 : }
207 : }
208 :
209 : /* get the winbind_cache structure */
210 1078 : static struct winbind_cache *get_cache(struct winbindd_domain *domain)
211 : {
212 1078 : struct winbind_cache *ret = wcache;
213 :
214 1078 : winbindd_domain_init_backend(domain);
215 :
216 1078 : if (ret != NULL) {
217 1078 : return ret;
218 : }
219 :
220 0 : ret = SMB_XMALLOC_P(struct winbind_cache);
221 0 : ZERO_STRUCTP(ret);
222 :
223 0 : wcache = ret;
224 0 : wcache_flush_cache();
225 :
226 0 : return ret;
227 : }
228 :
229 : /*
230 : free a centry structure
231 : */
232 24 : static void centry_free(struct cache_entry *centry)
233 : {
234 24 : if (!centry)
235 0 : return;
236 24 : SAFE_FREE(centry->data);
237 24 : free(centry);
238 : }
239 :
240 176 : static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
241 : {
242 176 : if (centry->len - centry->ofs < nbytes) {
243 0 : DBG_ERR("centry corruption? needed %u bytes, have %d\n",
244 : (unsigned int)nbytes,
245 : centry->len - centry->ofs);
246 0 : return false;
247 : }
248 176 : return true;
249 : }
250 :
251 : /*
252 : pull a uint64_t from a cache entry
253 : */
254 24 : static uint64_t centry_uint64_t(struct cache_entry *centry)
255 : {
256 0 : uint64_t ret;
257 :
258 24 : if (!centry_check_bytes(centry, 8)) {
259 0 : smb_panic_fn("centry_uint64_t");
260 : }
261 24 : ret = BVAL(centry->data, centry->ofs);
262 24 : centry->ofs += 8;
263 24 : return ret;
264 : }
265 :
266 : /*
267 : pull a uint32_t from a cache entry
268 : */
269 48 : static uint32_t centry_uint32(struct cache_entry *centry)
270 : {
271 0 : uint32_t ret;
272 :
273 48 : if (!centry_check_bytes(centry, 4)) {
274 0 : smb_panic_fn("centry_uint32");
275 : }
276 48 : ret = IVAL(centry->data, centry->ofs);
277 48 : centry->ofs += 4;
278 48 : return ret;
279 : }
280 :
281 : /*
282 : pull a uint16_t from a cache entry
283 : */
284 8 : static uint16_t centry_uint16(struct cache_entry *centry)
285 : {
286 0 : uint16_t ret;
287 8 : if (!centry_check_bytes(centry, 2)) {
288 0 : smb_panic_fn("centry_uint16");
289 : }
290 8 : ret = SVAL(centry->data, centry->ofs);
291 8 : centry->ofs += 2;
292 8 : return ret;
293 : }
294 :
295 : /*
296 : pull a uint8_t from a cache entry
297 : */
298 32 : static uint8_t centry_uint8(struct cache_entry *centry)
299 : {
300 0 : uint8_t ret;
301 32 : if (!centry_check_bytes(centry, 1)) {
302 0 : smb_panic_fn("centry_uint8");
303 : }
304 32 : ret = CVAL(centry->data, centry->ofs);
305 32 : centry->ofs += 1;
306 32 : return ret;
307 : }
308 :
309 : /*
310 : pull a NTTIME from a cache entry
311 : */
312 32 : static NTTIME centry_nttime(struct cache_entry *centry)
313 : {
314 0 : NTTIME ret;
315 32 : if (!centry_check_bytes(centry, 8)) {
316 0 : smb_panic_fn("centry_nttime");
317 : }
318 32 : ret = IVAL(centry->data, centry->ofs);
319 32 : centry->ofs += 4;
320 32 : ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
321 32 : centry->ofs += 4;
322 32 : return ret;
323 : }
324 :
325 : /*
326 : pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
327 : */
328 16 : static time_t centry_time(struct cache_entry *centry)
329 : {
330 16 : return (time_t)centry_nttime(centry);
331 : }
332 :
333 : /* pull a string from a cache entry, using the supplied
334 : talloc context
335 : */
336 0 : static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
337 : {
338 0 : uint32_t len;
339 0 : char *ret;
340 :
341 0 : len = centry_uint8(centry);
342 :
343 0 : if (len == 0xFF) {
344 : /* a deliberate NULL string */
345 0 : return NULL;
346 : }
347 :
348 0 : if (!centry_check_bytes(centry, (size_t)len)) {
349 0 : smb_panic_fn("centry_string");
350 : }
351 :
352 0 : ret = talloc_array(mem_ctx, char, len+1);
353 0 : if (!ret) {
354 0 : smb_panic_fn("centry_string out of memory\n");
355 : }
356 0 : memcpy(ret,centry->data + centry->ofs, len);
357 0 : ret[len] = 0;
358 0 : centry->ofs += len;
359 0 : return ret;
360 : }
361 :
362 : /* pull a hash16 from a cache entry, using the supplied
363 : talloc context
364 : */
365 32 : static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
366 : {
367 0 : uint32_t len;
368 0 : char *ret;
369 :
370 32 : len = centry_uint8(centry);
371 :
372 32 : if (len != 16) {
373 0 : DBG_ERR("centry corruption? hash len (%u) != 16\n",
374 : len );
375 0 : return NULL;
376 : }
377 :
378 32 : if (!centry_check_bytes(centry, 16)) {
379 0 : return NULL;
380 : }
381 :
382 32 : ret = talloc_array(mem_ctx, char, 16);
383 32 : if (!ret) {
384 0 : smb_panic_fn("centry_hash out of memory\n");
385 : }
386 32 : memcpy(ret,centry->data + centry->ofs, 16);
387 32 : centry->ofs += 16;
388 32 : return ret;
389 : }
390 :
391 : /* pull a sid from a cache entry, using the supplied
392 : talloc context
393 : */
394 0 : static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
395 : {
396 0 : char *sid_string;
397 0 : bool ret;
398 :
399 0 : sid_string = centry_string(centry, talloc_tos());
400 0 : if (sid_string == NULL) {
401 0 : return false;
402 : }
403 0 : ret = string_to_sid(sid, sid_string);
404 0 : TALLOC_FREE(sid_string);
405 0 : return ret;
406 : }
407 :
408 :
409 : /*
410 : pull a NTSTATUS from a cache entry
411 : */
412 0 : static NTSTATUS centry_ntstatus(struct cache_entry *centry)
413 : {
414 0 : NTSTATUS status;
415 :
416 0 : status = NT_STATUS(centry_uint32(centry));
417 0 : return status;
418 : }
419 :
420 :
421 : /* the server is considered down if it can't give us a sequence number */
422 0 : static bool wcache_server_down(struct winbindd_domain *domain)
423 : {
424 0 : bool ret;
425 :
426 0 : if (!wcache->tdb)
427 0 : return false;
428 :
429 0 : ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
430 :
431 0 : if (ret)
432 0 : DBG_DEBUG("wcache_server_down: server for Domain %s down\n",
433 : domain->name );
434 0 : return ret;
435 : }
436 :
437 : struct wcache_seqnum_state {
438 : uint32_t *seqnum;
439 : uint32_t *last_seq_check;
440 : };
441 :
442 104599 : static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
443 : void *private_data)
444 : {
445 104599 : struct wcache_seqnum_state *state = private_data;
446 :
447 104599 : if (data.dsize != 8) {
448 0 : DBG_DEBUG("wcache_fetch_seqnum: invalid data size %d\n",
449 : (int)data.dsize);
450 0 : return -1;
451 : }
452 :
453 104599 : *state->seqnum = IVAL(data.dptr, 0);
454 104599 : *state->last_seq_check = IVAL(data.dptr, 4);
455 104599 : return 0;
456 : }
457 :
458 106337 : static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
459 : uint32_t *last_seq_check)
460 106337 : {
461 106337 : struct wcache_seqnum_state state = {
462 : .seqnum = seqnum, .last_seq_check = last_seq_check
463 : };
464 106337 : size_t len = strlen(domain_name);
465 106337 : char keystr[len+8];
466 106337 : TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
467 0 : int ret;
468 :
469 106337 : if (wcache->tdb == NULL) {
470 0 : DBG_DEBUG("wcache_fetch_seqnum: tdb == NULL\n");
471 0 : return false;
472 : }
473 :
474 106337 : snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
475 :
476 106337 : ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
477 : &state);
478 106337 : return (ret == 0);
479 : }
480 :
481 882 : static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
482 : {
483 0 : uint32_t last_check, time_diff;
484 :
485 882 : if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
486 : &last_check)) {
487 424 : return NT_STATUS_UNSUCCESSFUL;
488 : }
489 458 : domain->last_seq_check = last_check;
490 :
491 : /* have we expired? */
492 :
493 458 : time_diff = now - domain->last_seq_check;
494 458 : if ((int)time_diff > lp_winbind_cache_time()) {
495 24 : DBG_DEBUG("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
496 : domain->name, domain->sequence_number,
497 : (uint32_t)domain->last_seq_check);
498 24 : return NT_STATUS_UNSUCCESSFUL;
499 : }
500 :
501 434 : DBG_DEBUG("fetch_cache_seqnum: success [%s][%u @ %u]\n",
502 : domain->name, domain->sequence_number,
503 : (uint32_t)domain->last_seq_check);
504 :
505 434 : return NT_STATUS_OK;
506 : }
507 :
508 16 : bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
509 : time_t last_seq_check)
510 16 : {
511 16 : size_t len = strlen(domain_name);
512 16 : char keystr[len+8];
513 16 : TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
514 0 : uint8_t buf[8];
515 0 : int ret;
516 :
517 16 : if (wcache->tdb == NULL) {
518 0 : DBG_DEBUG("wcache_store_seqnum: wcache->tdb == NULL\n");
519 0 : return false;
520 : }
521 :
522 16 : snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
523 :
524 16 : SIVAL(buf, 0, seqnum);
525 16 : SIVAL(buf, 4, last_seq_check);
526 :
527 16 : ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
528 : TDB_REPLACE);
529 16 : if (ret != 0) {
530 0 : DBG_DEBUG("tdb_store_bystring failed: %s\n",
531 : tdb_errorstr(wcache->tdb));
532 0 : return false;
533 : }
534 :
535 16 : DBG_DEBUG("wcache_store_seqnum: success [%s][%u @ %u]\n",
536 : domain_name, seqnum, (unsigned)last_seq_check);
537 :
538 16 : return true;
539 : }
540 :
541 0 : static bool store_cache_seqnum( struct winbindd_domain *domain )
542 : {
543 0 : return wcache_store_seqnum(domain->name, domain->sequence_number,
544 : domain->last_seq_check);
545 : }
546 :
547 : /*
548 : refresh the domain sequence number on timeout.
549 : */
550 :
551 0 : static void refresh_sequence_number(struct winbindd_domain *domain)
552 : {
553 0 : NTSTATUS status;
554 0 : unsigned time_diff;
555 0 : time_t t = time(NULL);
556 0 : unsigned cache_time = lp_winbind_cache_time();
557 :
558 0 : if (is_domain_offline(domain)) {
559 0 : return;
560 : }
561 :
562 0 : get_cache( domain );
563 :
564 0 : time_diff = t - domain->last_seq_check;
565 :
566 : /* see if we have to refetch the domain sequence number */
567 0 : if ((time_diff < cache_time) &&
568 0 : (domain->sequence_number != DOM_SEQUENCE_NONE) &&
569 0 : NT_STATUS_IS_OK(domain->last_status)) {
570 0 : DBG_DEBUG("refresh_sequence_number: %s time ok\n", domain->name);
571 0 : goto done;
572 : }
573 :
574 : /* try to get the sequence number from the tdb cache first */
575 : /* this will update the timestamp as well */
576 :
577 0 : status = fetch_cache_seqnum( domain, t );
578 0 : if (NT_STATUS_IS_OK(status) &&
579 0 : (domain->sequence_number != DOM_SEQUENCE_NONE) &&
580 0 : NT_STATUS_IS_OK(domain->last_status)) {
581 0 : goto done;
582 : }
583 :
584 : /* just use the current time */
585 0 : domain->last_status = NT_STATUS_OK;
586 0 : domain->sequence_number = time(NULL);
587 0 : domain->last_seq_check = time(NULL);
588 :
589 : /* save the new sequence number in the cache */
590 0 : store_cache_seqnum( domain );
591 :
592 0 : done:
593 0 : DBG_DEBUG("refresh_sequence_number: %s seq number is now %d\n",
594 : domain->name, domain->sequence_number);
595 :
596 0 : return;
597 : }
598 :
599 : /*
600 : decide if a cache entry has expired
601 : */
602 0 : static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
603 : {
604 : /* If we've been told to be offline - stay in that state... */
605 0 : if (lp_winbind_offline_logon() && get_global_winbindd_state_offline()) {
606 0 : DBG_DEBUG("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
607 : keystr, domain->name );
608 0 : return false;
609 : }
610 :
611 : /* when the domain is offline return the cached entry.
612 : * This deals with transient offline states... */
613 :
614 0 : if (!domain->online) {
615 0 : DBG_DEBUG("centry_expired: Key %s for domain %s valid as domain is offline.\n",
616 : keystr, domain->name );
617 0 : return false;
618 : }
619 :
620 : /* if the server is OK and our cache entry came from when it was down then
621 : the entry is invalid */
622 0 : if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
623 0 : (centry->sequence_number == DOM_SEQUENCE_NONE)) {
624 0 : DBG_DEBUG("centry_expired: Key %s for domain %s invalid sequence.\n",
625 : keystr, domain->name );
626 0 : return true;
627 : }
628 :
629 : /* if the server is down or the cache entry is not older than the
630 : current sequence number or it did not timeout then it is OK */
631 0 : if (wcache_server_down(domain)
632 0 : || ((centry->sequence_number == domain->sequence_number)
633 0 : && ((time_t)centry->timeout > time(NULL)))) {
634 0 : DBG_DEBUG("centry_expired: Key %s for domain %s is good.\n",
635 : keystr, domain->name );
636 0 : return false;
637 : }
638 :
639 0 : DBG_DEBUG("centry_expired: Key %s for domain %s expired\n",
640 : keystr, domain->name );
641 :
642 : /* it's expired */
643 0 : return true;
644 : }
645 :
646 0 : static struct cache_entry *wcache_fetch_raw(char *kstr)
647 : {
648 0 : TDB_DATA data;
649 0 : struct cache_entry *centry;
650 0 : TDB_DATA key;
651 :
652 0 : key = string_tdb_data(kstr);
653 0 : data = tdb_fetch(wcache->tdb, key);
654 0 : if (!data.dptr) {
655 : /* a cache miss */
656 0 : return NULL;
657 : }
658 :
659 0 : centry = SMB_XMALLOC_P(struct cache_entry);
660 0 : centry->data = (unsigned char *)data.dptr;
661 0 : centry->len = data.dsize;
662 0 : centry->ofs = 0;
663 :
664 0 : if (centry->len < 16) {
665 : /* huh? corrupt cache? */
666 0 : DBG_DEBUG("wcache_fetch_raw: Corrupt cache for key %s "
667 : "(len < 16)?\n", kstr);
668 0 : centry_free(centry);
669 0 : return NULL;
670 : }
671 :
672 0 : centry->status = centry_ntstatus(centry);
673 0 : centry->sequence_number = centry_uint32(centry);
674 0 : centry->timeout = centry_uint64_t(centry);
675 :
676 0 : return centry;
677 : }
678 :
679 139273 : static bool is_my_own_sam_domain(struct winbindd_domain *domain)
680 : {
681 163391 : if (strequal(domain->name, get_global_sam_name()) &&
682 24118 : sid_check_is_our_sam(&domain->sid)) {
683 24118 : return true;
684 : }
685 :
686 115155 : return false;
687 : }
688 :
689 115155 : static bool is_builtin_domain(struct winbindd_domain *domain)
690 : {
691 120515 : if (strequal(domain->name, "BUILTIN") &&
692 5360 : sid_check_is_builtin(&domain->sid)) {
693 5360 : return true;
694 : }
695 :
696 109795 : return false;
697 : }
698 :
699 : /*
700 : fetch an entry from the cache, with a varargs key. auto-fetch the sequence
701 : number and return status
702 : */
703 : static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
704 : struct winbindd_domain *domain,
705 : const char *format, ...) PRINTF_ATTRIBUTE(3,4);
706 0 : static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
707 : struct winbindd_domain *domain,
708 : const char *format, ...)
709 : {
710 0 : va_list ap;
711 0 : char *kstr;
712 0 : struct cache_entry *centry;
713 0 : int ret;
714 :
715 0 : if (!winbindd_use_cache() ||
716 0 : is_my_own_sam_domain(domain) ||
717 0 : is_builtin_domain(domain)) {
718 0 : return NULL;
719 : }
720 :
721 0 : refresh_sequence_number(domain);
722 :
723 0 : va_start(ap, format);
724 0 : ret = vasprintf(&kstr, format, ap);
725 0 : va_end(ap);
726 :
727 0 : if (ret == -1) {
728 0 : return NULL;
729 : }
730 :
731 0 : centry = wcache_fetch_raw(kstr);
732 0 : if (centry == NULL) {
733 0 : free(kstr);
734 0 : return NULL;
735 : }
736 :
737 0 : if (centry_expired(domain, kstr, centry)) {
738 :
739 0 : DBG_DEBUG("wcache_fetch: entry %s expired for domain %s\n",
740 : kstr, domain->name );
741 :
742 0 : centry_free(centry);
743 0 : free(kstr);
744 0 : return NULL;
745 : }
746 :
747 0 : DBG_DEBUG("wcache_fetch: returning entry %s for domain %s\n",
748 : kstr, domain->name );
749 :
750 0 : free(kstr);
751 0 : return centry;
752 : }
753 :
754 : static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
755 0 : static void wcache_delete(const char *format, ...)
756 : {
757 0 : va_list ap;
758 0 : char *kstr;
759 0 : TDB_DATA key;
760 0 : int ret;
761 :
762 0 : va_start(ap, format);
763 0 : ret = vasprintf(&kstr, format, ap);
764 0 : va_end(ap);
765 :
766 0 : if (ret == -1) {
767 0 : return;
768 : }
769 :
770 0 : key = string_tdb_data(kstr);
771 :
772 0 : tdb_delete(wcache->tdb, key);
773 0 : free(kstr);
774 : }
775 :
776 : /*
777 : make sure we have at least len bytes available in a centry
778 : */
779 0 : static void centry_expand(struct cache_entry *centry, uint32_t len)
780 : {
781 0 : if (centry->len - centry->ofs >= len)
782 0 : return;
783 0 : centry->len *= 2;
784 0 : centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
785 : centry->len);
786 0 : if (!centry->data) {
787 0 : DBG_ERR("out of memory: needed %d bytes in centry_expand\n", centry->len);
788 0 : smb_panic_fn("out of memory in centry_expand");
789 : }
790 : }
791 :
792 : /*
793 : push a uint64_t into a centry
794 : */
795 0 : static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
796 : {
797 0 : centry_expand(centry, 8);
798 0 : SBVAL(centry->data, centry->ofs, v);
799 0 : centry->ofs += 8;
800 0 : }
801 :
802 : /*
803 : push a uint32_t into a centry
804 : */
805 0 : static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
806 : {
807 0 : centry_expand(centry, 4);
808 0 : SIVAL(centry->data, centry->ofs, v);
809 0 : centry->ofs += 4;
810 0 : }
811 :
812 : /*
813 : push a uint16_t into a centry
814 : */
815 0 : static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
816 : {
817 0 : centry_expand(centry, 2);
818 0 : SSVAL(centry->data, centry->ofs, v);
819 0 : centry->ofs += 2;
820 0 : }
821 :
822 : /*
823 : push a uint8_t into a centry
824 : */
825 0 : static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
826 : {
827 0 : centry_expand(centry, 1);
828 0 : SCVAL(centry->data, centry->ofs, v);
829 0 : centry->ofs += 1;
830 0 : }
831 :
832 : /*
833 : push a string into a centry
834 : */
835 0 : static void centry_put_string(struct cache_entry *centry, const char *s)
836 : {
837 0 : int len;
838 :
839 0 : if (!s) {
840 : /* null strings are marked as len 0xFFFF */
841 0 : centry_put_uint8(centry, 0xFF);
842 0 : return;
843 : }
844 :
845 0 : len = strlen(s);
846 : /* can't handle more than 254 char strings. Truncating is probably best */
847 0 : if (len > 254) {
848 0 : DBG_DEBUG("centry_put_string: truncating len (%d) to: 254\n", len);
849 0 : len = 254;
850 : }
851 0 : centry_put_uint8(centry, len);
852 0 : centry_expand(centry, len);
853 0 : memcpy(centry->data + centry->ofs, s, len);
854 0 : centry->ofs += len;
855 : }
856 :
857 : /*
858 : push a 16 byte hash into a centry - treat as 16 byte string.
859 : */
860 0 : static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
861 : {
862 0 : centry_put_uint8(centry, 16);
863 0 : centry_expand(centry, 16);
864 0 : memcpy(centry->data + centry->ofs, val, 16);
865 0 : centry->ofs += 16;
866 0 : }
867 :
868 0 : static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
869 : {
870 0 : struct dom_sid_buf sid_string;
871 0 : centry_put_string(centry, dom_sid_str_buf(sid, &sid_string));
872 0 : }
873 :
874 :
875 : /*
876 : put NTSTATUS into a centry
877 : */
878 0 : static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
879 : {
880 0 : uint32_t status_value = NT_STATUS_V(status);
881 0 : centry_put_uint32(centry, status_value);
882 0 : }
883 :
884 :
885 : /*
886 : push a NTTIME into a centry
887 : */
888 0 : static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
889 : {
890 0 : centry_expand(centry, 8);
891 0 : SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
892 0 : centry->ofs += 4;
893 0 : SIVAL(centry->data, centry->ofs, nt >> 32);
894 0 : centry->ofs += 4;
895 0 : }
896 :
897 : /*
898 : push a time_t into a centry - use a 64 bit size.
899 : NTTIME here is being used as a convenient 64-bit size.
900 : */
901 0 : static void centry_put_time(struct cache_entry *centry, time_t t)
902 : {
903 0 : NTTIME nt = (NTTIME)t;
904 0 : centry_put_nttime(centry, nt);
905 0 : }
906 :
907 : /*
908 : start a centry for output. When finished, call centry_end()
909 : */
910 0 : static struct cache_entry *centry_start(struct winbindd_domain *domain,
911 : NTSTATUS status)
912 : {
913 0 : struct cache_entry *centry;
914 :
915 0 : if (!wcache->tdb)
916 0 : return NULL;
917 :
918 0 : centry = SMB_XMALLOC_P(struct cache_entry);
919 :
920 0 : centry->len = 8192; /* reasonable default */
921 0 : centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
922 0 : centry->ofs = 0;
923 0 : centry->sequence_number = domain->sequence_number;
924 0 : centry->timeout = lp_winbind_cache_time() + time(NULL);
925 0 : centry_put_ntstatus(centry, status);
926 0 : centry_put_uint32(centry, centry->sequence_number);
927 0 : centry_put_uint64_t(centry, centry->timeout);
928 0 : return centry;
929 : }
930 :
931 : /*
932 : finish a centry and write it to the tdb
933 : */
934 : static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
935 0 : static void centry_end(struct cache_entry *centry, const char *format, ...)
936 : {
937 0 : va_list ap;
938 0 : char *kstr;
939 0 : TDB_DATA key, data;
940 0 : int ret;
941 :
942 0 : if (!winbindd_use_cache()) {
943 0 : return;
944 : }
945 :
946 0 : va_start(ap, format);
947 0 : ret = vasprintf(&kstr, format, ap);
948 0 : va_end(ap);
949 :
950 0 : if (ret == -1) {
951 0 : return;
952 : }
953 :
954 0 : key = string_tdb_data(kstr);
955 0 : data.dptr = centry->data;
956 0 : data.dsize = centry->ofs;
957 :
958 0 : tdb_store(wcache->tdb, key, data, TDB_REPLACE);
959 0 : free(kstr);
960 : }
961 :
962 882 : static void wcache_save_name_to_sid(struct winbindd_domain *domain,
963 : NTSTATUS status, const char *domain_name,
964 : const char *name, const struct dom_sid *sid,
965 : enum lsa_SidType type)
966 : {
967 0 : bool ok;
968 :
969 882 : ok = namemap_cache_set_name2sid(domain_name, name, sid, type,
970 882 : time(NULL) + lp_winbind_cache_time());
971 882 : if (!ok) {
972 0 : DBG_DEBUG("namemap_cache_set_name2sid failed\n");
973 : }
974 :
975 : /*
976 : * Don't store the reverse mapping. The name came from user
977 : * input, and we might not have the correct capitalization,
978 : * which is important for nsswitch.
979 : */
980 882 : }
981 :
982 0 : static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
983 : const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
984 : {
985 0 : bool ok;
986 :
987 0 : ok = namemap_cache_set_sid2name(sid, domain_name, name, type,
988 0 : time(NULL) + lp_winbind_cache_time());
989 0 : if (!ok) {
990 0 : DBG_DEBUG("namemap_cache_set_sid2name failed\n");
991 : }
992 :
993 0 : if (type != SID_NAME_UNKNOWN) {
994 0 : ok = namemap_cache_set_name2sid(
995 : domain_name, name, sid, type,
996 0 : time(NULL) + lp_winbind_cache_time());
997 0 : if (!ok) {
998 0 : DBG_DEBUG("namemap_cache_set_name2sid failed\n");
999 : }
1000 : }
1001 0 : }
1002 :
1003 0 : static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1004 : NTSTATUS status,
1005 : struct samr_DomInfo12 *lockout_policy)
1006 : {
1007 0 : struct cache_entry *centry;
1008 :
1009 0 : centry = centry_start(domain, status);
1010 0 : if (!centry)
1011 0 : return;
1012 :
1013 0 : centry_put_nttime(centry, lockout_policy->lockout_duration);
1014 0 : centry_put_nttime(centry, lockout_policy->lockout_window);
1015 0 : centry_put_uint16(centry, lockout_policy->lockout_threshold);
1016 :
1017 0 : centry_end(centry, "LOC_POL/%s", domain->name);
1018 :
1019 0 : DBG_DEBUG("wcache_save_lockout_policy: %s\n", domain->name);
1020 :
1021 0 : centry_free(centry);
1022 : }
1023 :
1024 :
1025 :
1026 0 : static void wcache_save_password_policy(struct winbindd_domain *domain,
1027 : NTSTATUS status,
1028 : struct samr_DomInfo1 *policy)
1029 : {
1030 0 : struct cache_entry *centry;
1031 :
1032 0 : centry = centry_start(domain, status);
1033 0 : if (!centry)
1034 0 : return;
1035 :
1036 0 : centry_put_uint16(centry, policy->min_password_length);
1037 0 : centry_put_uint16(centry, policy->password_history_length);
1038 0 : centry_put_uint32(centry, policy->password_properties);
1039 0 : centry_put_nttime(centry, policy->max_password_age);
1040 0 : centry_put_nttime(centry, policy->min_password_age);
1041 :
1042 0 : centry_end(centry, "PWD_POL/%s", domain->name);
1043 :
1044 0 : DBG_DEBUG("wcache_save_password_policy: %s\n", domain->name);
1045 :
1046 0 : centry_free(centry);
1047 : }
1048 :
1049 : /***************************************************************************
1050 : ***************************************************************************/
1051 :
1052 0 : static void wcache_save_username_alias(struct winbindd_domain *domain,
1053 : NTSTATUS status,
1054 : const char *name, const char *alias)
1055 : {
1056 0 : struct cache_entry *centry;
1057 0 : fstring uname;
1058 :
1059 0 : if ( (centry = centry_start(domain, status)) == NULL )
1060 0 : return;
1061 :
1062 0 : centry_put_string( centry, alias );
1063 :
1064 0 : fstrcpy(uname, name);
1065 0 : (void)strupper_m(uname);
1066 0 : centry_end(centry, "NSS/NA/%s", uname);
1067 :
1068 0 : DBG_DEBUG("wcache_save_username_alias: %s -> %s\n", name, alias );
1069 :
1070 0 : centry_free(centry);
1071 : }
1072 :
1073 0 : static void wcache_save_alias_username(struct winbindd_domain *domain,
1074 : NTSTATUS status,
1075 : const char *alias, const char *name)
1076 : {
1077 0 : struct cache_entry *centry;
1078 0 : fstring uname;
1079 :
1080 0 : if ( (centry = centry_start(domain, status)) == NULL )
1081 0 : return;
1082 :
1083 0 : centry_put_string( centry, name );
1084 :
1085 0 : fstrcpy(uname, alias);
1086 0 : (void)strupper_m(uname);
1087 0 : centry_end(centry, "NSS/AN/%s", uname);
1088 :
1089 0 : DBG_DEBUG("wcache_save_alias_username: %s -> %s\n", alias, name );
1090 :
1091 0 : centry_free(centry);
1092 : }
1093 :
1094 : /***************************************************************************
1095 : ***************************************************************************/
1096 :
1097 0 : NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1098 : struct winbindd_domain *domain,
1099 : const char *name, char **alias )
1100 : {
1101 0 : struct winbind_cache *cache = get_cache(domain);
1102 0 : struct cache_entry *centry = NULL;
1103 0 : NTSTATUS status;
1104 0 : char *upper_name;
1105 :
1106 0 : if ( domain->internal )
1107 0 : return NT_STATUS_NOT_SUPPORTED;
1108 :
1109 0 : if (!cache->tdb)
1110 0 : goto do_query;
1111 :
1112 0 : upper_name = talloc_strdup_upper(mem_ctx, name);
1113 0 : if (upper_name == NULL) {
1114 0 : return NT_STATUS_NO_MEMORY;
1115 : }
1116 :
1117 0 : centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1118 :
1119 0 : talloc_free(upper_name);
1120 :
1121 0 : if (!centry)
1122 0 : goto do_query;
1123 :
1124 0 : status = centry->status;
1125 :
1126 0 : if (!NT_STATUS_IS_OK(status)) {
1127 0 : centry_free(centry);
1128 0 : return status;
1129 : }
1130 :
1131 0 : *alias = centry_string( centry, mem_ctx );
1132 :
1133 0 : centry_free(centry);
1134 :
1135 0 : DBG_DEBUG("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1136 : name, *alias ? *alias : "(none)");
1137 :
1138 0 : return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1139 :
1140 0 : do_query:
1141 :
1142 : /* If its not in cache and we are offline, then fail */
1143 :
1144 0 : if (is_domain_offline(domain)) {
1145 0 : DBG_DEBUG("resolve_username_to_alias: rejecting query "
1146 : "in offline mode\n");
1147 0 : return NT_STATUS_NOT_FOUND;
1148 : }
1149 :
1150 0 : status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1151 :
1152 0 : if ( NT_STATUS_IS_OK( status ) ) {
1153 0 : wcache_save_username_alias(domain, status, name, *alias);
1154 : }
1155 :
1156 0 : if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1157 0 : wcache_save_username_alias(domain, status, name, "(NULL)");
1158 : }
1159 :
1160 0 : DBG_INFO("resolve_username_to_alias: backend query returned %s\n",
1161 : nt_errstr(status));
1162 :
1163 0 : if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1164 0 : set_domain_offline( domain );
1165 : }
1166 :
1167 0 : return status;
1168 : }
1169 :
1170 : /***************************************************************************
1171 : ***************************************************************************/
1172 :
1173 0 : NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1174 : struct winbindd_domain *domain,
1175 : const char *alias, char **name )
1176 : {
1177 0 : struct winbind_cache *cache = get_cache(domain);
1178 0 : struct cache_entry *centry = NULL;
1179 0 : NTSTATUS status;
1180 0 : char *upper_name;
1181 :
1182 0 : if ( domain->internal )
1183 0 : return NT_STATUS_NOT_SUPPORTED;
1184 :
1185 0 : if (!cache->tdb)
1186 0 : goto do_query;
1187 :
1188 0 : upper_name = talloc_strdup(mem_ctx, alias);
1189 0 : if (upper_name == NULL) {
1190 0 : return NT_STATUS_NO_MEMORY;
1191 : }
1192 0 : if (!strupper_m(upper_name)) {
1193 0 : talloc_free(upper_name);
1194 0 : return NT_STATUS_INVALID_PARAMETER;
1195 : }
1196 :
1197 0 : centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1198 :
1199 0 : talloc_free(upper_name);
1200 :
1201 0 : if (!centry)
1202 0 : goto do_query;
1203 :
1204 0 : status = centry->status;
1205 :
1206 0 : if (!NT_STATUS_IS_OK(status)) {
1207 0 : centry_free(centry);
1208 0 : return status;
1209 : }
1210 :
1211 0 : *name = centry_string( centry, mem_ctx );
1212 :
1213 0 : centry_free(centry);
1214 :
1215 0 : DBG_DEBUG("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1216 : alias, *name ? *name : "(none)");
1217 :
1218 0 : return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1219 :
1220 0 : do_query:
1221 :
1222 : /* If its not in cache and we are offline, then fail */
1223 :
1224 0 : if (is_domain_offline(domain)) {
1225 0 : DBG_DEBUG("resolve_alias_to_username: rejecting query "
1226 : "in offline mode\n");
1227 0 : return NT_STATUS_NOT_FOUND;
1228 : }
1229 :
1230 : /* an alias cannot contain a domain prefix or '@' */
1231 :
1232 0 : if (strchr(alias, '\\') || strchr(alias, '@')) {
1233 0 : DBG_DEBUG("resolve_alias_to_username: skipping fully "
1234 : "qualified name %s\n", alias);
1235 0 : return NT_STATUS_OBJECT_NAME_INVALID;
1236 : }
1237 :
1238 0 : status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1239 :
1240 0 : if ( NT_STATUS_IS_OK( status ) ) {
1241 0 : wcache_save_alias_username( domain, status, alias, *name );
1242 : }
1243 :
1244 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1245 0 : wcache_save_alias_username(domain, status, alias, "(NULL)");
1246 : }
1247 :
1248 0 : DBG_INFO("resolve_alias_to_username: backend query returned %s\n",
1249 : nt_errstr(status));
1250 :
1251 0 : if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1252 0 : set_domain_offline( domain );
1253 : }
1254 :
1255 0 : return status;
1256 : }
1257 :
1258 0 : NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1259 : {
1260 0 : struct winbind_cache *cache = get_cache(domain);
1261 0 : int ret;
1262 0 : struct dom_sid_buf tmp;
1263 0 : fstring key_str;
1264 0 : uint32_t rid;
1265 :
1266 0 : if (!cache->tdb) {
1267 0 : return NT_STATUS_INTERNAL_DB_ERROR;
1268 : }
1269 :
1270 0 : if (is_null_sid(sid)) {
1271 0 : return NT_STATUS_INVALID_SID;
1272 : }
1273 :
1274 0 : if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1275 0 : return NT_STATUS_INVALID_SID;
1276 : }
1277 :
1278 0 : fstr_sprintf(key_str, "CRED/%s", dom_sid_str_buf(sid, &tmp));
1279 :
1280 0 : ret = tdb_exists(cache->tdb, string_tdb_data(key_str));
1281 0 : if (ret != 1) {
1282 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1283 : }
1284 :
1285 0 : return NT_STATUS_OK;
1286 : }
1287 :
1288 : /* Lookup creds for a SID - copes with old (unsalted) creds as well
1289 : as new salted ones. */
1290 :
1291 0 : NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1292 : TALLOC_CTX *mem_ctx,
1293 : const struct dom_sid *sid,
1294 : const uint8_t **cached_nt_pass,
1295 : const uint8_t **cached_salt)
1296 : {
1297 0 : struct winbind_cache *cache = get_cache(domain);
1298 0 : struct cache_entry *centry = NULL;
1299 0 : NTSTATUS status;
1300 0 : uint32_t rid;
1301 0 : struct dom_sid_buf sidstr;
1302 :
1303 0 : if (!cache->tdb) {
1304 0 : return NT_STATUS_INTERNAL_DB_ERROR;
1305 : }
1306 :
1307 0 : if (is_null_sid(sid)) {
1308 0 : return NT_STATUS_INVALID_SID;
1309 : }
1310 :
1311 0 : if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1312 0 : return NT_STATUS_INVALID_SID;
1313 : }
1314 :
1315 : /* Try and get a salted cred first. If we can't
1316 : fall back to an unsalted cred. */
1317 :
1318 0 : centry = wcache_fetch(cache, domain, "CRED/%s",
1319 : dom_sid_str_buf(sid, &sidstr));
1320 0 : if (!centry) {
1321 0 : DBG_DEBUG("wcache_get_creds: entry for [CRED/%s] not found\n",
1322 : dom_sid_str_buf(sid, &sidstr));
1323 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1324 : }
1325 :
1326 : /*
1327 : * We don't use the time element at this moment,
1328 : * but we have to consume it, so that we don't
1329 : * need to change the disk format of the cache.
1330 : */
1331 0 : (void)centry_time(centry);
1332 :
1333 : /* In the salted case this isn't actually the nt_hash itself,
1334 : but the MD5 of the salt + nt_hash. Let the caller
1335 : sort this out. It can tell as we only return the cached_salt
1336 : if we are returning a salted cred. */
1337 :
1338 0 : *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1339 0 : if (*cached_nt_pass == NULL) {
1340 :
1341 0 : dom_sid_str_buf(sid, &sidstr);
1342 :
1343 : /* Bad (old) cred cache. Delete and pretend we
1344 : don't have it. */
1345 0 : DBG_WARNING("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1346 : sidstr.buf);
1347 0 : wcache_delete("CRED/%s", sidstr.buf);
1348 0 : centry_free(centry);
1349 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1350 : }
1351 :
1352 : /* We only have 17 bytes more data in the salted cred case. */
1353 0 : if (centry->len - centry->ofs == 17) {
1354 0 : *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1355 : } else {
1356 0 : *cached_salt = NULL;
1357 : }
1358 :
1359 0 : dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1360 0 : if (*cached_salt) {
1361 0 : dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1362 : }
1363 :
1364 0 : status = centry->status;
1365 :
1366 0 : DBG_DEBUG("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1367 : dom_sid_str_buf(sid, &sidstr),
1368 : nt_errstr(status) );
1369 :
1370 0 : centry_free(centry);
1371 0 : return status;
1372 : }
1373 :
1374 : /* Store creds for a SID - only writes out new salted ones. */
1375 :
1376 0 : NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1377 : const struct dom_sid *sid,
1378 : const uint8_t nt_pass[NT_HASH_LEN])
1379 : {
1380 0 : struct cache_entry *centry;
1381 0 : struct dom_sid_buf sid_str;
1382 0 : uint32_t rid;
1383 0 : uint8_t cred_salt[NT_HASH_LEN];
1384 0 : uint8_t salted_hash[NT_HASH_LEN];
1385 0 : gnutls_hash_hd_t hash_hnd = NULL;
1386 0 : int rc;
1387 :
1388 0 : if (is_null_sid(sid)) {
1389 0 : return NT_STATUS_INVALID_SID;
1390 : }
1391 :
1392 0 : if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1393 0 : return NT_STATUS_INVALID_SID;
1394 : }
1395 :
1396 0 : centry = centry_start(domain, NT_STATUS_OK);
1397 0 : if (!centry) {
1398 0 : return NT_STATUS_INTERNAL_DB_ERROR;
1399 : }
1400 :
1401 0 : dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1402 :
1403 0 : centry_put_time(centry, time(NULL));
1404 :
1405 : /* Create a salt and then salt the hash. */
1406 0 : generate_random_buffer(cred_salt, NT_HASH_LEN);
1407 :
1408 0 : rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
1409 0 : if (rc < 0) {
1410 0 : centry_free(centry);
1411 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
1412 : }
1413 :
1414 0 : rc = gnutls_hash(hash_hnd, cred_salt, 16);
1415 0 : if (rc < 0) {
1416 0 : gnutls_hash_deinit(hash_hnd, NULL);
1417 0 : centry_free(centry);
1418 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
1419 : }
1420 0 : rc = gnutls_hash(hash_hnd, nt_pass, 16);
1421 0 : if (rc < 0) {
1422 0 : gnutls_hash_deinit(hash_hnd, NULL);
1423 0 : centry_free(centry);
1424 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
1425 : }
1426 0 : gnutls_hash_deinit(hash_hnd, salted_hash);
1427 :
1428 0 : centry_put_hash16(centry, salted_hash);
1429 0 : centry_put_hash16(centry, cred_salt);
1430 0 : centry_end(centry, "CRED/%s", dom_sid_str_buf(sid, &sid_str));
1431 :
1432 0 : DBG_DEBUG("wcache_save_creds: %s\n", sid_str.buf);
1433 :
1434 0 : centry_free(centry);
1435 :
1436 0 : return NT_STATUS_OK;
1437 : }
1438 :
1439 :
1440 : /* Query display info. This is the basic user list fn */
1441 0 : NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1442 : TALLOC_CTX *mem_ctx,
1443 : uint32_t **prids)
1444 : {
1445 0 : struct winbind_cache *cache = get_cache(domain);
1446 0 : struct cache_entry *centry = NULL;
1447 0 : uint32_t num_rids = 0;
1448 0 : uint32_t *rids = NULL;
1449 0 : NTSTATUS status;
1450 0 : unsigned int i, retry;
1451 0 : bool old_status = domain->online;
1452 :
1453 0 : *prids = NULL;
1454 :
1455 0 : if (!cache->tdb)
1456 0 : goto do_query;
1457 :
1458 0 : centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1459 0 : if (!centry)
1460 0 : goto do_query;
1461 :
1462 0 : do_fetch_cache:
1463 0 : num_rids = centry_uint32(centry);
1464 :
1465 0 : if (num_rids == 0) {
1466 0 : goto do_cached;
1467 : }
1468 :
1469 0 : rids = talloc_array(mem_ctx, uint32_t, num_rids);
1470 0 : if (rids == NULL) {
1471 0 : centry_free(centry);
1472 0 : return NT_STATUS_NO_MEMORY;
1473 : }
1474 :
1475 0 : for (i=0; i<num_rids; i++) {
1476 0 : rids[i] = centry_uint32(centry);
1477 : }
1478 :
1479 0 : do_cached:
1480 0 : status = centry->status;
1481 :
1482 0 : DBG_DEBUG("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1483 : domain->name, nt_errstr(status) );
1484 :
1485 0 : centry_free(centry);
1486 0 : return status;
1487 :
1488 0 : do_query:
1489 :
1490 : /* Put the query_user_list() in a retry loop. There appears to be
1491 : * some bug either with Windows 2000 or Samba's handling of large
1492 : * rpc replies. This manifests itself as sudden disconnection
1493 : * at a random point in the enumeration of a large (60k) user list.
1494 : * The retry loop simply tries the operation again. )-: It's not
1495 : * pretty but an acceptable workaround until we work out what the
1496 : * real problem is. */
1497 :
1498 0 : retry = 0;
1499 0 : do {
1500 :
1501 0 : DBG_DEBUG("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1502 : domain->name );
1503 :
1504 0 : rids = NULL;
1505 0 : status = domain->backend->query_user_list(domain, mem_ctx,
1506 : &rids);
1507 0 : num_rids = talloc_array_length(rids);
1508 :
1509 0 : if (!NT_STATUS_IS_OK(status)) {
1510 0 : DBG_NOTICE("query_user_list: returned 0x%08x, "
1511 : "retrying\n", NT_STATUS_V(status));
1512 : }
1513 0 : reset_cm_connection_on_error(domain, NULL, status);
1514 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1515 0 : DBG_NOTICE("query_user_list: flushing "
1516 : "connection cache\n");
1517 0 : invalidate_cm_connection(domain);
1518 : }
1519 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1520 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1521 0 : if (!domain->internal && old_status) {
1522 0 : set_domain_offline(domain);
1523 : }
1524 : /* store partial response. */
1525 0 : if (num_rids > 0) {
1526 : /*
1527 : * humm, what about the status used for cache?
1528 : * Should it be NT_STATUS_OK?
1529 : */
1530 0 : break;
1531 : }
1532 : /*
1533 : * domain is offline now, and there is no user entries,
1534 : * try to fetch from cache again.
1535 : */
1536 0 : if (cache->tdb && !domain->online && !domain->internal && old_status) {
1537 0 : centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1538 : /* partial response... */
1539 0 : if (!centry) {
1540 0 : goto skip_save;
1541 : } else {
1542 0 : goto do_fetch_cache;
1543 : }
1544 : } else {
1545 0 : goto skip_save;
1546 : }
1547 : }
1548 :
1549 0 : } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1550 0 : (retry++ < 5));
1551 :
1552 : /* and save it */
1553 0 : refresh_sequence_number(domain);
1554 0 : if (!NT_STATUS_IS_OK(status)) {
1555 0 : return status;
1556 : }
1557 0 : centry = centry_start(domain, status);
1558 0 : if (!centry)
1559 0 : goto skip_save;
1560 0 : centry_put_uint32(centry, num_rids);
1561 0 : for (i=0; i<num_rids; i++) {
1562 0 : centry_put_uint32(centry, rids[i]);
1563 : }
1564 0 : centry_end(centry, "UL/%s", domain->name);
1565 0 : centry_free(centry);
1566 :
1567 0 : *prids = rids;
1568 :
1569 0 : skip_save:
1570 0 : return status;
1571 : }
1572 :
1573 : /* list all domain groups */
1574 0 : NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1575 : TALLOC_CTX *mem_ctx,
1576 : uint32_t *num_entries,
1577 : struct wb_acct_info **info)
1578 : {
1579 0 : struct winbind_cache *cache = get_cache(domain);
1580 0 : struct cache_entry *centry = NULL;
1581 0 : NTSTATUS status;
1582 0 : unsigned int i;
1583 0 : bool old_status;
1584 :
1585 0 : old_status = domain->online;
1586 0 : if (!cache->tdb)
1587 0 : goto do_query;
1588 :
1589 0 : centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1590 0 : if (!centry)
1591 0 : goto do_query;
1592 :
1593 0 : do_fetch_cache:
1594 0 : *num_entries = centry_uint32(centry);
1595 :
1596 0 : if (*num_entries == 0)
1597 0 : goto do_cached;
1598 :
1599 0 : (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1600 0 : if (! (*info)) {
1601 0 : smb_panic_fn("enum_dom_groups out of memory");
1602 : }
1603 0 : for (i=0; i<(*num_entries); i++) {
1604 0 : (*info)[i].acct_name = centry_string(centry, (*info));
1605 0 : (*info)[i].acct_desc = centry_string(centry, (*info));
1606 0 : (*info)[i].rid = centry_uint32(centry);
1607 : }
1608 :
1609 0 : do_cached:
1610 0 : status = centry->status;
1611 :
1612 0 : DBG_DEBUG("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1613 : domain->name, nt_errstr(status) );
1614 :
1615 0 : centry_free(centry);
1616 0 : return status;
1617 :
1618 0 : do_query:
1619 0 : *num_entries = 0;
1620 0 : *info = NULL;
1621 :
1622 0 : DBG_DEBUG("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1623 : domain->name );
1624 :
1625 0 : status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1626 :
1627 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1628 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1629 0 : if (!domain->internal && old_status) {
1630 0 : set_domain_offline(domain);
1631 : }
1632 0 : if (cache->tdb &&
1633 0 : !domain->online &&
1634 0 : !domain->internal &&
1635 : old_status) {
1636 0 : centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1637 0 : if (centry) {
1638 0 : goto do_fetch_cache;
1639 : }
1640 : }
1641 : }
1642 : /* and save it */
1643 0 : refresh_sequence_number(domain);
1644 0 : if (!NT_STATUS_IS_OK(status)) {
1645 0 : return status;
1646 : }
1647 0 : centry = centry_start(domain, status);
1648 0 : if (!centry)
1649 0 : goto skip_save;
1650 0 : centry_put_uint32(centry, *num_entries);
1651 0 : for (i=0; i<(*num_entries); i++) {
1652 0 : centry_put_string(centry, (*info)[i].acct_name);
1653 0 : centry_put_string(centry, (*info)[i].acct_desc);
1654 0 : centry_put_uint32(centry, (*info)[i].rid);
1655 : }
1656 0 : centry_end(centry, "GL/%s/domain", domain->name);
1657 0 : centry_free(centry);
1658 :
1659 0 : skip_save:
1660 0 : return status;
1661 : }
1662 :
1663 : /* list all domain groups */
1664 0 : NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1665 : TALLOC_CTX *mem_ctx,
1666 : uint32_t *num_entries,
1667 : struct wb_acct_info **info)
1668 : {
1669 0 : struct winbind_cache *cache = get_cache(domain);
1670 0 : struct cache_entry *centry = NULL;
1671 0 : NTSTATUS status;
1672 0 : unsigned int i;
1673 0 : bool old_status;
1674 :
1675 0 : old_status = domain->online;
1676 0 : if (!cache->tdb)
1677 0 : goto do_query;
1678 :
1679 0 : centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1680 0 : if (!centry)
1681 0 : goto do_query;
1682 :
1683 0 : do_fetch_cache:
1684 0 : *num_entries = centry_uint32(centry);
1685 :
1686 0 : if (*num_entries == 0)
1687 0 : goto do_cached;
1688 :
1689 0 : (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1690 0 : if (! (*info)) {
1691 0 : smb_panic_fn("enum_dom_groups out of memory");
1692 : }
1693 0 : for (i=0; i<(*num_entries); i++) {
1694 0 : (*info)[i].acct_name = centry_string(centry, (*info));
1695 0 : (*info)[i].acct_desc = centry_string(centry, (*info));
1696 0 : (*info)[i].rid = centry_uint32(centry);
1697 : }
1698 :
1699 0 : do_cached:
1700 :
1701 : /* If we are returning cached data and the domain controller
1702 : is down then we don't know whether the data is up to date
1703 : or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1704 : indicate this. */
1705 :
1706 0 : if (wcache_server_down(domain)) {
1707 0 : DBG_DEBUG("enum_local_groups: returning cached user list and server was down\n");
1708 0 : status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1709 : } else
1710 0 : status = centry->status;
1711 :
1712 0 : DBG_DEBUG("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1713 : domain->name, nt_errstr(status) );
1714 :
1715 0 : centry_free(centry);
1716 0 : return status;
1717 :
1718 0 : do_query:
1719 0 : *num_entries = 0;
1720 0 : *info = NULL;
1721 :
1722 0 : DBG_DEBUG("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1723 : domain->name );
1724 :
1725 0 : status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1726 :
1727 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1728 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1729 0 : if (!domain->internal && old_status) {
1730 0 : set_domain_offline(domain);
1731 : }
1732 0 : if (cache->tdb &&
1733 0 : !domain->internal &&
1734 0 : !domain->online &&
1735 : old_status) {
1736 0 : centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1737 0 : if (centry) {
1738 0 : goto do_fetch_cache;
1739 : }
1740 : }
1741 : }
1742 : /* and save it */
1743 0 : refresh_sequence_number(domain);
1744 0 : if (!NT_STATUS_IS_OK(status)) {
1745 0 : return status;
1746 : }
1747 0 : centry = centry_start(domain, status);
1748 0 : if (!centry)
1749 0 : goto skip_save;
1750 0 : centry_put_uint32(centry, *num_entries);
1751 0 : for (i=0; i<(*num_entries); i++) {
1752 0 : centry_put_string(centry, (*info)[i].acct_name);
1753 0 : centry_put_string(centry, (*info)[i].acct_desc);
1754 0 : centry_put_uint32(centry, (*info)[i].rid);
1755 : }
1756 0 : centry_end(centry, "GL/%s/local", domain->name);
1757 0 : centry_free(centry);
1758 :
1759 0 : skip_save:
1760 0 : return status;
1761 : }
1762 :
1763 : struct wcache_name_to_sid_state {
1764 : struct dom_sid *sid;
1765 : enum lsa_SidType *type;
1766 : bool offline;
1767 : bool found;
1768 : };
1769 :
1770 0 : static void wcache_name_to_sid_fn(const struct dom_sid *sid,
1771 : enum lsa_SidType type,
1772 : bool expired,
1773 : void *private_data)
1774 : {
1775 0 : struct wcache_name_to_sid_state *state = private_data;
1776 :
1777 0 : *state->sid = *sid;
1778 0 : *state->type = type;
1779 0 : state->found = (!expired || state->offline);
1780 0 : }
1781 :
1782 0 : static NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1783 : const char *domain_name,
1784 : const char *name,
1785 : struct dom_sid *sid,
1786 : enum lsa_SidType *type)
1787 : {
1788 0 : struct wcache_name_to_sid_state state = {
1789 : .sid = sid, .type = type, .found = false,
1790 0 : .offline = is_domain_offline(domain),
1791 : };
1792 0 : bool ok;
1793 :
1794 0 : ok = namemap_cache_find_name(domain_name, name, wcache_name_to_sid_fn,
1795 : &state);
1796 0 : if (!ok) {
1797 0 : DBG_DEBUG("namemap_cache_find_name failed\n");
1798 0 : return NT_STATUS_NOT_FOUND;
1799 : }
1800 0 : if (!state.found) {
1801 0 : DBG_DEBUG("cache entry not found\n");
1802 0 : return NT_STATUS_NOT_FOUND;
1803 : }
1804 0 : if (*type == SID_NAME_UNKNOWN) {
1805 0 : return NT_STATUS_NONE_MAPPED;
1806 : }
1807 :
1808 0 : return NT_STATUS_OK;
1809 : }
1810 :
1811 : /* convert a single name to a sid in a domain */
1812 0 : NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1813 : TALLOC_CTX *mem_ctx,
1814 : const char *domain_name,
1815 : const char *name,
1816 : uint32_t flags,
1817 : struct dom_sid *sid,
1818 : enum lsa_SidType *type)
1819 : {
1820 0 : NTSTATUS status;
1821 0 : bool old_status;
1822 0 : const char *dom_name;
1823 :
1824 0 : old_status = domain->online;
1825 :
1826 0 : status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1827 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1828 0 : return status;
1829 : }
1830 :
1831 0 : ZERO_STRUCTP(sid);
1832 :
1833 0 : DBG_DEBUG("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1834 : domain->name );
1835 :
1836 0 : winbindd_domain_init_backend(domain);
1837 0 : status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1838 : name, flags, &dom_name, sid, type);
1839 :
1840 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1841 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1842 0 : if (!domain->internal && old_status) {
1843 0 : set_domain_offline(domain);
1844 : }
1845 0 : if (!domain->internal &&
1846 0 : !domain->online &&
1847 : old_status) {
1848 0 : NTSTATUS cache_status;
1849 0 : cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1850 0 : return cache_status;
1851 : }
1852 : }
1853 : /* and save it */
1854 :
1855 0 : if (domain->online &&
1856 0 : (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1857 0 : enum lsa_SidType save_type = *type;
1858 :
1859 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1860 0 : save_type = SID_NAME_UNKNOWN;
1861 : }
1862 :
1863 0 : wcache_save_name_to_sid(domain, status, domain_name, name, sid,
1864 : save_type);
1865 :
1866 : /* Only save the reverse mapping if this was not a UPN */
1867 0 : if (!strchr(name, '@')) {
1868 0 : if (!strupper_m(discard_const_p(char, domain_name))) {
1869 0 : return NT_STATUS_INVALID_PARAMETER;
1870 : }
1871 0 : (void)strlower_m(discard_const_p(char, name));
1872 0 : wcache_save_sid_to_name(domain, status, sid,
1873 : dom_name, name, save_type);
1874 : }
1875 : }
1876 :
1877 0 : return status;
1878 : }
1879 :
1880 : struct wcache_sid_to_name_state {
1881 : TALLOC_CTX *mem_ctx;
1882 : char **domain_name;
1883 : char **name;
1884 : enum lsa_SidType *type;
1885 : bool offline;
1886 : bool found;
1887 : };
1888 :
1889 0 : static void wcache_sid_to_name_fn(const char *domain,
1890 : const char *name,
1891 : enum lsa_SidType type,
1892 : bool expired,
1893 : void *private_data)
1894 : {
1895 0 : struct wcache_sid_to_name_state *state = private_data;
1896 :
1897 0 : *state->domain_name = talloc_strdup(state->mem_ctx, domain);
1898 0 : if (*state->domain_name == NULL) {
1899 0 : return;
1900 : }
1901 0 : *state->name = talloc_strdup(state->mem_ctx, name);
1902 0 : if (*state->name == NULL) {
1903 0 : return;
1904 : }
1905 0 : *state->type = type;
1906 0 : state->found = (!expired || state->offline);
1907 : }
1908 :
1909 0 : static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1910 : const struct dom_sid *sid,
1911 : TALLOC_CTX *mem_ctx,
1912 : char **domain_name,
1913 : char **name,
1914 : enum lsa_SidType *type)
1915 : {
1916 0 : struct wcache_sid_to_name_state state = {
1917 : .mem_ctx = mem_ctx, .found = false,
1918 : .domain_name = domain_name, .name = name, .type = type,
1919 0 : .offline = is_domain_offline(domain)
1920 : };
1921 0 : bool ok;
1922 :
1923 0 : ok = namemap_cache_find_sid(sid, wcache_sid_to_name_fn, &state);
1924 0 : if (!ok) {
1925 0 : DBG_DEBUG("namemap_cache_find_name failed\n");
1926 0 : return NT_STATUS_NOT_FOUND;
1927 : }
1928 0 : if (!state.found) {
1929 0 : DBG_DEBUG("cache entry not found\n");
1930 0 : return NT_STATUS_NOT_FOUND;
1931 : }
1932 0 : if (*type == SID_NAME_UNKNOWN) {
1933 0 : return NT_STATUS_NONE_MAPPED;
1934 : }
1935 :
1936 0 : return NT_STATUS_OK;
1937 : }
1938 :
1939 : /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1940 : given */
1941 0 : NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1942 : TALLOC_CTX *mem_ctx,
1943 : const struct dom_sid *sid,
1944 : char **domain_name,
1945 : char **name,
1946 : enum lsa_SidType *type)
1947 : {
1948 0 : NTSTATUS status;
1949 0 : bool old_status;
1950 :
1951 0 : old_status = domain->online;
1952 0 : status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1953 : type);
1954 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1955 0 : return status;
1956 : }
1957 :
1958 0 : *name = NULL;
1959 0 : *domain_name = NULL;
1960 :
1961 0 : DBG_DEBUG("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1962 : domain->name );
1963 :
1964 0 : winbindd_domain_init_backend(domain);
1965 :
1966 0 : status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1967 :
1968 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1969 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1970 0 : if (!domain->internal && old_status) {
1971 0 : set_domain_offline(domain);
1972 : }
1973 0 : if (!domain->internal &&
1974 0 : !domain->online &&
1975 : old_status) {
1976 0 : NTSTATUS cache_status;
1977 0 : cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1978 : domain_name, name, type);
1979 0 : return cache_status;
1980 : }
1981 : }
1982 : /* and save it */
1983 0 : if (!NT_STATUS_IS_OK(status)) {
1984 0 : return status;
1985 : }
1986 0 : wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1987 :
1988 : /* We can't save the name to sid mapping here, as with sid history a
1989 : * later name2sid would give the wrong sid. */
1990 :
1991 0 : return status;
1992 : }
1993 :
1994 0 : NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
1995 : TALLOC_CTX *mem_ctx,
1996 : const struct dom_sid *domain_sid,
1997 : uint32_t *rids,
1998 : size_t num_rids,
1999 : char **domain_name,
2000 : char ***names,
2001 : enum lsa_SidType **types)
2002 : {
2003 0 : struct winbind_cache *cache = get_cache(domain);
2004 0 : size_t i;
2005 0 : NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2006 0 : bool have_mapped;
2007 0 : bool have_unmapped;
2008 0 : bool old_status;
2009 :
2010 0 : old_status = domain->online;
2011 0 : *domain_name = NULL;
2012 0 : *names = NULL;
2013 0 : *types = NULL;
2014 :
2015 0 : if (!cache->tdb) {
2016 0 : goto do_query;
2017 : }
2018 :
2019 0 : if (num_rids == 0) {
2020 0 : return NT_STATUS_OK;
2021 : }
2022 :
2023 0 : *names = talloc_array(mem_ctx, char *, num_rids);
2024 0 : *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2025 :
2026 0 : if ((*names == NULL) || (*types == NULL)) {
2027 0 : result = NT_STATUS_NO_MEMORY;
2028 0 : goto error;
2029 : }
2030 :
2031 0 : have_mapped = have_unmapped = false;
2032 :
2033 0 : for (i=0; i<num_rids; i++) {
2034 0 : struct dom_sid sid;
2035 0 : NTSTATUS status;
2036 0 : enum lsa_SidType type;
2037 0 : char *dom, *name;
2038 :
2039 0 : if (!sid_compose(&sid, domain_sid, rids[i])) {
2040 0 : result = NT_STATUS_INTERNAL_ERROR;
2041 0 : goto error;
2042 : }
2043 :
2044 0 : status = wcache_sid_to_name(domain, &sid, *names, &dom,
2045 : &name, &type);
2046 :
2047 0 : (*types)[i] = SID_NAME_UNKNOWN;
2048 0 : (*names)[i] = talloc_strdup(*names, "");
2049 :
2050 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2051 : /* not cached */
2052 0 : goto do_query;
2053 : }
2054 :
2055 0 : if (NT_STATUS_IS_OK(status)) {
2056 0 : have_mapped = true;
2057 0 : (*types)[i] = type;
2058 :
2059 0 : if (*domain_name == NULL) {
2060 0 : *domain_name = dom;
2061 : } else {
2062 0 : TALLOC_FREE(dom);
2063 : }
2064 :
2065 0 : (*names)[i] = name;
2066 :
2067 0 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
2068 0 : have_unmapped = true;
2069 : } else {
2070 : /* something's definitely wrong */
2071 0 : result = status;
2072 0 : goto error;
2073 : }
2074 : }
2075 :
2076 0 : if (!have_mapped) {
2077 0 : return NT_STATUS_NONE_MAPPED;
2078 : }
2079 0 : if (!have_unmapped) {
2080 0 : return NT_STATUS_OK;
2081 : }
2082 0 : return STATUS_SOME_UNMAPPED;
2083 :
2084 0 : do_query:
2085 :
2086 0 : TALLOC_FREE(*names);
2087 0 : TALLOC_FREE(*types);
2088 :
2089 0 : result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2090 : rids, num_rids, domain_name,
2091 : names, types);
2092 :
2093 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2094 0 : NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2095 0 : if (!domain->internal && old_status) {
2096 0 : set_domain_offline(domain);
2097 : }
2098 0 : if (cache->tdb &&
2099 0 : !domain->internal &&
2100 0 : !domain->online &&
2101 : old_status) {
2102 0 : have_mapped = have_unmapped = false;
2103 :
2104 0 : *names = talloc_array(mem_ctx, char *, num_rids);
2105 0 : if (*names == NULL) {
2106 0 : result = NT_STATUS_NO_MEMORY;
2107 0 : goto error;
2108 : }
2109 :
2110 0 : *types = talloc_array(mem_ctx, enum lsa_SidType,
2111 : num_rids);
2112 0 : if (*types == NULL) {
2113 0 : result = NT_STATUS_NO_MEMORY;
2114 0 : goto error;
2115 : }
2116 :
2117 0 : for (i=0; i<num_rids; i++) {
2118 0 : struct dom_sid sid;
2119 0 : NTSTATUS status;
2120 0 : enum lsa_SidType type;
2121 0 : char *dom, *name;
2122 :
2123 0 : if (!sid_compose(&sid, domain_sid, rids[i])) {
2124 0 : result = NT_STATUS_INTERNAL_ERROR;
2125 0 : goto error;
2126 : }
2127 :
2128 0 : status = wcache_sid_to_name(domain, &sid,
2129 : *names, &dom,
2130 : &name, &type);
2131 :
2132 0 : (*types)[i] = SID_NAME_UNKNOWN;
2133 0 : (*names)[i] = talloc_strdup(*names, "");
2134 :
2135 0 : if (NT_STATUS_IS_OK(status)) {
2136 0 : have_mapped = true;
2137 0 : (*types)[i] = type;
2138 :
2139 0 : if (*domain_name == NULL) {
2140 0 : *domain_name = dom;
2141 : } else {
2142 0 : TALLOC_FREE(dom);
2143 : }
2144 :
2145 0 : (*names)[i] = name;
2146 :
2147 0 : } else if (NT_STATUS_EQUAL(
2148 : status,
2149 : NT_STATUS_NONE_MAPPED)) {
2150 0 : have_unmapped = true;
2151 : } else {
2152 : /* something's definitely wrong */
2153 0 : result = status;
2154 0 : goto error;
2155 : }
2156 : }
2157 :
2158 0 : if (!have_mapped) {
2159 0 : return NT_STATUS_NONE_MAPPED;
2160 : }
2161 0 : if (!have_unmapped) {
2162 0 : return NT_STATUS_OK;
2163 : }
2164 0 : return STATUS_SOME_UNMAPPED;
2165 : }
2166 : }
2167 : /*
2168 : None of the queried rids has been found so save all negative entries
2169 : */
2170 0 : if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2171 0 : for (i = 0; i < num_rids; i++) {
2172 0 : struct dom_sid sid;
2173 0 : const char *name = "";
2174 0 : const enum lsa_SidType type = SID_NAME_UNKNOWN;
2175 0 : NTSTATUS status = NT_STATUS_NONE_MAPPED;
2176 :
2177 0 : if (!sid_compose(&sid, domain_sid, rids[i])) {
2178 0 : return NT_STATUS_INTERNAL_ERROR;
2179 : }
2180 :
2181 0 : wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2182 : name, type);
2183 : }
2184 :
2185 0 : return result;
2186 : }
2187 :
2188 : /*
2189 : Some or all of the queried rids have been found.
2190 : */
2191 0 : if (!NT_STATUS_IS_OK(result) &&
2192 0 : !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2193 0 : return result;
2194 : }
2195 :
2196 0 : refresh_sequence_number(domain);
2197 :
2198 0 : for (i=0; i<num_rids; i++) {
2199 0 : struct dom_sid sid;
2200 0 : NTSTATUS status;
2201 :
2202 0 : if (!sid_compose(&sid, domain_sid, rids[i])) {
2203 0 : result = NT_STATUS_INTERNAL_ERROR;
2204 0 : goto error;
2205 : }
2206 :
2207 0 : status = (*types)[i] == SID_NAME_UNKNOWN ?
2208 0 : NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2209 :
2210 0 : wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2211 0 : (*names)[i], (*types)[i]);
2212 : }
2213 :
2214 0 : return result;
2215 :
2216 0 : error:
2217 0 : TALLOC_FREE(*names);
2218 0 : TALLOC_FREE(*types);
2219 0 : return result;
2220 : }
2221 :
2222 0 : static NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2223 : TALLOC_CTX *mem_ctx,
2224 : const struct dom_sid *user_sid,
2225 : struct wbint_userinfo *info)
2226 : {
2227 0 : struct winbind_cache *cache = get_cache(domain);
2228 0 : struct cache_entry *centry = NULL;
2229 0 : NTSTATUS status;
2230 0 : struct dom_sid_buf sid_string;
2231 :
2232 0 : if (cache->tdb == NULL) {
2233 0 : return NT_STATUS_NOT_FOUND;
2234 : }
2235 :
2236 0 : centry = wcache_fetch(
2237 : cache, domain, "U/%s", dom_sid_str_buf(user_sid, &sid_string));
2238 0 : if (centry == NULL) {
2239 0 : return NT_STATUS_NOT_FOUND;
2240 : }
2241 :
2242 : /* if status is not ok then this is a negative hit
2243 : and the rest of the data doesn't matter */
2244 0 : status = centry->status;
2245 0 : if (NT_STATUS_IS_OK(status)) {
2246 0 : info->domain_name = centry_string(centry, mem_ctx);
2247 0 : info->acct_name = centry_string(centry, mem_ctx);
2248 0 : info->full_name = centry_string(centry, mem_ctx);
2249 0 : info->homedir = centry_string(centry, mem_ctx);
2250 0 : info->shell = centry_string(centry, mem_ctx);
2251 0 : info->uid = centry_uint32(centry);
2252 0 : info->primary_gid = centry_uint32(centry);
2253 0 : info->primary_group_name = centry_string(centry, mem_ctx);
2254 0 : centry_sid(centry, &info->user_sid);
2255 0 : centry_sid(centry, &info->group_sid);
2256 : }
2257 :
2258 0 : DBG_DEBUG("query_user: [Cached] - cached info for domain %s status: "
2259 : "%s\n", domain->name, nt_errstr(status) );
2260 :
2261 0 : centry_free(centry);
2262 0 : return status;
2263 : }
2264 :
2265 :
2266 : /**
2267 : * @brief Query a fullname from the username cache (for further gecos processing)
2268 : *
2269 : * @param domain A pointer to the winbindd_domain struct.
2270 : * @param mem_ctx The talloc context.
2271 : * @param user_sid The user sid.
2272 : * @param full_name A pointer to the full_name string.
2273 : *
2274 : * @return NTSTATUS code
2275 : */
2276 0 : NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2277 : TALLOC_CTX *mem_ctx,
2278 : const struct dom_sid *user_sid,
2279 : const char **full_name)
2280 : {
2281 0 : NTSTATUS status;
2282 0 : struct wbint_userinfo info;
2283 :
2284 0 : status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2285 0 : if (!NT_STATUS_IS_OK(status)) {
2286 0 : return status;
2287 : }
2288 :
2289 0 : if (info.full_name != NULL) {
2290 0 : *full_name = talloc_strdup(mem_ctx, info.full_name);
2291 0 : if (*full_name == NULL) {
2292 0 : return NT_STATUS_NO_MEMORY;
2293 : }
2294 : }
2295 :
2296 0 : return NT_STATUS_OK;
2297 : }
2298 :
2299 0 : static NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2300 : TALLOC_CTX *mem_ctx,
2301 : const struct dom_sid *user_sid,
2302 : uint32_t *pnum_sids,
2303 : struct dom_sid **psids)
2304 : {
2305 0 : struct winbind_cache *cache = get_cache(domain);
2306 0 : struct cache_entry *centry = NULL;
2307 0 : NTSTATUS status;
2308 0 : uint32_t i, num_sids;
2309 0 : struct dom_sid *sids;
2310 0 : struct dom_sid_buf sid_string;
2311 :
2312 0 : if (cache->tdb == NULL) {
2313 0 : return NT_STATUS_NOT_FOUND;
2314 : }
2315 :
2316 0 : centry = wcache_fetch(
2317 : cache,
2318 : domain,
2319 : "UG/%s",
2320 : dom_sid_str_buf(user_sid, &sid_string));
2321 0 : if (centry == NULL) {
2322 0 : return NT_STATUS_NOT_FOUND;
2323 : }
2324 :
2325 0 : num_sids = centry_uint32(centry);
2326 0 : sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2327 0 : if (sids == NULL) {
2328 0 : centry_free(centry);
2329 0 : return NT_STATUS_NO_MEMORY;
2330 : }
2331 :
2332 0 : for (i=0; i<num_sids; i++) {
2333 0 : centry_sid(centry, &sids[i]);
2334 : }
2335 :
2336 0 : status = centry->status;
2337 :
2338 0 : DBG_DEBUG("lookup_usergroups: [Cached] - cached info for domain %s "
2339 : "status: %s\n", domain->name, nt_errstr(status));
2340 :
2341 0 : centry_free(centry);
2342 :
2343 0 : *pnum_sids = num_sids;
2344 0 : *psids = sids;
2345 0 : return status;
2346 : }
2347 :
2348 : /* Lookup groups a user is a member of. */
2349 0 : NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
2350 : TALLOC_CTX *mem_ctx,
2351 : const struct dom_sid *user_sid,
2352 : uint32_t *num_groups,
2353 : struct dom_sid **user_gids)
2354 : {
2355 0 : struct cache_entry *centry = NULL;
2356 0 : NTSTATUS status;
2357 0 : unsigned int i;
2358 0 : struct dom_sid_buf sid_string;
2359 0 : bool old_status;
2360 :
2361 0 : old_status = domain->online;
2362 0 : status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2363 : num_groups, user_gids);
2364 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2365 0 : return status;
2366 : }
2367 :
2368 0 : (*num_groups) = 0;
2369 0 : (*user_gids) = NULL;
2370 :
2371 0 : DBG_DEBUG("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2372 : domain->name );
2373 :
2374 0 : status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2375 :
2376 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2377 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2378 0 : if (!domain->internal && old_status) {
2379 0 : set_domain_offline(domain);
2380 : }
2381 0 : if (!domain->internal &&
2382 0 : !domain->online &&
2383 : old_status) {
2384 0 : NTSTATUS cache_status;
2385 0 : cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2386 : num_groups, user_gids);
2387 0 : return cache_status;
2388 : }
2389 : }
2390 0 : if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2391 0 : goto skip_save;
2392 :
2393 : /* and save it */
2394 0 : refresh_sequence_number(domain);
2395 0 : if (!NT_STATUS_IS_OK(status)) {
2396 0 : return status;
2397 : }
2398 0 : centry = centry_start(domain, status);
2399 0 : if (!centry)
2400 0 : goto skip_save;
2401 :
2402 0 : centry_put_uint32(centry, *num_groups);
2403 0 : for (i=0; i<(*num_groups); i++) {
2404 0 : centry_put_sid(centry, &(*user_gids)[i]);
2405 : }
2406 :
2407 0 : centry_end(centry, "UG/%s", dom_sid_str_buf(user_sid, &sid_string));
2408 0 : centry_free(centry);
2409 :
2410 0 : skip_save:
2411 0 : return status;
2412 : }
2413 :
2414 0 : static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2415 : const struct dom_sid *sids)
2416 : {
2417 0 : uint32_t i;
2418 0 : char *sidlist;
2419 :
2420 0 : sidlist = talloc_strdup(mem_ctx, "");
2421 0 : if (sidlist == NULL) {
2422 0 : return NULL;
2423 : }
2424 0 : for (i=0; i<num_sids; i++) {
2425 0 : struct dom_sid_buf tmp;
2426 0 : sidlist = talloc_asprintf_append_buffer(
2427 : sidlist,
2428 : "/%s",
2429 0 : dom_sid_str_buf(&sids[i], &tmp));
2430 0 : if (sidlist == NULL) {
2431 0 : return NULL;
2432 : }
2433 : }
2434 0 : return sidlist;
2435 : }
2436 :
2437 0 : static NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2438 : TALLOC_CTX *mem_ctx,
2439 : uint32_t num_sids,
2440 : const struct dom_sid *sids,
2441 : uint32_t *pnum_aliases,
2442 : uint32_t **paliases)
2443 : {
2444 0 : struct winbind_cache *cache = get_cache(domain);
2445 0 : struct cache_entry *centry = NULL;
2446 0 : uint32_t i, num_aliases;
2447 0 : uint32_t *aliases;
2448 0 : NTSTATUS status;
2449 0 : char *sidlist;
2450 :
2451 0 : if (cache->tdb == NULL) {
2452 0 : return NT_STATUS_NOT_FOUND;
2453 : }
2454 :
2455 0 : if (num_sids == 0) {
2456 0 : *pnum_aliases = 0;
2457 0 : *paliases = NULL;
2458 0 : return NT_STATUS_OK;
2459 : }
2460 :
2461 : /* We need to cache indexed by the whole list of SIDs, the aliases
2462 : * resulting might come from any of the SIDs. */
2463 :
2464 0 : sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2465 0 : if (sidlist == NULL) {
2466 0 : return NT_STATUS_NO_MEMORY;
2467 : }
2468 :
2469 0 : centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2470 0 : TALLOC_FREE(sidlist);
2471 0 : if (centry == NULL) {
2472 0 : return NT_STATUS_NOT_FOUND;
2473 : }
2474 :
2475 0 : num_aliases = centry_uint32(centry);
2476 0 : aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2477 0 : if (aliases == NULL) {
2478 0 : centry_free(centry);
2479 0 : return NT_STATUS_NO_MEMORY;
2480 : }
2481 :
2482 0 : for (i=0; i<num_aliases; i++) {
2483 0 : aliases[i] = centry_uint32(centry);
2484 : }
2485 :
2486 0 : status = centry->status;
2487 :
2488 0 : DBG_DEBUG("lookup_useraliases: [Cached] - cached info for domain: %s "
2489 : "status %s\n", domain->name, nt_errstr(status));
2490 :
2491 0 : centry_free(centry);
2492 :
2493 0 : *pnum_aliases = num_aliases;
2494 0 : *paliases = aliases;
2495 :
2496 0 : return status;
2497 : }
2498 :
2499 0 : NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2500 : TALLOC_CTX *mem_ctx,
2501 : uint32_t num_sids,
2502 : const struct dom_sid *sids,
2503 : uint32_t *num_aliases,
2504 : uint32_t **alias_rids)
2505 : {
2506 0 : struct cache_entry *centry = NULL;
2507 0 : NTSTATUS status;
2508 0 : char *sidlist;
2509 0 : uint32_t i;
2510 0 : bool old_status;
2511 :
2512 0 : old_status = domain->online;
2513 0 : status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2514 : num_aliases, alias_rids);
2515 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2516 0 : return status;
2517 : }
2518 :
2519 0 : (*num_aliases) = 0;
2520 0 : (*alias_rids) = NULL;
2521 :
2522 0 : DBG_DEBUG("lookup_usergroups: [Cached] - doing backend query for info "
2523 : "for domain %s\n", domain->name );
2524 :
2525 0 : sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2526 0 : if (sidlist == NULL) {
2527 0 : return NT_STATUS_NO_MEMORY;
2528 : }
2529 :
2530 0 : status = domain->backend->lookup_useraliases(domain, mem_ctx,
2531 : num_sids, sids,
2532 : num_aliases, alias_rids);
2533 :
2534 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2535 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2536 0 : if (!domain->internal && old_status) {
2537 0 : set_domain_offline(domain);
2538 : }
2539 0 : if (!domain->internal &&
2540 0 : !domain->online &&
2541 : old_status) {
2542 0 : NTSTATUS cache_status;
2543 0 : cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2544 : sids, num_aliases, alias_rids);
2545 0 : return cache_status;
2546 : }
2547 : }
2548 : /* and save it */
2549 0 : refresh_sequence_number(domain);
2550 0 : if (!NT_STATUS_IS_OK(status)) {
2551 0 : return status;
2552 : }
2553 0 : centry = centry_start(domain, status);
2554 0 : if (!centry)
2555 0 : goto skip_save;
2556 0 : centry_put_uint32(centry, *num_aliases);
2557 0 : for (i=0; i<(*num_aliases); i++)
2558 0 : centry_put_uint32(centry, (*alias_rids)[i]);
2559 0 : centry_end(centry, "UA%s", sidlist);
2560 0 : centry_free(centry);
2561 :
2562 0 : skip_save:
2563 0 : return status;
2564 : }
2565 :
2566 0 : static NTSTATUS wcache_lookup_aliasmem(struct winbindd_domain *domain,
2567 : TALLOC_CTX *mem_ctx,
2568 : const struct dom_sid *group_sid,
2569 : uint32_t *num_names,
2570 : struct dom_sid **sid_mem)
2571 : {
2572 0 : struct winbind_cache *cache = get_cache(domain);
2573 0 : struct cache_entry *centry = NULL;
2574 0 : NTSTATUS status;
2575 0 : unsigned int i;
2576 0 : struct dom_sid_buf sid_string;
2577 :
2578 0 : if (cache->tdb == NULL) {
2579 0 : return NT_STATUS_NOT_FOUND;
2580 : }
2581 :
2582 0 : centry = wcache_fetch(cache,
2583 : domain,
2584 : "AM/%s",
2585 : dom_sid_str_buf(group_sid, &sid_string));
2586 0 : if (centry == NULL) {
2587 0 : return NT_STATUS_NOT_FOUND;
2588 : }
2589 :
2590 0 : *sid_mem = NULL;
2591 :
2592 0 : *num_names = centry_uint32(centry);
2593 0 : if (*num_names == 0) {
2594 0 : centry_free(centry);
2595 0 : return NT_STATUS_OK;
2596 : }
2597 :
2598 0 : *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2599 0 : if (*sid_mem == NULL) {
2600 0 : TALLOC_FREE(*sid_mem);
2601 0 : centry_free(centry);
2602 0 : return NT_STATUS_NO_MEMORY;
2603 : }
2604 :
2605 0 : for (i = 0; i < (*num_names); i++) {
2606 0 : centry_sid(centry, &(*sid_mem)[i]);
2607 : }
2608 :
2609 0 : status = centry->status;
2610 :
2611 0 : D_DEBUG("[Cached] - cached info for domain %s "
2612 : "status: %s\n",
2613 : domain->name,
2614 : nt_errstr(status));
2615 :
2616 0 : centry_free(centry);
2617 0 : return status;
2618 : }
2619 :
2620 0 : NTSTATUS wb_cache_lookup_aliasmem(struct winbindd_domain *domain,
2621 : TALLOC_CTX *mem_ctx,
2622 : const struct dom_sid *group_sid,
2623 : enum lsa_SidType type,
2624 : uint32_t *num_sids,
2625 : struct dom_sid **sid_mem)
2626 : {
2627 0 : struct cache_entry *centry = NULL;
2628 0 : NTSTATUS status;
2629 0 : unsigned int i;
2630 0 : struct dom_sid_buf sid_string;
2631 0 : bool old_status;
2632 :
2633 0 : old_status = domain->online;
2634 0 : status = wcache_lookup_aliasmem(domain,
2635 : mem_ctx,
2636 : group_sid,
2637 : num_sids,
2638 : sid_mem);
2639 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2640 0 : return status;
2641 : }
2642 :
2643 0 : (*num_sids) = 0;
2644 0 : (*sid_mem) = NULL;
2645 :
2646 0 : D_DEBUG("[Cached] - doing backend query for info for domain %s\n",
2647 : domain->name);
2648 :
2649 0 : status = domain->backend->lookup_aliasmem(domain,
2650 : mem_ctx,
2651 : group_sid,
2652 : type,
2653 : num_sids,
2654 : sid_mem);
2655 :
2656 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2657 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2658 0 : if (!domain->internal && old_status) {
2659 0 : set_domain_offline(domain);
2660 : }
2661 0 : if (!domain->internal && !domain->online && old_status) {
2662 0 : NTSTATUS cache_status;
2663 0 : cache_status = wcache_lookup_aliasmem(domain,
2664 : mem_ctx,
2665 : group_sid,
2666 : num_sids,
2667 : sid_mem);
2668 0 : return cache_status;
2669 : }
2670 : }
2671 : /* and save it */
2672 0 : refresh_sequence_number(domain);
2673 0 : if (!NT_STATUS_IS_OK(status)) {
2674 0 : return status;
2675 : }
2676 0 : centry = centry_start(domain, status);
2677 0 : if (!centry)
2678 0 : goto skip_save;
2679 0 : centry_put_uint32(centry, *num_sids);
2680 0 : for (i = 0; i < (*num_sids); i++) {
2681 0 : centry_put_sid(centry, &(*sid_mem)[i]);
2682 : }
2683 0 : centry_end(centry, "AM/%s", dom_sid_str_buf(group_sid, &sid_string));
2684 0 : centry_free(centry);
2685 :
2686 0 : skip_save:
2687 0 : return status;
2688 : }
2689 :
2690 0 : static NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2691 : TALLOC_CTX *mem_ctx,
2692 : const struct dom_sid *group_sid,
2693 : uint32_t *num_names,
2694 : struct dom_sid **sid_mem, char ***names,
2695 : uint32_t **name_types)
2696 : {
2697 0 : struct winbind_cache *cache = get_cache(domain);
2698 0 : struct cache_entry *centry = NULL;
2699 0 : NTSTATUS status;
2700 0 : unsigned int i;
2701 0 : struct dom_sid_buf sid_string;
2702 :
2703 0 : if (cache->tdb == NULL) {
2704 0 : return NT_STATUS_NOT_FOUND;
2705 : }
2706 :
2707 0 : centry = wcache_fetch(
2708 : cache,
2709 : domain,
2710 : "GM/%s",
2711 : dom_sid_str_buf(group_sid, &sid_string));
2712 0 : if (centry == NULL) {
2713 0 : return NT_STATUS_NOT_FOUND;
2714 : }
2715 :
2716 0 : *sid_mem = NULL;
2717 0 : *names = NULL;
2718 0 : *name_types = NULL;
2719 :
2720 0 : *num_names = centry_uint32(centry);
2721 0 : if (*num_names == 0) {
2722 0 : centry_free(centry);
2723 0 : return NT_STATUS_OK;
2724 : }
2725 :
2726 0 : *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2727 0 : *names = talloc_array(mem_ctx, char *, *num_names);
2728 0 : *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2729 :
2730 0 : if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2731 0 : TALLOC_FREE(*sid_mem);
2732 0 : TALLOC_FREE(*names);
2733 0 : TALLOC_FREE(*name_types);
2734 0 : centry_free(centry);
2735 0 : return NT_STATUS_NO_MEMORY;
2736 : }
2737 :
2738 0 : for (i=0; i<(*num_names); i++) {
2739 0 : centry_sid(centry, &(*sid_mem)[i]);
2740 0 : (*names)[i] = centry_string(centry, mem_ctx);
2741 0 : (*name_types)[i] = centry_uint32(centry);
2742 : }
2743 :
2744 0 : status = centry->status;
2745 :
2746 0 : DBG_DEBUG("lookup_groupmem: [Cached] - cached info for domain %s "
2747 : "status: %s\n", domain->name, nt_errstr(status));
2748 :
2749 0 : centry_free(centry);
2750 0 : return status;
2751 : }
2752 :
2753 0 : NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2754 : TALLOC_CTX *mem_ctx,
2755 : const struct dom_sid *group_sid,
2756 : enum lsa_SidType type,
2757 : uint32_t *num_names,
2758 : struct dom_sid **sid_mem,
2759 : char ***names,
2760 : uint32_t **name_types)
2761 : {
2762 0 : struct cache_entry *centry = NULL;
2763 0 : NTSTATUS status;
2764 0 : unsigned int i;
2765 0 : struct dom_sid_buf sid_string;
2766 0 : bool old_status;
2767 :
2768 0 : old_status = domain->online;
2769 0 : status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2770 : sid_mem, names, name_types);
2771 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2772 0 : return status;
2773 : }
2774 :
2775 0 : (*num_names) = 0;
2776 0 : (*sid_mem) = NULL;
2777 0 : (*names) = NULL;
2778 0 : (*name_types) = NULL;
2779 :
2780 0 : DBG_DEBUG("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2781 : domain->name );
2782 :
2783 0 : status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2784 : type, num_names,
2785 : sid_mem, names, name_types);
2786 :
2787 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2788 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2789 0 : if (!domain->internal && old_status) {
2790 0 : set_domain_offline(domain);
2791 : }
2792 0 : if (!domain->internal &&
2793 0 : !domain->online &&
2794 : old_status) {
2795 0 : NTSTATUS cache_status;
2796 0 : cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2797 : num_names, sid_mem, names,
2798 : name_types);
2799 0 : return cache_status;
2800 : }
2801 : }
2802 : /* and save it */
2803 0 : refresh_sequence_number(domain);
2804 0 : if (!NT_STATUS_IS_OK(status)) {
2805 0 : return status;
2806 : }
2807 0 : centry = centry_start(domain, status);
2808 0 : if (!centry)
2809 0 : goto skip_save;
2810 0 : centry_put_uint32(centry, *num_names);
2811 0 : for (i=0; i<(*num_names); i++) {
2812 0 : centry_put_sid(centry, &(*sid_mem)[i]);
2813 0 : centry_put_string(centry, (*names)[i]);
2814 0 : centry_put_uint32(centry, (*name_types)[i]);
2815 : }
2816 0 : centry_end(centry,
2817 : "GM/%s",
2818 : dom_sid_str_buf(group_sid, &sid_string));
2819 0 : centry_free(centry);
2820 :
2821 0 : skip_save:
2822 0 : return status;
2823 : }
2824 :
2825 : /* find the sequence number for a domain */
2826 0 : NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2827 : uint32_t *seq)
2828 : {
2829 0 : refresh_sequence_number(domain);
2830 :
2831 0 : *seq = domain->sequence_number;
2832 :
2833 0 : return NT_STATUS_OK;
2834 : }
2835 :
2836 : /* enumerate trusted domains
2837 : * (we need to have the list of trustdoms in the cache when we go offline) -
2838 : * Guenther */
2839 0 : NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2840 : TALLOC_CTX *mem_ctx,
2841 : struct netr_DomainTrustList *trusts)
2842 : {
2843 0 : NTSTATUS status;
2844 0 : struct winbind_cache *cache;
2845 0 : struct winbindd_tdc_domain *dom_list = NULL;
2846 0 : size_t num_domains = 0;
2847 0 : bool retval = false;
2848 0 : size_t i;
2849 0 : bool old_status;
2850 :
2851 0 : old_status = domain->online;
2852 0 : trusts->count = 0;
2853 0 : trusts->array = NULL;
2854 :
2855 0 : cache = get_cache(domain);
2856 0 : if (!cache || !cache->tdb) {
2857 0 : goto do_query;
2858 : }
2859 :
2860 0 : if (domain->online) {
2861 0 : goto do_query;
2862 : }
2863 :
2864 0 : retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2865 0 : if (!retval || !num_domains || !dom_list) {
2866 0 : TALLOC_FREE(dom_list);
2867 0 : goto do_query;
2868 : }
2869 :
2870 0 : do_fetch_cache:
2871 0 : trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2872 0 : if (!trusts->array) {
2873 0 : TALLOC_FREE(dom_list);
2874 0 : return NT_STATUS_NO_MEMORY;
2875 : }
2876 :
2877 0 : for (i = 0; i < num_domains; i++) {
2878 0 : struct netr_DomainTrust *trust;
2879 0 : struct dom_sid *sid;
2880 0 : struct winbindd_domain *dom;
2881 :
2882 0 : dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2883 0 : if (dom && dom->internal) {
2884 0 : continue;
2885 : }
2886 :
2887 0 : trust = &trusts->array[trusts->count];
2888 0 : trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2889 0 : trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2890 0 : sid = talloc(trusts->array, struct dom_sid);
2891 0 : if (!trust->netbios_name || !trust->dns_name ||
2892 : !sid) {
2893 0 : TALLOC_FREE(dom_list);
2894 0 : TALLOC_FREE(trusts->array);
2895 0 : return NT_STATUS_NO_MEMORY;
2896 : }
2897 :
2898 0 : trust->trust_flags = dom_list[i].trust_flags;
2899 0 : trust->trust_attributes = dom_list[i].trust_attribs;
2900 0 : trust->trust_type = dom_list[i].trust_type;
2901 0 : sid_copy(sid, &dom_list[i].sid);
2902 0 : trust->sid = sid;
2903 0 : trusts->count++;
2904 : }
2905 :
2906 0 : TALLOC_FREE(dom_list);
2907 0 : return NT_STATUS_OK;
2908 :
2909 0 : do_query:
2910 0 : DBG_DEBUG("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2911 : domain->name );
2912 :
2913 0 : status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2914 :
2915 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2916 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2917 0 : if (!domain->internal && old_status) {
2918 0 : set_domain_offline(domain);
2919 : }
2920 0 : if (!domain->internal &&
2921 0 : !domain->online &&
2922 : old_status) {
2923 0 : retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2924 0 : if (retval && num_domains && dom_list) {
2925 0 : TALLOC_FREE(trusts->array);
2926 0 : trusts->count = 0;
2927 0 : goto do_fetch_cache;
2928 : }
2929 : }
2930 : }
2931 : /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2932 : * so that the generic centry handling still applies correctly -
2933 : * Guenther*/
2934 :
2935 0 : if (!NT_STATUS_IS_ERR(status)) {
2936 0 : status = NT_STATUS_OK;
2937 : }
2938 0 : return status;
2939 : }
2940 :
2941 : /* get lockout policy */
2942 0 : NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2943 : TALLOC_CTX *mem_ctx,
2944 : struct samr_DomInfo12 *policy)
2945 : {
2946 0 : struct winbind_cache *cache = get_cache(domain);
2947 0 : struct cache_entry *centry = NULL;
2948 0 : NTSTATUS status;
2949 0 : bool old_status;
2950 :
2951 0 : old_status = domain->online;
2952 0 : if (!cache->tdb)
2953 0 : goto do_query;
2954 :
2955 0 : centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2956 :
2957 0 : if (!centry)
2958 0 : goto do_query;
2959 :
2960 0 : do_fetch_cache:
2961 0 : policy->lockout_duration = centry_nttime(centry);
2962 0 : policy->lockout_window = centry_nttime(centry);
2963 0 : policy->lockout_threshold = centry_uint16(centry);
2964 :
2965 0 : status = centry->status;
2966 :
2967 0 : DBG_DEBUG("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2968 : domain->name, nt_errstr(status) );
2969 :
2970 0 : centry_free(centry);
2971 0 : return status;
2972 :
2973 0 : do_query:
2974 0 : ZERO_STRUCTP(policy);
2975 :
2976 0 : DBG_DEBUG("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2977 : domain->name );
2978 :
2979 0 : status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2980 :
2981 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2982 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2983 0 : if (!domain->internal && old_status) {
2984 0 : set_domain_offline(domain);
2985 : }
2986 0 : if (cache->tdb &&
2987 0 : !domain->internal &&
2988 0 : !domain->online &&
2989 : old_status) {
2990 0 : centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2991 0 : if (centry) {
2992 0 : goto do_fetch_cache;
2993 : }
2994 : }
2995 : }
2996 : /* and save it */
2997 0 : refresh_sequence_number(domain);
2998 0 : if (!NT_STATUS_IS_OK(status)) {
2999 0 : return status;
3000 : }
3001 0 : wcache_save_lockout_policy(domain, status, policy);
3002 :
3003 0 : return status;
3004 : }
3005 :
3006 : /* get password policy */
3007 0 : NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
3008 : TALLOC_CTX *mem_ctx,
3009 : struct samr_DomInfo1 *policy)
3010 : {
3011 0 : struct winbind_cache *cache = get_cache(domain);
3012 0 : struct cache_entry *centry = NULL;
3013 0 : NTSTATUS status;
3014 0 : bool old_status;
3015 :
3016 0 : old_status = domain->online;
3017 0 : if (!cache->tdb)
3018 0 : goto do_query;
3019 :
3020 0 : centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
3021 :
3022 0 : if (!centry)
3023 0 : goto do_query;
3024 :
3025 0 : do_fetch_cache:
3026 0 : policy->min_password_length = centry_uint16(centry);
3027 0 : policy->password_history_length = centry_uint16(centry);
3028 0 : policy->password_properties = centry_uint32(centry);
3029 0 : policy->max_password_age = centry_nttime(centry);
3030 0 : policy->min_password_age = centry_nttime(centry);
3031 :
3032 0 : status = centry->status;
3033 :
3034 0 : DBG_DEBUG("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
3035 : domain->name, nt_errstr(status) );
3036 :
3037 0 : centry_free(centry);
3038 0 : return status;
3039 :
3040 0 : do_query:
3041 0 : ZERO_STRUCTP(policy);
3042 :
3043 0 : DBG_DEBUG("password_policy: [Cached] - doing backend query for info for domain %s\n",
3044 : domain->name );
3045 :
3046 0 : status = domain->backend->password_policy(domain, mem_ctx, policy);
3047 :
3048 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
3049 0 : NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
3050 0 : if (!domain->internal && old_status) {
3051 0 : set_domain_offline(domain);
3052 : }
3053 0 : if (cache->tdb &&
3054 0 : !domain->internal &&
3055 0 : !domain->online &&
3056 : old_status) {
3057 0 : centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
3058 0 : if (centry) {
3059 0 : goto do_fetch_cache;
3060 : }
3061 : }
3062 : }
3063 : /* and save it */
3064 0 : refresh_sequence_number(domain);
3065 0 : if (!NT_STATUS_IS_OK(status)) {
3066 0 : return status;
3067 : }
3068 0 : wcache_save_password_policy(domain, status, policy);
3069 :
3070 0 : return status;
3071 : }
3072 :
3073 :
3074 : /* Invalidate cached user and group lists coherently */
3075 :
3076 16342 : static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3077 : void *state)
3078 : {
3079 16342 : if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3080 16338 : strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3081 6 : tdb_delete(the_tdb, kbuf);
3082 :
3083 16342 : return 0;
3084 : }
3085 :
3086 : /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3087 :
3088 0 : void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3089 : const struct dom_sid *sid)
3090 : {
3091 0 : fstring key_str;
3092 0 : struct dom_sid_buf sid_string;
3093 0 : struct winbind_cache *cache;
3094 :
3095 : /* don't clear cached U/SID and UG/SID entries when we want to logon
3096 : * offline - gd */
3097 :
3098 0 : if (lp_winbind_offline_logon()) {
3099 0 : return;
3100 : }
3101 :
3102 0 : if (!domain)
3103 0 : return;
3104 :
3105 0 : cache = get_cache(domain);
3106 :
3107 0 : if (!cache->tdb) {
3108 0 : return;
3109 : }
3110 :
3111 : /* Clear U/SID cache entry */
3112 0 : fstr_sprintf(key_str, "U/%s", dom_sid_str_buf(sid, &sid_string));
3113 0 : DBG_DEBUG("wcache_invalidate_samlogon: clearing %s\n", key_str);
3114 0 : tdb_delete(cache->tdb, string_tdb_data(key_str));
3115 :
3116 : /* Clear UG/SID cache entry */
3117 0 : fstr_sprintf(key_str, "UG/%s", dom_sid_str_buf(sid, &sid_string));
3118 0 : DBG_DEBUG("wcache_invalidate_samlogon: clearing %s\n", key_str);
3119 0 : tdb_delete(cache->tdb, string_tdb_data(key_str));
3120 :
3121 : /* Samba/winbindd never needs this. */
3122 0 : netsamlogon_clear_cached_user(sid);
3123 : }
3124 :
3125 86 : bool wcache_invalidate_cache(void)
3126 : {
3127 0 : struct winbindd_domain *domain;
3128 :
3129 282 : for (domain = domain_list(); domain; domain = domain->next) {
3130 196 : struct winbind_cache *cache = get_cache(domain);
3131 :
3132 196 : DBG_DEBUG("wcache_invalidate_cache: invalidating cache "
3133 : "entries for %s\n", domain->name);
3134 196 : if (cache) {
3135 196 : if (cache->tdb) {
3136 196 : tdb_traverse(cache->tdb, traverse_fn, NULL);
3137 : } else {
3138 0 : return false;
3139 : }
3140 : }
3141 : }
3142 86 : return true;
3143 : }
3144 :
3145 0 : bool wcache_invalidate_cache_noinit(void)
3146 : {
3147 0 : struct winbindd_domain *domain;
3148 :
3149 0 : for (domain = domain_list(); domain; domain = domain->next) {
3150 0 : struct winbind_cache *cache;
3151 :
3152 : /* Skip uninitialized domains. */
3153 0 : if (!domain->initialized && !domain->internal) {
3154 0 : continue;
3155 : }
3156 :
3157 0 : cache = get_cache(domain);
3158 :
3159 0 : DBG_DEBUG("wcache_invalidate_cache: invalidating cache "
3160 : "entries for %s\n", domain->name);
3161 0 : if (cache) {
3162 0 : if (cache->tdb) {
3163 0 : tdb_traverse(cache->tdb, traverse_fn, NULL);
3164 : /*
3165 : * Flushing cache has nothing to with domains.
3166 : * return here if we successfully flushed once.
3167 : * To avoid unnecessary traversing the cache.
3168 : */
3169 0 : return true;
3170 : } else {
3171 0 : return false;
3172 : }
3173 : }
3174 : }
3175 0 : return true;
3176 : }
3177 :
3178 262 : static bool init_wcache(void)
3179 : {
3180 0 : char *db_path;
3181 :
3182 262 : if (wcache == NULL) {
3183 45 : wcache = SMB_XMALLOC_P(struct winbind_cache);
3184 45 : ZERO_STRUCTP(wcache);
3185 : }
3186 :
3187 262 : if (wcache->tdb != NULL)
3188 135 : return true;
3189 :
3190 127 : db_path = wcache_path();
3191 127 : if (db_path == NULL) {
3192 0 : return false;
3193 : }
3194 :
3195 : /* when working offline we must not clear the cache on restart */
3196 127 : wcache->tdb = tdb_open_log(db_path,
3197 : WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3198 : TDB_INCOMPATIBLE_HASH |
3199 127 : (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3200 : O_RDWR|O_CREAT, 0600);
3201 127 : TALLOC_FREE(db_path);
3202 127 : if (wcache->tdb == NULL) {
3203 0 : DBG_ERR("Failed to open winbindd_cache.tdb!\n");
3204 0 : return false;
3205 : }
3206 :
3207 127 : return true;
3208 : }
3209 :
3210 : /************************************************************************
3211 : This is called by the parent to initialize the cache file.
3212 : We don't need sophisticated locking here as we know we're the
3213 : only opener.
3214 : ************************************************************************/
3215 :
3216 45 : bool initialize_winbindd_cache(void)
3217 : {
3218 45 : bool cache_bad = false;
3219 45 : uint32_t vers = 0;
3220 0 : bool ok;
3221 :
3222 45 : if (!init_wcache()) {
3223 0 : DBG_ERR("initialize_winbindd_cache: init_wcache failed.\n");
3224 0 : return false;
3225 : }
3226 :
3227 : /* Check version number. */
3228 45 : ok = tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers);
3229 45 : if (!ok) {
3230 37 : DBG_DEBUG("Failed to get cache version\n");
3231 37 : cache_bad = true;
3232 : }
3233 45 : if (vers != WINBINDD_CACHE_VERSION) {
3234 37 : DBG_DEBUG("Invalid cache version %u != %u\n",
3235 : vers,
3236 : WINBINDD_CACHE_VERSION);
3237 37 : cache_bad = true;
3238 : }
3239 :
3240 45 : if (cache_bad) {
3241 0 : char *db_path;
3242 :
3243 37 : DBG_NOTICE("initialize_winbindd_cache: clearing cache "
3244 : "and re-creating with version number %d\n",
3245 : WINBINDD_CACHE_VERSION);
3246 :
3247 37 : tdb_close(wcache->tdb);
3248 37 : wcache->tdb = NULL;
3249 :
3250 37 : db_path = wcache_path();
3251 37 : if (db_path == NULL) {
3252 0 : return false;
3253 : }
3254 :
3255 37 : if (unlink(db_path) == -1) {
3256 0 : DBG_ERR("initialize_winbindd_cache: unlink %s failed %s\n",
3257 : db_path,
3258 : strerror(errno) );
3259 0 : TALLOC_FREE(db_path);
3260 0 : return false;
3261 : }
3262 37 : TALLOC_FREE(db_path);
3263 37 : if (!init_wcache()) {
3264 0 : DBG_ERR("initialize_winbindd_cache: re-initialization "
3265 : "init_wcache failed.\n");
3266 0 : return false;
3267 : }
3268 :
3269 : /* Write the version. */
3270 37 : if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3271 0 : DBG_ERR("initialize_winbindd_cache: version number store failed %s\n",
3272 : tdb_errorstr(wcache->tdb) );
3273 0 : return false;
3274 : }
3275 : }
3276 :
3277 45 : tdb_close(wcache->tdb);
3278 45 : wcache->tdb = NULL;
3279 45 : return true;
3280 : }
3281 :
3282 45 : void close_winbindd_cache(void)
3283 : {
3284 45 : if (!wcache) {
3285 45 : return;
3286 : }
3287 0 : if (wcache->tdb) {
3288 0 : tdb_close(wcache->tdb);
3289 0 : wcache->tdb = NULL;
3290 : }
3291 : }
3292 :
3293 0 : bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3294 : char **domain_name, char **name,
3295 : enum lsa_SidType *type)
3296 : {
3297 0 : struct winbindd_domain *domain;
3298 0 : NTSTATUS status;
3299 :
3300 0 : domain = find_lookup_domain_from_sid(sid);
3301 0 : if (domain == NULL) {
3302 0 : return false;
3303 : }
3304 0 : status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3305 : type);
3306 0 : return NT_STATUS_IS_OK(status);
3307 : }
3308 :
3309 0 : bool lookup_cached_name(const char *namespace,
3310 : const char *domain_name,
3311 : const char *name,
3312 : struct dom_sid *sid,
3313 : enum lsa_SidType *type)
3314 : {
3315 0 : struct winbindd_domain *domain;
3316 0 : NTSTATUS status;
3317 0 : bool original_online_state;
3318 :
3319 0 : domain = find_lookup_domain_from_name(namespace);
3320 0 : if (domain == NULL) {
3321 0 : return false;
3322 : }
3323 :
3324 : /* If we are doing a cached logon, temporarily set the domain
3325 : offline so the cache won't expire the entry */
3326 :
3327 0 : original_online_state = domain->online;
3328 0 : domain->online = false;
3329 0 : status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3330 0 : domain->online = original_online_state;
3331 :
3332 0 : return NT_STATUS_IS_OK(status);
3333 : }
3334 :
3335 : /*
3336 : * Cache a name to sid without checking the sequence number.
3337 : * Used when caching from a trusted PAC.
3338 : */
3339 :
3340 882 : void cache_name2sid_trusted(struct winbindd_domain *domain,
3341 : const char *domain_name,
3342 : const char *name,
3343 : enum lsa_SidType type,
3344 : const struct dom_sid *sid)
3345 : {
3346 : /*
3347 : * Ensure we store the mapping with the
3348 : * existing sequence number from the cache.
3349 : */
3350 882 : get_cache(domain);
3351 882 : (void)fetch_cache_seqnum(domain, time(NULL));
3352 882 : wcache_save_name_to_sid(domain,
3353 882 : NT_STATUS_OK,
3354 : domain_name,
3355 : name,
3356 : sid,
3357 : type);
3358 882 : }
3359 :
3360 0 : void cache_name2sid(struct winbindd_domain *domain,
3361 : const char *domain_name, const char *name,
3362 : enum lsa_SidType type, const struct dom_sid *sid)
3363 : {
3364 0 : refresh_sequence_number(domain);
3365 0 : wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3366 : sid, type);
3367 0 : }
3368 :
3369 : /*
3370 : * The original idea that this cache only contains centries has
3371 : * been blurred - now other stuff gets put in here. Ensure we
3372 : * ignore these things on cleanup.
3373 : */
3374 :
3375 0 : static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3376 : TDB_DATA dbuf, void *state)
3377 : {
3378 0 : struct cache_entry *centry;
3379 :
3380 0 : if (is_non_centry_key(kbuf)) {
3381 0 : return 0;
3382 : }
3383 :
3384 0 : centry = wcache_fetch_raw((char *)kbuf.dptr);
3385 0 : if (!centry) {
3386 0 : return 0;
3387 : }
3388 :
3389 0 : if (!NT_STATUS_IS_OK(centry->status)) {
3390 0 : DBG_DEBUG("deleting centry %s\n", (const char *)kbuf.dptr);
3391 0 : tdb_delete(the_tdb, kbuf);
3392 : }
3393 :
3394 0 : centry_free(centry);
3395 0 : return 0;
3396 : }
3397 :
3398 : /* flush the cache */
3399 0 : static void wcache_flush_cache(void)
3400 : {
3401 0 : char *db_path;
3402 :
3403 0 : if (!wcache)
3404 0 : return;
3405 0 : if (wcache->tdb) {
3406 0 : tdb_close(wcache->tdb);
3407 0 : wcache->tdb = NULL;
3408 : }
3409 0 : if (!winbindd_use_cache()) {
3410 0 : return;
3411 : }
3412 :
3413 0 : db_path = wcache_path();
3414 0 : if (db_path == NULL) {
3415 0 : return;
3416 : }
3417 :
3418 : /* when working offline we must not clear the cache on restart */
3419 0 : wcache->tdb = tdb_open_log(db_path,
3420 : WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3421 : TDB_INCOMPATIBLE_HASH |
3422 0 : (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3423 : O_RDWR|O_CREAT, 0600);
3424 0 : TALLOC_FREE(db_path);
3425 0 : if (!wcache->tdb) {
3426 0 : DBG_ERR("Failed to open winbindd_cache.tdb!\n");
3427 0 : return;
3428 : }
3429 :
3430 0 : tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3431 :
3432 0 : DBG_DEBUG("wcache_flush_cache success\n");
3433 : }
3434 :
3435 : /* Count cached creds */
3436 :
3437 0 : static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3438 : void *state)
3439 : {
3440 0 : int *cred_count = (int*)state;
3441 :
3442 0 : if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3443 0 : (*cred_count)++;
3444 : }
3445 0 : return 0;
3446 : }
3447 :
3448 0 : NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3449 : {
3450 0 : struct winbind_cache *cache = get_cache(domain);
3451 :
3452 0 : *count = 0;
3453 :
3454 0 : if (!cache->tdb) {
3455 0 : return NT_STATUS_INTERNAL_DB_ERROR;
3456 : }
3457 :
3458 0 : tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3459 :
3460 0 : return NT_STATUS_OK;
3461 : }
3462 :
3463 : struct cred_list {
3464 : struct cred_list *prev, *next;
3465 : TDB_DATA key;
3466 : fstring name;
3467 : time_t created;
3468 : };
3469 : static struct cred_list *wcache_cred_list;
3470 :
3471 0 : static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3472 : void *state)
3473 : {
3474 0 : struct cred_list *cred;
3475 :
3476 0 : if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3477 :
3478 0 : cred = SMB_MALLOC_P(struct cred_list);
3479 0 : if (cred == NULL) {
3480 0 : DBG_ERR("traverse_fn_remove_first_creds: failed to malloc new entry for list\n");
3481 0 : return -1;
3482 : }
3483 :
3484 0 : ZERO_STRUCTP(cred);
3485 :
3486 : /* save a copy of the key */
3487 :
3488 0 : fstrcpy(cred->name, (const char *)kbuf.dptr);
3489 0 : DLIST_ADD(wcache_cred_list, cred);
3490 : }
3491 :
3492 0 : return 0;
3493 : }
3494 :
3495 0 : NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3496 : {
3497 0 : struct winbind_cache *cache = get_cache(domain);
3498 0 : NTSTATUS status;
3499 0 : int ret;
3500 0 : struct cred_list *cred, *next, *oldest = NULL;
3501 :
3502 0 : if (!cache->tdb) {
3503 0 : return NT_STATUS_INTERNAL_DB_ERROR;
3504 : }
3505 :
3506 : /* we possibly already have an entry */
3507 0 : if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3508 :
3509 0 : fstring key_str;
3510 0 : struct dom_sid_buf tmp;
3511 :
3512 0 : DBG_DEBUG("we already have an entry, deleting that\n");
3513 :
3514 0 : fstr_sprintf(key_str, "CRED/%s", dom_sid_str_buf(sid, &tmp));
3515 :
3516 0 : tdb_delete(cache->tdb, string_tdb_data(key_str));
3517 :
3518 0 : return NT_STATUS_OK;
3519 : }
3520 :
3521 0 : ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3522 0 : if (ret == 0) {
3523 0 : return NT_STATUS_OK;
3524 0 : } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3525 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3526 : }
3527 :
3528 0 : ZERO_STRUCTP(oldest);
3529 :
3530 0 : for (cred = wcache_cred_list; cred; cred = cred->next) {
3531 :
3532 0 : TDB_DATA data;
3533 0 : time_t t;
3534 :
3535 0 : data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3536 0 : if (!data.dptr) {
3537 0 : DBG_DEBUG("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3538 : cred->name);
3539 0 : status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3540 0 : goto done;
3541 : }
3542 :
3543 0 : t = IVAL(data.dptr, 0);
3544 0 : SAFE_FREE(data.dptr);
3545 :
3546 0 : if (!oldest) {
3547 0 : oldest = SMB_MALLOC_P(struct cred_list);
3548 0 : if (oldest == NULL) {
3549 0 : status = NT_STATUS_NO_MEMORY;
3550 0 : goto done;
3551 : }
3552 :
3553 0 : fstrcpy(oldest->name, cred->name);
3554 0 : oldest->created = t;
3555 0 : continue;
3556 : }
3557 :
3558 0 : if (t < oldest->created) {
3559 0 : fstrcpy(oldest->name, cred->name);
3560 0 : oldest->created = t;
3561 : }
3562 : }
3563 :
3564 0 : if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3565 0 : status = NT_STATUS_OK;
3566 : } else {
3567 0 : status = NT_STATUS_UNSUCCESSFUL;
3568 : }
3569 0 : done:
3570 0 : for (cred = wcache_cred_list; cred; cred = next) {
3571 0 : next = cred->next;
3572 0 : DLIST_REMOVE(wcache_cred_list, cred);
3573 0 : SAFE_FREE(cred);
3574 : }
3575 0 : SAFE_FREE(oldest);
3576 :
3577 0 : return status;
3578 : }
3579 :
3580 : /* Change the global online/offline state. */
3581 4 : bool set_global_winbindd_state_offline(void)
3582 : {
3583 0 : bool ok;
3584 4 : uint8_t buf[4] = {0};
3585 4 : TDB_DATA data = {
3586 : .dptr = buf,
3587 : .dsize = sizeof(buf)
3588 : };
3589 0 : int rc;
3590 :
3591 4 : DBG_NOTICE("Offline requested\n");
3592 :
3593 4 : if (wcache == NULL || wcache->tdb == NULL) {
3594 0 : DBG_NOTICE("Winbind cache doesn't exist yet\n");
3595 0 : return false;
3596 : }
3597 :
3598 4 : if (!lp_winbind_offline_logon()) {
3599 0 : DBG_DEBUG("Rejecting request to set winbind offline, "
3600 : "offline logons are disabled in smb.conf\n");
3601 0 : return false;
3602 : }
3603 :
3604 4 : ok = get_global_winbindd_state_offline();
3605 4 : if (ok) {
3606 4 : return true;
3607 : }
3608 :
3609 0 : PUSH_LE_U32(buf, 0, time(NULL));
3610 :
3611 0 : rc = tdb_store_bystring(wcache->tdb,
3612 : "WINBINDD_OFFLINE",
3613 : data,
3614 : TDB_INSERT);
3615 0 : if (rc != 0) {
3616 0 : return false;
3617 : }
3618 :
3619 0 : return true;
3620 :
3621 : }
3622 :
3623 0 : void set_global_winbindd_state_online(void)
3624 : {
3625 0 : DBG_DEBUG("set_global_winbindd_state_online: online requested.\n");
3626 :
3627 0 : if (!lp_winbind_offline_logon()) {
3628 0 : DBG_DEBUG("Rejecting request to set winbind online, "
3629 : "offline logons are disabled in smb.conf.\n");
3630 0 : return;
3631 : }
3632 :
3633 0 : if (!wcache->tdb) {
3634 0 : return;
3635 : }
3636 :
3637 : /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3638 0 : tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3639 : }
3640 :
3641 101507 : bool get_global_winbindd_state_offline(void)
3642 : {
3643 0 : TDB_DATA data;
3644 :
3645 101507 : data = tdb_fetch_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3646 101507 : if (data.dptr == NULL || data.dsize != 4) {
3647 101499 : DBG_DEBUG("Offline state not set.\n");
3648 101499 : SAFE_FREE(data.dptr);
3649 101499 : return false;
3650 : }
3651 :
3652 8 : return true;
3653 : }
3654 :
3655 : /***********************************************************************
3656 : Validate functions for all possible cache tdb keys.
3657 : ***********************************************************************/
3658 :
3659 24 : static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3660 : struct tdb_validation_status *state)
3661 : {
3662 0 : struct cache_entry *centry;
3663 :
3664 24 : centry = SMB_XMALLOC_P(struct cache_entry);
3665 24 : centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3666 24 : if (!centry->data) {
3667 0 : SAFE_FREE(centry);
3668 0 : return NULL;
3669 : }
3670 24 : centry->len = data.dsize;
3671 24 : centry->ofs = 0;
3672 :
3673 24 : if (centry->len < 16) {
3674 : /* huh? corrupt cache? */
3675 0 : DBG_ERR("create_centry_validate: Corrupt cache for key %s "
3676 : "(len < 16) ?\n", kstr);
3677 0 : centry_free(centry);
3678 0 : state->bad_entry = true;
3679 0 : state->success = false;
3680 0 : return NULL;
3681 : }
3682 :
3683 24 : centry->status = NT_STATUS(centry_uint32(centry));
3684 24 : centry->sequence_number = centry_uint32(centry);
3685 24 : centry->timeout = centry_uint64_t(centry);
3686 24 : return centry;
3687 : }
3688 :
3689 8 : static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3690 : struct tdb_validation_status *state)
3691 : {
3692 8 : if (dbuf.dsize != 8) {
3693 0 : DBG_ERR("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3694 : keystr, (unsigned int)dbuf.dsize );
3695 0 : state->bad_entry = true;
3696 0 : return 1;
3697 : }
3698 8 : return 0;
3699 : }
3700 :
3701 0 : static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3702 : struct tdb_validation_status *state)
3703 : {
3704 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3705 0 : struct dom_sid sid;
3706 :
3707 0 : if (!centry) {
3708 0 : return 1;
3709 : }
3710 :
3711 0 : (void)centry_string(centry, mem_ctx);
3712 0 : (void)centry_string(centry, mem_ctx);
3713 0 : (void)centry_string(centry, mem_ctx);
3714 0 : (void)centry_string(centry, mem_ctx);
3715 0 : (void)centry_string(centry, mem_ctx);
3716 0 : (void)centry_uint32(centry);
3717 0 : (void)centry_uint32(centry);
3718 0 : (void)centry_string(centry, mem_ctx);
3719 0 : (void)centry_sid(centry, &sid);
3720 0 : (void)centry_sid(centry, &sid);
3721 :
3722 0 : centry_free(centry);
3723 :
3724 0 : if (!(state->success)) {
3725 0 : return 1;
3726 : }
3727 0 : DBG_DEBUG("validate_u: %s ok\n", keystr);
3728 0 : return 0;
3729 : }
3730 :
3731 8 : static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3732 : struct tdb_validation_status *state)
3733 : {
3734 8 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3735 :
3736 8 : if (!centry) {
3737 0 : return 1;
3738 : }
3739 :
3740 8 : (void)centry_nttime(centry);
3741 8 : (void)centry_nttime(centry);
3742 8 : (void)centry_uint16(centry);
3743 :
3744 8 : centry_free(centry);
3745 :
3746 8 : if (!(state->success)) {
3747 0 : return 1;
3748 : }
3749 8 : DBG_DEBUG("validate_loc_pol: %s ok\n", keystr);
3750 8 : return 0;
3751 : }
3752 :
3753 0 : static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3754 : struct tdb_validation_status *state)
3755 : {
3756 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3757 :
3758 0 : if (!centry) {
3759 0 : return 1;
3760 : }
3761 :
3762 0 : (void)centry_uint16(centry);
3763 0 : (void)centry_uint16(centry);
3764 0 : (void)centry_uint32(centry);
3765 0 : (void)centry_nttime(centry);
3766 0 : (void)centry_nttime(centry);
3767 :
3768 0 : centry_free(centry);
3769 :
3770 0 : if (!(state->success)) {
3771 0 : return 1;
3772 : }
3773 0 : DBG_DEBUG("validate_pwd_pol: %s ok\n", keystr);
3774 0 : return 0;
3775 : }
3776 :
3777 16 : static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3778 : struct tdb_validation_status *state)
3779 : {
3780 16 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3781 :
3782 16 : if (!centry) {
3783 0 : return 1;
3784 : }
3785 :
3786 16 : (void)centry_time(centry);
3787 16 : (void)centry_hash16(centry, mem_ctx);
3788 :
3789 : /* We only have 17 bytes more data in the salted cred case. */
3790 16 : if (centry->len - centry->ofs == 17) {
3791 16 : (void)centry_hash16(centry, mem_ctx);
3792 : }
3793 :
3794 16 : centry_free(centry);
3795 :
3796 16 : if (!(state->success)) {
3797 0 : return 1;
3798 : }
3799 16 : DBG_DEBUG("validate_cred: %s ok\n", keystr);
3800 16 : return 0;
3801 : }
3802 :
3803 0 : static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3804 : struct tdb_validation_status *state)
3805 : {
3806 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3807 0 : int32_t num_entries, i;
3808 :
3809 0 : if (!centry) {
3810 0 : return 1;
3811 : }
3812 :
3813 0 : num_entries = (int32_t)centry_uint32(centry);
3814 :
3815 0 : for (i=0; i< num_entries; i++) {
3816 0 : (void)centry_uint32(centry);
3817 : }
3818 :
3819 0 : centry_free(centry);
3820 :
3821 0 : if (!(state->success)) {
3822 0 : return 1;
3823 : }
3824 0 : DBG_DEBUG("validate_ul: %s ok\n", keystr);
3825 0 : return 0;
3826 : }
3827 :
3828 0 : static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3829 : struct tdb_validation_status *state)
3830 : {
3831 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3832 0 : int32_t num_entries, i;
3833 :
3834 0 : if (!centry) {
3835 0 : return 1;
3836 : }
3837 :
3838 0 : num_entries = centry_uint32(centry);
3839 :
3840 0 : for (i=0; i< num_entries; i++) {
3841 0 : (void)centry_string(centry, mem_ctx);
3842 0 : (void)centry_string(centry, mem_ctx);
3843 0 : (void)centry_uint32(centry);
3844 : }
3845 :
3846 0 : centry_free(centry);
3847 :
3848 0 : if (!(state->success)) {
3849 0 : return 1;
3850 : }
3851 0 : DBG_DEBUG("validate_gl: %s ok\n", keystr);
3852 0 : return 0;
3853 : }
3854 :
3855 0 : static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3856 : struct tdb_validation_status *state)
3857 : {
3858 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3859 0 : int32_t num_groups, i;
3860 :
3861 0 : if (!centry) {
3862 0 : return 1;
3863 : }
3864 :
3865 0 : num_groups = centry_uint32(centry);
3866 :
3867 0 : for (i=0; i< num_groups; i++) {
3868 0 : struct dom_sid sid;
3869 0 : centry_sid(centry, &sid);
3870 : }
3871 :
3872 0 : centry_free(centry);
3873 :
3874 0 : if (!(state->success)) {
3875 0 : return 1;
3876 : }
3877 0 : DBG_DEBUG("validate_ug: %s ok\n", keystr);
3878 0 : return 0;
3879 : }
3880 :
3881 0 : static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3882 : struct tdb_validation_status *state)
3883 : {
3884 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3885 0 : int32_t num_aliases, i;
3886 :
3887 0 : if (!centry) {
3888 0 : return 1;
3889 : }
3890 :
3891 0 : num_aliases = centry_uint32(centry);
3892 :
3893 0 : for (i=0; i < num_aliases; i++) {
3894 0 : (void)centry_uint32(centry);
3895 : }
3896 :
3897 0 : centry_free(centry);
3898 :
3899 0 : if (!(state->success)) {
3900 0 : return 1;
3901 : }
3902 0 : DBG_DEBUG("validate_ua: %s ok\n", keystr);
3903 0 : return 0;
3904 : }
3905 :
3906 0 : static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3907 : struct tdb_validation_status *state)
3908 : {
3909 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3910 0 : int32_t num_names, i;
3911 :
3912 0 : if (!centry) {
3913 0 : return 1;
3914 : }
3915 :
3916 0 : num_names = centry_uint32(centry);
3917 :
3918 0 : for (i=0; i< num_names; i++) {
3919 0 : struct dom_sid sid;
3920 0 : centry_sid(centry, &sid);
3921 0 : (void)centry_string(centry, mem_ctx);
3922 0 : (void)centry_uint32(centry);
3923 : }
3924 :
3925 0 : centry_free(centry);
3926 :
3927 0 : if (!(state->success)) {
3928 0 : return 1;
3929 : }
3930 0 : DBG_DEBUG("validate_gm: %s ok\n", keystr);
3931 0 : return 0;
3932 : }
3933 :
3934 0 : static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3935 : struct tdb_validation_status *state)
3936 : {
3937 : /* Can't say anything about this other than must be nonzero. */
3938 0 : if (dbuf.dsize == 0) {
3939 0 : DBG_ERR("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3940 : keystr);
3941 0 : state->bad_entry = true;
3942 0 : state->success = false;
3943 0 : return 1;
3944 : }
3945 :
3946 0 : DBG_DEBUG("validate_dr: %s ok\n", keystr);
3947 0 : return 0;
3948 : }
3949 :
3950 0 : static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3951 : struct tdb_validation_status *state)
3952 : {
3953 : /* Can't say anything about this other than must be nonzero. */
3954 0 : if (dbuf.dsize == 0) {
3955 0 : DBG_ERR("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3956 : keystr);
3957 0 : state->bad_entry = true;
3958 0 : state->success = false;
3959 0 : return 1;
3960 : }
3961 :
3962 0 : DBG_DEBUG("validate_de: %s ok\n", keystr);
3963 0 : return 0;
3964 : }
3965 :
3966 0 : static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3967 : TDB_DATA dbuf,
3968 : struct tdb_validation_status *state)
3969 : {
3970 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3971 :
3972 0 : if (!centry) {
3973 0 : return 1;
3974 : }
3975 :
3976 0 : (void)centry_string( centry, mem_ctx );
3977 :
3978 0 : centry_free(centry);
3979 :
3980 0 : if (!(state->success)) {
3981 0 : return 1;
3982 : }
3983 0 : DBG_DEBUG("validate_pwinfo: %s ok\n", keystr);
3984 0 : return 0;
3985 : }
3986 :
3987 0 : static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3988 : TDB_DATA dbuf,
3989 : struct tdb_validation_status *state)
3990 : {
3991 0 : struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3992 :
3993 0 : if (!centry) {
3994 0 : return 1;
3995 : }
3996 :
3997 0 : (void)centry_string( centry, mem_ctx );
3998 :
3999 0 : centry_free(centry);
4000 :
4001 0 : if (!(state->success)) {
4002 0 : return 1;
4003 : }
4004 0 : DBG_DEBUG("%s ok\n", keystr);
4005 0 : return 0;
4006 : }
4007 :
4008 8 : static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
4009 : TDB_DATA dbuf,
4010 : struct tdb_validation_status *state)
4011 : {
4012 8 : if (dbuf.dsize == 0) {
4013 0 : DBG_ERR("validate_trustdomcache: Corrupt cache for "
4014 : "key %s (len ==0) ?\n", keystr);
4015 0 : state->bad_entry = true;
4016 0 : state->success = false;
4017 0 : return 1;
4018 : }
4019 :
4020 8 : DBG_DEBUG("validate_trustdomcache: %s ok\n"
4021 : " Don't trust me, I am a DUMMY!\n",
4022 : keystr);
4023 8 : return 0;
4024 : }
4025 :
4026 8 : static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4027 : struct tdb_validation_status *state)
4028 : {
4029 8 : if (dbuf.dsize != 4) {
4030 0 : DBG_ERR("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4031 : keystr, (unsigned int)dbuf.dsize );
4032 0 : state->bad_entry = true;
4033 0 : state->success = false;
4034 0 : return 1;
4035 : }
4036 8 : DBG_DEBUG("validate_offline: %s ok\n", keystr);
4037 8 : return 0;
4038 : }
4039 :
4040 0 : static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4041 : struct tdb_validation_status *state)
4042 : {
4043 : /*
4044 : * Ignore validation for now. The proper way to do this is with a
4045 : * checksum. Just pure parsing does not really catch much.
4046 : */
4047 0 : return 0;
4048 : }
4049 :
4050 12 : static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4051 : struct tdb_validation_status *state)
4052 : {
4053 12 : if (dbuf.dsize != 4) {
4054 0 : DBG_ERR("validate_cache_version: Corrupt cache for "
4055 : "key %s (len %u != 4) ?\n",
4056 : keystr, (unsigned int)dbuf.dsize);
4057 0 : state->bad_entry = true;
4058 0 : state->success = false;
4059 0 : return 1;
4060 : }
4061 :
4062 12 : DBG_DEBUG("validate_cache_version: %s ok\n", keystr);
4063 12 : return 0;
4064 : }
4065 :
4066 : /***********************************************************************
4067 : A list of all possible cache tdb keys with associated validation
4068 : functions.
4069 : ***********************************************************************/
4070 :
4071 : struct key_val_struct {
4072 : const char *keyname;
4073 : int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4074 : } key_val[] = {
4075 : {"SEQNUM/", validate_seqnum},
4076 : {"U/", validate_u},
4077 : {"LOC_POL/", validate_loc_pol},
4078 : {"PWD_POL/", validate_pwd_pol},
4079 : {"CRED/", validate_cred},
4080 : {"UL/", validate_ul},
4081 : {"GL/", validate_gl},
4082 : {"UG/", validate_ug},
4083 : {"UA", validate_ua},
4084 : {"GM/", validate_gm},
4085 : {"DR/", validate_dr},
4086 : {"DE/", validate_de},
4087 : {"TRUSTDOMCACHE/", validate_trustdomcache},
4088 : {"NSS/NA/", validate_nss_na},
4089 : {"NSS/AN/", validate_nss_an},
4090 : {"WINBINDD_OFFLINE", validate_offline},
4091 : {"NDR/", validate_ndr},
4092 : {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4093 : {NULL, NULL}
4094 : };
4095 :
4096 : /***********************************************************************
4097 : Function to look at every entry in the tdb and validate it as far as
4098 : possible.
4099 : ***********************************************************************/
4100 :
4101 60 : static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4102 : {
4103 0 : int i;
4104 60 : unsigned int max_key_len = 1024;
4105 60 : struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4106 :
4107 : /* Paranoia check. */
4108 60 : if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
4109 60 : strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
4110 0 : max_key_len = 1024 * 1024;
4111 : }
4112 60 : if (kbuf.dsize > max_key_len) {
4113 0 : DBG_ERR("cache_traverse_validate_fn: key length too large: "
4114 : "(%u) > (%u)\n\n",
4115 : (unsigned int)kbuf.dsize, (unsigned int)max_key_len);
4116 0 : return 1;
4117 : }
4118 :
4119 560 : for (i = 0; key_val[i].keyname; i++) {
4120 560 : size_t namelen = strlen(key_val[i].keyname);
4121 560 : if (kbuf.dsize >= namelen && (
4122 560 : strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4123 0 : TALLOC_CTX *mem_ctx;
4124 0 : char *keystr;
4125 0 : int ret;
4126 :
4127 60 : keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4128 60 : if (!keystr) {
4129 0 : return 1;
4130 : }
4131 60 : memcpy(keystr, kbuf.dptr, kbuf.dsize);
4132 60 : keystr[kbuf.dsize] = '\0';
4133 :
4134 60 : mem_ctx = talloc_init("validate_ctx");
4135 60 : if (!mem_ctx) {
4136 0 : SAFE_FREE(keystr);
4137 0 : return 1;
4138 : }
4139 :
4140 60 : ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4141 : v_state);
4142 :
4143 60 : SAFE_FREE(keystr);
4144 60 : talloc_destroy(mem_ctx);
4145 60 : return ret;
4146 : }
4147 : }
4148 :
4149 0 : DBG_ERR("cache_traverse_validate_fn: unknown cache entry\nkey :\n");
4150 0 : dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4151 0 : DBG_ERR("data :\n");
4152 0 : dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4153 0 : v_state->unknown_key = true;
4154 0 : v_state->success = false;
4155 0 : return 1; /* terminate. */
4156 : }
4157 :
4158 0 : static void validate_panic(const char *const why)
4159 : {
4160 0 : DBG_ERR("validating cache: would panic %s\n"
4161 : "exiting instead (cache validation mode)\n", why );
4162 0 : exit(47);
4163 : }
4164 :
4165 0 : static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4166 : TDB_DATA key,
4167 : TDB_DATA data,
4168 : void *state)
4169 : {
4170 0 : uint64_t ctimeout;
4171 0 : TDB_DATA blob;
4172 :
4173 0 : if (is_non_centry_key(key)) {
4174 0 : return 0;
4175 : }
4176 :
4177 0 : if (data.dptr == NULL || data.dsize == 0) {
4178 0 : if (tdb_delete(tdb, key) < 0) {
4179 0 : DBG_ERR("tdb_delete for [%s] failed!\n",
4180 : key.dptr);
4181 0 : return 1;
4182 : }
4183 : }
4184 :
4185 : /* add timeout to blob (uint64_t) */
4186 0 : blob.dsize = data.dsize + 8;
4187 :
4188 0 : blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4189 0 : if (blob.dptr == NULL) {
4190 0 : return 1;
4191 : }
4192 0 : memset(blob.dptr, 0, blob.dsize);
4193 :
4194 : /* copy status and seqnum */
4195 0 : memcpy(blob.dptr, data.dptr, 8);
4196 :
4197 : /* add timeout */
4198 0 : ctimeout = lp_winbind_cache_time() + time(NULL);
4199 0 : SBVAL(blob.dptr, 8, ctimeout);
4200 :
4201 : /* copy the rest */
4202 0 : memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4203 :
4204 0 : if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4205 0 : DBG_ERR("tdb_store to update [%s] failed!\n",
4206 : key.dptr);
4207 0 : SAFE_FREE(blob.dptr);
4208 0 : return 1;
4209 : }
4210 :
4211 0 : SAFE_FREE(blob.dptr);
4212 0 : return 0;
4213 : }
4214 :
4215 0 : static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4216 : {
4217 0 : int rc;
4218 :
4219 0 : DBG_NOTICE("Upgrade to version 2 of the winbindd_cache.tdb\n");
4220 :
4221 0 : rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4222 0 : if (rc < 0) {
4223 0 : return false;
4224 : }
4225 :
4226 0 : return true;
4227 : }
4228 :
4229 : /***********************************************************************
4230 : Try and validate every entry in the winbindd cache. If we fail here,
4231 : delete the cache tdb and return non-zero.
4232 : ***********************************************************************/
4233 :
4234 8 : int winbindd_validate_cache(void)
4235 : {
4236 8 : int ret = -1;
4237 8 : char *tdb_path = NULL;
4238 8 : TDB_CONTEXT *tdb = NULL;
4239 0 : uint32_t vers_id;
4240 0 : bool ok;
4241 :
4242 8 : DBG_DEBUG("winbindd_validate_cache: replacing panic function\n");
4243 8 : smb_panic_fn = validate_panic;
4244 :
4245 8 : tdb_path = wcache_path();
4246 8 : if (tdb_path == NULL) {
4247 0 : goto done;
4248 : }
4249 :
4250 8 : tdb = tdb_open_log(tdb_path,
4251 : WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4252 : TDB_INCOMPATIBLE_HASH |
4253 8 : ( lp_winbind_offline_logon()
4254 : ? TDB_DEFAULT
4255 : : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4256 : O_RDWR|O_CREAT,
4257 : 0600);
4258 8 : if (!tdb) {
4259 0 : DBG_ERR("winbindd_validate_cache: "
4260 : "error opening/initializing tdb\n");
4261 0 : goto done;
4262 : }
4263 :
4264 : /* Version check and upgrade code. */
4265 8 : if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4266 4 : DBG_DEBUG("Fresh database\n");
4267 4 : tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4268 4 : vers_id = WINBINDD_CACHE_VERSION;
4269 : }
4270 :
4271 8 : if (vers_id != WINBINDD_CACHE_VERSION) {
4272 0 : if (vers_id == WINBINDD_CACHE_VER1) {
4273 0 : ok = wbcache_upgrade_v1_to_v2(tdb);
4274 0 : if (!ok) {
4275 0 : DBG_DEBUG("winbindd_validate_cache: upgrade to version 2 failed.\n");
4276 0 : unlink(tdb_path);
4277 0 : goto done;
4278 : }
4279 :
4280 0 : tdb_store_uint32(tdb,
4281 : WINBINDD_CACHE_VERSION_KEYSTR,
4282 : WINBINDD_CACHE_VERSION);
4283 0 : vers_id = WINBINDD_CACHE_VER2;
4284 : }
4285 : }
4286 :
4287 8 : tdb_close(tdb);
4288 :
4289 8 : ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4290 :
4291 8 : if (ret != 0) {
4292 0 : DBG_DEBUG("winbindd_validate_cache: validation not successful.\n"
4293 : "removing tdb %s.\n", tdb_path);
4294 0 : unlink(tdb_path);
4295 : }
4296 :
4297 8 : done:
4298 8 : TALLOC_FREE(tdb_path);
4299 8 : DBG_DEBUG("winbindd_validate_cache: restoring panic function\n");
4300 8 : smb_panic_fn = smb_panic;
4301 8 : return ret;
4302 : }
4303 :
4304 : /***********************************************************************
4305 : Try and validate every entry in the winbindd cache.
4306 : ***********************************************************************/
4307 :
4308 0 : int winbindd_validate_cache_nobackup(void)
4309 : {
4310 0 : int ret = -1;
4311 0 : char *tdb_path;
4312 :
4313 0 : DBG_DEBUG("winbindd_validate_cache: replacing panic function\n");
4314 0 : smb_panic_fn = validate_panic;
4315 :
4316 0 : tdb_path = wcache_path();
4317 0 : if (tdb_path == NULL) {
4318 0 : goto err_panic_restore;
4319 : }
4320 :
4321 0 : if (wcache == NULL || wcache->tdb == NULL) {
4322 0 : ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4323 : } else {
4324 0 : ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4325 : }
4326 :
4327 0 : if (ret != 0) {
4328 0 : DBG_DEBUG("winbindd_validate_cache_nobackup: validation not "
4329 : "successful.\n");
4330 : }
4331 :
4332 0 : TALLOC_FREE(tdb_path);
4333 0 : err_panic_restore:
4334 0 : DBG_DEBUG("winbindd_validate_cache_nobackup: restoring panic "
4335 : "function\n");
4336 0 : smb_panic_fn = smb_panic;
4337 0 : return ret;
4338 : }
4339 :
4340 45 : bool winbindd_cache_validate_and_initialize(void)
4341 : {
4342 45 : close_winbindd_cache();
4343 :
4344 45 : if (lp_winbind_offline_logon()) {
4345 8 : if (winbindd_validate_cache() < 0) {
4346 0 : DBG_ERR("winbindd cache tdb corrupt and no backup "
4347 : "could be restored.\n");
4348 : }
4349 : }
4350 :
4351 45 : return initialize_winbindd_cache();
4352 : }
4353 :
4354 : /*********************************************************************
4355 : ********************************************************************/
4356 :
4357 135 : static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4358 : struct winbindd_tdc_domain **domains,
4359 : size_t *num_domains )
4360 : {
4361 135 : struct winbindd_tdc_domain *list = NULL;
4362 0 : size_t i, idx;
4363 135 : bool set_only = false;
4364 :
4365 : /* don't allow duplicates */
4366 :
4367 135 : idx = *num_domains;
4368 135 : list = *domains;
4369 :
4370 284 : for ( i=0; i< (*num_domains); i++ ) {
4371 153 : if ( strequal( new_dom->name, list[i].domain_name ) ) {
4372 4 : DBG_DEBUG("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4373 : new_dom->name);
4374 4 : idx = i;
4375 4 : set_only = true;
4376 :
4377 4 : break;
4378 : }
4379 : }
4380 :
4381 135 : if ( !set_only ) {
4382 131 : if ( !*domains ) {
4383 45 : list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4384 45 : idx = 0;
4385 : } else {
4386 86 : list = talloc_realloc( *domains, *domains,
4387 : struct winbindd_tdc_domain,
4388 : (*num_domains)+1);
4389 86 : idx = *num_domains;
4390 : }
4391 :
4392 131 : ZERO_STRUCT( list[idx] );
4393 : }
4394 :
4395 135 : if ( !list )
4396 0 : return false;
4397 :
4398 135 : list[idx].domain_name = talloc_strdup(list, new_dom->name);
4399 135 : if (list[idx].domain_name == NULL) {
4400 0 : return false;
4401 : }
4402 135 : if (new_dom->alt_name != NULL) {
4403 41 : list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4404 41 : if (list[idx].dns_name == NULL) {
4405 0 : return false;
4406 : }
4407 : }
4408 :
4409 135 : if ( !is_null_sid( &new_dom->sid ) ) {
4410 135 : sid_copy( &list[idx].sid, &new_dom->sid );
4411 : } else {
4412 0 : sid_copy(&list[idx].sid, &global_sid_NULL);
4413 : }
4414 :
4415 135 : if ( new_dom->domain_flags != 0x0 )
4416 90 : list[idx].trust_flags = new_dom->domain_flags;
4417 :
4418 135 : if ( new_dom->domain_type != 0x0 )
4419 129 : list[idx].trust_type = new_dom->domain_type;
4420 :
4421 135 : if ( new_dom->domain_trust_attribs != 0x0 )
4422 4 : list[idx].trust_attribs = new_dom->domain_trust_attribs;
4423 :
4424 135 : if ( !set_only ) {
4425 131 : *domains = list;
4426 131 : *num_domains = idx + 1;
4427 : }
4428 :
4429 135 : return true;
4430 : }
4431 :
4432 : /*********************************************************************
4433 : ********************************************************************/
4434 :
4435 391 : static TDB_DATA make_tdc_key( const char *domain_name )
4436 : {
4437 391 : char *keystr = NULL;
4438 391 : TDB_DATA key = { NULL, 0 };
4439 :
4440 391 : if ( !domain_name ) {
4441 0 : DBG_INFO("make_tdc_key: Keyname workgroup is NULL!\n");
4442 0 : return key;
4443 : }
4444 :
4445 391 : if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4446 0 : return key;
4447 : }
4448 391 : key = string_term_tdb_data(keystr);
4449 :
4450 391 : return key;
4451 : }
4452 :
4453 : /*********************************************************************
4454 : ********************************************************************/
4455 :
4456 135 : static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4457 : size_t num_domains,
4458 : unsigned char **buf )
4459 : {
4460 135 : unsigned char *buffer = NULL;
4461 135 : int len = 0;
4462 135 : int buflen = 0;
4463 135 : size_t i = 0;
4464 :
4465 135 : DBG_DEBUG("pack_tdc_domains: Packing %d trusted domains\n",
4466 : (int)num_domains);
4467 :
4468 135 : buflen = 0;
4469 :
4470 270 : again:
4471 270 : len = 0;
4472 :
4473 : /* Store the number of array items first */
4474 270 : len += tdb_pack( buffer ? buffer+len : NULL,
4475 : buffer ? buflen-len : 0, "d",
4476 : num_domains );
4477 :
4478 : /* now pack each domain trust record */
4479 842 : for ( i=0; i<num_domains; i++ ) {
4480 :
4481 0 : struct dom_sid_buf tmp;
4482 :
4483 572 : if ( buflen > 0 ) {
4484 286 : DBG_DEBUG("pack_tdc_domains: Packing domain %s (%s)\n",
4485 : domains[i].domain_name,
4486 : domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" );
4487 : }
4488 :
4489 1030 : len += tdb_pack( buffer ? buffer+len : NULL,
4490 : buffer ? buflen-len : 0, "fffddd",
4491 572 : domains[i].domain_name,
4492 572 : domains[i].dns_name ? domains[i].dns_name : "",
4493 572 : dom_sid_str_buf(&domains[i].sid, &tmp),
4494 572 : domains[i].trust_flags,
4495 572 : domains[i].trust_attribs,
4496 572 : domains[i].trust_type );
4497 : }
4498 :
4499 270 : if ( buflen < len ) {
4500 135 : SAFE_FREE(buffer);
4501 135 : if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4502 0 : DBG_ERR("pack_tdc_domains: failed to alloc buffer!\n");
4503 0 : buflen = -1;
4504 0 : goto done;
4505 : }
4506 135 : buflen = len;
4507 135 : goto again;
4508 : }
4509 :
4510 135 : *buf = buffer;
4511 :
4512 135 : done:
4513 135 : return buflen;
4514 : }
4515 :
4516 : /*********************************************************************
4517 : ********************************************************************/
4518 :
4519 166 : static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4520 : struct winbindd_tdc_domain **domains )
4521 : {
4522 0 : fstring domain_name, dns_name, sid_string;
4523 0 : uint32_t type, attribs, flags;
4524 0 : int num_domains;
4525 166 : int len = 0;
4526 0 : int i;
4527 166 : struct winbindd_tdc_domain *list = NULL;
4528 :
4529 : /* get the number of domains */
4530 166 : len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4531 166 : if ( len == -1 ) {
4532 0 : DBG_INFO("unpack_tdc_domains: Failed to unpack domain array\n");
4533 0 : return 0;
4534 : }
4535 :
4536 166 : list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4537 166 : if ( !list ) {
4538 0 : DBG_ERR("unpack_tdc_domains: Failed to talloc() domain list!\n");
4539 0 : return 0;
4540 : }
4541 :
4542 607 : for ( i=0; i<num_domains; i++ ) {
4543 0 : int this_len;
4544 :
4545 441 : this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4546 : domain_name,
4547 : dns_name,
4548 : sid_string,
4549 : &flags,
4550 : &attribs,
4551 : &type );
4552 :
4553 441 : if ( this_len == -1 ) {
4554 0 : DBG_INFO("unpack_tdc_domains: Failed to unpack domain array\n");
4555 0 : TALLOC_FREE( list );
4556 0 : return 0;
4557 : }
4558 441 : len += this_len;
4559 :
4560 441 : DBG_DEBUG("unpack_tdc_domains: Unpacking domain %s (%s) "
4561 : "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4562 : domain_name, dns_name, sid_string,
4563 : flags, attribs, type);
4564 :
4565 441 : list[i].domain_name = talloc_strdup( list, domain_name );
4566 441 : list[i].dns_name = NULL;
4567 441 : if (dns_name[0] != '\0') {
4568 128 : list[i].dns_name = talloc_strdup(list, dns_name);
4569 : }
4570 441 : if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4571 0 : DBG_DEBUG("unpack_tdc_domains: no SID for domain %s\n",
4572 : domain_name);
4573 : }
4574 441 : list[i].trust_flags = flags;
4575 441 : list[i].trust_attribs = attribs;
4576 441 : list[i].trust_type = type;
4577 : }
4578 :
4579 166 : *domains = list;
4580 :
4581 166 : return num_domains;
4582 : }
4583 :
4584 : /*********************************************************************
4585 : ********************************************************************/
4586 :
4587 180 : static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4588 : {
4589 180 : TDB_DATA key = make_tdc_key( lp_workgroup() );
4590 180 : TDB_DATA data = { NULL, 0 };
4591 0 : int ret;
4592 :
4593 180 : if ( !key.dptr )
4594 0 : return false;
4595 :
4596 : /* See if we were asked to delete the cache entry */
4597 :
4598 180 : if ( !domains ) {
4599 45 : ret = tdb_delete( wcache->tdb, key );
4600 45 : goto done;
4601 : }
4602 :
4603 135 : data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4604 :
4605 135 : if ( !data.dptr ) {
4606 0 : ret = -1;
4607 0 : goto done;
4608 : }
4609 :
4610 135 : ret = tdb_store(wcache->tdb, key, data, TDB_REPLACE);
4611 :
4612 180 : done:
4613 180 : SAFE_FREE( data.dptr );
4614 180 : SAFE_FREE( key.dptr );
4615 :
4616 180 : return ( ret == 0 );
4617 : }
4618 :
4619 : /*********************************************************************
4620 : ********************************************************************/
4621 :
4622 211 : bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4623 : {
4624 211 : TDB_DATA key = make_tdc_key( lp_workgroup() );
4625 211 : TDB_DATA data = { NULL, 0 };
4626 :
4627 211 : *domains = NULL;
4628 211 : *num_domains = 0;
4629 :
4630 211 : if ( !key.dptr )
4631 0 : return false;
4632 :
4633 211 : data = tdb_fetch( wcache->tdb, key );
4634 :
4635 211 : SAFE_FREE( key.dptr );
4636 :
4637 211 : if ( !data.dptr )
4638 45 : return false;
4639 :
4640 166 : *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4641 :
4642 166 : SAFE_FREE( data.dptr );
4643 :
4644 166 : if ( !*domains )
4645 0 : return false;
4646 :
4647 166 : return true;
4648 : }
4649 :
4650 : /*********************************************************************
4651 : ********************************************************************/
4652 :
4653 135 : bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4654 : {
4655 135 : struct winbindd_tdc_domain *dom_list = NULL;
4656 135 : size_t num_domains = 0;
4657 135 : bool ret = false;
4658 0 : struct dom_sid_buf buf;
4659 :
4660 135 : DBG_DEBUG("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4661 : "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4662 : domain->name, domain->alt_name,
4663 : dom_sid_str_buf(&domain->sid, &buf),
4664 : domain->domain_flags,
4665 : domain->domain_trust_attribs,
4666 : domain->domain_type);
4667 :
4668 135 : if ( !init_wcache() ) {
4669 0 : return false;
4670 : }
4671 :
4672 : /* fetch the list */
4673 :
4674 135 : wcache_tdc_fetch_list( &dom_list, &num_domains );
4675 :
4676 : /* add the new domain */
4677 :
4678 135 : if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4679 0 : goto done;
4680 : }
4681 :
4682 : /* pack the domain */
4683 :
4684 135 : if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4685 0 : goto done;
4686 : }
4687 :
4688 : /* Success */
4689 :
4690 135 : ret = true;
4691 135 : done:
4692 135 : TALLOC_FREE( dom_list );
4693 :
4694 135 : return ret;
4695 : }
4696 :
4697 0 : static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4698 : TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4699 : {
4700 0 : struct winbindd_tdc_domain *dst;
4701 :
4702 0 : dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4703 0 : if (dst == NULL) {
4704 0 : goto fail;
4705 : }
4706 0 : dst->domain_name = talloc_strdup(dst, src->domain_name);
4707 0 : if (dst->domain_name == NULL) {
4708 0 : goto fail;
4709 : }
4710 :
4711 0 : dst->dns_name = NULL;
4712 0 : if (src->dns_name != NULL) {
4713 0 : dst->dns_name = talloc_strdup(dst, src->dns_name);
4714 0 : if (dst->dns_name == NULL) {
4715 0 : goto fail;
4716 : }
4717 : }
4718 :
4719 0 : sid_copy(&dst->sid, &src->sid);
4720 0 : dst->trust_flags = src->trust_flags;
4721 0 : dst->trust_type = src->trust_type;
4722 0 : dst->trust_attribs = src->trust_attribs;
4723 0 : return dst;
4724 0 : fail:
4725 0 : TALLOC_FREE(dst);
4726 0 : return NULL;
4727 : }
4728 :
4729 : /*********************************************************************
4730 : ********************************************************************/
4731 :
4732 0 : struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4733 : {
4734 0 : struct winbindd_tdc_domain *dom_list = NULL;
4735 0 : size_t num_domains = 0;
4736 0 : size_t i;
4737 0 : struct winbindd_tdc_domain *d = NULL;
4738 :
4739 0 : DBG_DEBUG("wcache_tdc_fetch_domain: Searching for domain %s\n", name);
4740 :
4741 0 : if ( !init_wcache() ) {
4742 0 : return NULL;
4743 : }
4744 :
4745 : /* fetch the list */
4746 :
4747 0 : wcache_tdc_fetch_list( &dom_list, &num_domains );
4748 :
4749 0 : for ( i=0; i<num_domains; i++ ) {
4750 0 : if ( strequal(name, dom_list[i].domain_name) ||
4751 0 : strequal(name, dom_list[i].dns_name) )
4752 : {
4753 0 : DBG_DEBUG("wcache_tdc_fetch_domain: Found domain %s\n",
4754 : name);
4755 :
4756 0 : d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4757 0 : break;
4758 : }
4759 : }
4760 :
4761 0 : TALLOC_FREE( dom_list );
4762 :
4763 0 : return d;
4764 : }
4765 :
4766 : /*********************************************************************
4767 : ********************************************************************/
4768 :
4769 45 : void wcache_tdc_clear( void )
4770 : {
4771 45 : if ( !init_wcache() )
4772 0 : return;
4773 :
4774 45 : wcache_tdc_store_list( NULL, 0 );
4775 :
4776 45 : return;
4777 : }
4778 :
4779 108481 : static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4780 : uint32_t opnum, const DATA_BLOB *req,
4781 : TDB_DATA *pkey)
4782 : {
4783 0 : char *key;
4784 0 : size_t keylen;
4785 :
4786 108481 : key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4787 108481 : if (key == NULL) {
4788 0 : return false;
4789 : }
4790 108481 : keylen = talloc_get_size(key) - 1;
4791 :
4792 108481 : key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4793 108481 : if (key == NULL) {
4794 0 : return false;
4795 : }
4796 108481 : memcpy(key + keylen, req->data, req->length);
4797 :
4798 108481 : pkey->dptr = (uint8_t *)key;
4799 108481 : pkey->dsize = talloc_get_size(key);
4800 108481 : return true;
4801 : }
4802 :
4803 141863 : static bool wcache_opnum_cacheable(uint32_t opnum)
4804 : {
4805 141863 : switch (opnum) {
4806 139273 : case NDR_WBINT_LOOKUPSID:
4807 : case NDR_WBINT_LOOKUPSIDS:
4808 : case NDR_WBINT_LOOKUPNAME:
4809 : case NDR_WBINT_SIDS2UNIXIDS:
4810 : case NDR_WBINT_UNIXIDS2SIDS:
4811 : case NDR_WBINT_GETNSSINFO:
4812 : case NDR_WBINT_LOOKUPUSERALIASES:
4813 : case NDR_WBINT_LOOKUPUSERGROUPS:
4814 : case NDR_WBINT_LOOKUPGROUPMEMBERS:
4815 : case NDR_WBINT_QUERYGROUPLIST:
4816 : case NDR_WBINT_QUERYUSERRIDLIST:
4817 : case NDR_WBINT_DSGETDCNAME:
4818 : case NDR_WBINT_LOOKUPRIDS:
4819 139273 : return true;
4820 : }
4821 2590 : return false;
4822 : }
4823 :
4824 119116 : bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4825 : uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4826 : {
4827 0 : TDB_DATA key, data;
4828 119116 : bool ret = false;
4829 :
4830 236937 : if (!wcache_opnum_cacheable(opnum) ||
4831 223583 : is_my_own_sam_domain(domain) ||
4832 105762 : is_builtin_domain(domain)) {
4833 16034 : return false;
4834 : }
4835 :
4836 103082 : if (wcache->tdb == NULL) {
4837 0 : return false;
4838 : }
4839 :
4840 103082 : if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4841 0 : return false;
4842 : }
4843 103082 : data = tdb_fetch(wcache->tdb, key);
4844 103082 : TALLOC_FREE(key.dptr);
4845 :
4846 103082 : if (data.dptr == NULL) {
4847 4340 : return false;
4848 : }
4849 98742 : if (data.dsize < 12) {
4850 0 : goto fail;
4851 : }
4852 :
4853 98742 : if (is_domain_online(domain)) {
4854 0 : uint32_t entry_seqnum, dom_seqnum, last_check;
4855 0 : uint64_t entry_timeout;
4856 :
4857 98742 : if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4858 : &last_check)) {
4859 2373 : goto fail;
4860 : }
4861 98742 : entry_seqnum = IVAL(data.dptr, 0);
4862 98742 : if (entry_seqnum != dom_seqnum) {
4863 2364 : DBG_DEBUG("Entry has wrong sequence number: %d\n",
4864 : (int)entry_seqnum);
4865 2364 : goto fail;
4866 : }
4867 96378 : entry_timeout = BVAL(data.dptr, 4);
4868 96378 : if (time(NULL) > (time_t)entry_timeout) {
4869 9 : DBG_DEBUG("Entry has timed out\n");
4870 9 : goto fail;
4871 : }
4872 : }
4873 :
4874 96369 : resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4875 : data.dsize - 12);
4876 96369 : if (resp->data == NULL) {
4877 0 : DBG_DEBUG("talloc failed\n");
4878 0 : goto fail;
4879 : }
4880 96369 : resp->length = data.dsize - 12;
4881 :
4882 96369 : ret = true;
4883 98742 : fail:
4884 98742 : SAFE_FREE(data.dptr);
4885 98742 : return ret;
4886 : }
4887 :
4888 22747 : void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4889 : const DATA_BLOB *req, const DATA_BLOB *resp)
4890 : {
4891 0 : TDB_DATA key, data;
4892 0 : uint32_t dom_seqnum, last_check;
4893 0 : uint64_t timeout;
4894 :
4895 44199 : if (!wcache_opnum_cacheable(opnum) ||
4896 30845 : is_my_own_sam_domain(domain) ||
4897 9393 : is_builtin_domain(domain)) {
4898 16034 : return;
4899 : }
4900 :
4901 6713 : if (wcache->tdb == NULL) {
4902 0 : return;
4903 : }
4904 :
4905 6713 : if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4906 1314 : DBG_DEBUG("could not fetch seqnum for domain %s\n",
4907 : domain->name);
4908 1314 : return;
4909 : }
4910 :
4911 5399 : if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4912 0 : return;
4913 : }
4914 :
4915 5399 : timeout = time(NULL) + lp_winbind_cache_time();
4916 :
4917 5399 : data.dsize = resp->length + 12;
4918 5399 : data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4919 5399 : if (data.dptr == NULL) {
4920 0 : goto done;
4921 : }
4922 :
4923 5399 : SIVAL(data.dptr, 0, dom_seqnum);
4924 5399 : SBVAL(data.dptr, 4, timeout);
4925 5399 : memcpy(data.dptr + 12, resp->data, resp->length);
4926 :
4927 5399 : tdb_store(wcache->tdb, key, data, TDB_REPLACE);
4928 :
4929 5399 : done:
4930 5399 : TALLOC_FREE(key.dptr);
4931 5399 : return;
4932 : }
|