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