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