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 8 Copyright (C) Volker Lendecke 2005 9 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 2 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24*/ 25 26#include "includes.h" 27#include "winbindd.h" 28 29#undef DBGC_CLASS 30#define DBGC_CLASS DBGC_WINBIND 31 32struct winbind_cache { 33 TDB_CONTEXT *tdb; 34}; 35 36struct cache_entry { 37 NTSTATUS status; 38 uint32 sequence_number; 39 uint8 *data; 40 uint32 len, ofs; 41}; 42 43#define WINBINDD_MAX_CACHE_SIZE (50*1024*1024) 44 45static struct winbind_cache *wcache; 46 47/* flush the cache */ 48void wcache_flush_cache(void) 49{ 50 extern BOOL opt_nocache; 51 52 if (!wcache) 53 return; 54 if (wcache->tdb) { 55 tdb_close(wcache->tdb); 56 wcache->tdb = NULL; 57 } 58 if (opt_nocache) 59 return; 60 61 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000, 62 TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600); 63 64 if (!wcache->tdb) { 65 DEBUG(0,("Failed to open winbindd_cache.tdb!\n")); 66 } 67 DEBUG(10,("wcache_flush_cache success\n")); 68} 69 70void winbindd_check_cache_size(time_t t) 71{ 72 static time_t last_check_time; 73 struct stat st; 74 75 if (last_check_time == (time_t)0) 76 last_check_time = t; 77 78 if (t - last_check_time < 60 && t - last_check_time > 0) 79 return; 80 81 if (wcache == NULL || wcache->tdb == NULL) { 82 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n")); 83 return; 84 } 85 86 if (fstat(wcache->tdb->fd, &st) == -1) { 87 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) )); 88 return; 89 } 90 91 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) { 92 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n", 93 (unsigned long)st.st_size, 94 (unsigned long)WINBINDD_MAX_CACHE_SIZE)); 95 wcache_flush_cache(); 96 } 97} 98 99/* get the winbind_cache structure */ 100static struct winbind_cache *get_cache(struct winbindd_domain *domain) 101{ 102 struct winbind_cache *ret = wcache; 103 104 if (!domain->backend) { 105 extern struct winbindd_methods msrpc_methods; 106 switch (lp_security()) { 107#ifdef HAVE_ADS 108 case SEC_ADS: { 109 extern struct winbindd_methods ads_methods; 110 /* always obey the lp_security parameter for our domain */ 111 if (domain->primary) { 112 domain->backend = &ads_methods; 113 break; 114 } 115 116 /* only use ADS for native modes at the momment. 117 The problem is the correct detection of mixed 118 mode domains from NT4 BDC's --jerry */ 119 120 if ( domain->native_mode ) { 121 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", 122 domain->name)); 123 domain->backend = &ads_methods; 124 break; 125 } 126 127 /* fall through */ 128 } 129#endif 130 default: 131 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", 132 domain->name)); 133 domain->backend = &msrpc_methods; 134 } 135 } 136 137 if (ret) 138 return ret; 139 140 ret = SMB_XMALLOC_P(struct winbind_cache); 141 ZERO_STRUCTP(ret); 142 143 wcache = ret; 144 wcache_flush_cache(); 145 146 return ret; 147} 148 149/* 150 free a centry structure 151*/ 152static void centry_free(struct cache_entry *centry) 153{ 154 if (!centry) 155 return; 156 SAFE_FREE(centry->data); 157 free(centry); 158} 159 160/* 161 pull a uint32 from a cache entry 162*/ 163static uint32 centry_uint32(struct cache_entry *centry) 164{ 165 uint32 ret; 166 if (centry->len - centry->ofs < 4) { 167 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n", 168 centry->len - centry->ofs)); 169 smb_panic("centry_uint32"); 170 } 171 ret = IVAL(centry->data, centry->ofs); 172 centry->ofs += 4; 173 return ret; 174} 175 176/* 177 pull a uint8 from a cache entry 178*/ 179static uint8 centry_uint8(struct cache_entry *centry) 180{ 181 uint8 ret; 182 if (centry->len - centry->ofs < 1) { 183 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n", 184 centry->len - centry->ofs)); 185 smb_panic("centry_uint32"); 186 } 187 ret = CVAL(centry->data, centry->ofs); 188 centry->ofs += 1; 189 return ret; 190} 191 192/* pull a string from a cache entry, using the supplied 193 talloc context 194*/ 195static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx) 196{ 197 uint32 len; 198 char *ret; 199 200 len = centry_uint8(centry); 201 202 if (len == 0xFF) { 203 /* a deliberate NULL string */ 204 return NULL; 205 } 206 207 if (centry->len - centry->ofs < len) { 208 DEBUG(0,("centry corruption? needed %d bytes, have %d\n", 209 len, centry->len - centry->ofs)); 210 smb_panic("centry_string"); 211 } 212 213 ret = TALLOC(mem_ctx, len+1); 214 if (!ret) { 215 smb_panic("centry_string out of memory\n"); 216 } 217 memcpy(ret,centry->data + centry->ofs, len); 218 ret[len] = 0; 219 centry->ofs += len; 220 return ret; 221} 222 223/* pull a string from a cache entry, using the supplied 224 talloc context 225*/ 226static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx) 227{ 228 DOM_SID *sid; 229 char *sid_string; 230 231 sid = TALLOC_P(mem_ctx, DOM_SID); 232 if (!sid) 233 return NULL; 234 235 sid_string = centry_string(centry, mem_ctx); 236 if (!string_to_sid(sid, sid_string)) { 237 return NULL; 238 } 239 return sid; 240} 241 242/* the server is considered down if it can't give us a sequence number */ 243static BOOL wcache_server_down(struct winbindd_domain *domain) 244{ 245 BOOL ret; 246 247 if (!wcache->tdb) 248 return False; 249 250 ret = (domain->sequence_number == DOM_SEQUENCE_NONE); 251 252 if (ret) 253 DEBUG(10,("wcache_server_down: server for Domain %s down\n", 254 domain->name )); 255 return ret; 256} 257 258static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now ) 259{ 260 TDB_DATA data; 261 fstring key; 262 uint32 time_diff; 263 264 if (!wcache->tdb) { 265 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n")); 266 return NT_STATUS_UNSUCCESSFUL; 267 } 268 269 fstr_sprintf( key, "SEQNUM/%s", domain->name ); 270 271 data = tdb_fetch_bystring( wcache->tdb, key ); 272 if ( !data.dptr || data.dsize!=8 ) { 273 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key )); 274 return NT_STATUS_UNSUCCESSFUL; 275 } 276 277 domain->sequence_number = IVAL(data.dptr, 0); 278 domain->last_seq_check = IVAL(data.dptr, 4); 279 280 SAFE_FREE(data.dptr); 281 282 /* have we expired? */ 283 284 time_diff = now - domain->last_seq_check; 285 if ( time_diff > lp_winbind_cache_time() ) { 286 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n", 287 domain->name, domain->sequence_number, 288 (uint32)domain->last_seq_check)); 289 return NT_STATUS_UNSUCCESSFUL; 290 } 291 292 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n", 293 domain->name, domain->sequence_number, 294 (uint32)domain->last_seq_check)); 295 296 return NT_STATUS_OK; 297} 298 299static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain ) 300{ 301 TDB_DATA data, key; 302 fstring key_str; 303 char buf[8]; 304 305 if (!wcache->tdb) { 306 DEBUG(10,("store_cache_seqnum: tdb == NULL\n")); 307 return NT_STATUS_UNSUCCESSFUL; 308 } 309 310 fstr_sprintf( key_str, "SEQNUM/%s", domain->name ); 311 key.dptr = key_str; 312 key.dsize = strlen(key_str)+1; 313 314 SIVAL(buf, 0, domain->sequence_number); 315 SIVAL(buf, 4, domain->last_seq_check); 316 data.dptr = buf; 317 data.dsize = 8; 318 319 if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) { 320 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str )); 321 return NT_STATUS_UNSUCCESSFUL; 322 } 323 324 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n", 325 domain->name, domain->sequence_number, 326 (uint32)domain->last_seq_check)); 327 328 return NT_STATUS_OK; 329} 330 331/* 332 refresh the domain sequence number. If force is True 333 then always refresh it, no matter how recently we fetched it 334*/ 335 336static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force) 337{ 338 NTSTATUS status; 339 unsigned time_diff; 340 time_t t = time(NULL); 341 unsigned cache_time = lp_winbind_cache_time(); 342 343 get_cache( domain ); 344 345#if 0 /* JERRY -- disable as the default cache time is now 5 minutes */ 346 /* trying to reconnect is expensive, don't do it too often */ 347 if (domain->sequence_number == DOM_SEQUENCE_NONE) { 348 cache_time *= 8; 349 } 350#endif 351 352 time_diff = t - domain->last_seq_check; 353 354 /* see if we have to refetch the domain sequence number */ 355 if (!force && (time_diff < cache_time)) { 356 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name)); 357 goto done; 358 } 359 360 /* try to get the sequence number from the tdb cache first */ 361 /* this will update the timestamp as well */ 362 363 status = fetch_cache_seqnum( domain, t ); 364 if ( NT_STATUS_IS_OK(status) ) 365 goto done; 366 367 /* important! make sure that we know if this is a native 368 mode domain or not */ 369 370 if ( !domain->initialized ) 371 set_dc_type_and_flags( domain ); 372 373 status = domain->backend->sequence_number(domain, &domain->sequence_number); 374 375 if (!NT_STATUS_IS_OK(status)) { 376 domain->sequence_number = DOM_SEQUENCE_NONE; 377 } 378 379 domain->last_status = status; 380 domain->last_seq_check = time(NULL); 381 382 /* save the new sequence number ni the cache */ 383 store_cache_seqnum( domain ); 384 385done: 386 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n", 387 domain->name, domain->sequence_number)); 388 389 return; 390} 391 392/* 393 decide if a cache entry has expired 394*/ 395static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry) 396{ 397 /* if the server is OK and our cache entry came from when it was down then 398 the entry is invalid */ 399 if (domain->sequence_number != DOM_SEQUENCE_NONE && 400 centry->sequence_number == DOM_SEQUENCE_NONE) { 401 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n", 402 keystr, domain->name )); 403 return True; 404 } 405 406 /* if the server is down or the cache entry is not older than the 407 current sequence number then it is OK */ 408 if (wcache_server_down(domain) || 409 centry->sequence_number == domain->sequence_number) { 410 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n", 411 keystr, domain->name )); 412 return False; 413 } 414 415 DEBUG(10,("centry_expired: Key %s for domain %s expired\n", 416 keystr, domain->name )); 417 418 /* it's expired */ 419 return True; 420} 421 422/* 423 fetch an entry from the cache, with a varargs key. auto-fetch the sequence 424 number and return status 425*/ 426static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 427 struct winbindd_domain *domain, 428 const char *format, ...) PRINTF_ATTRIBUTE(3,4); 429static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 430 struct winbindd_domain *domain, 431 const char *format, ...) 432{ 433 va_list ap; 434 char *kstr; 435 TDB_DATA data; 436 struct cache_entry *centry; 437 TDB_DATA key; 438 439 refresh_sequence_number(domain, False); 440 441 va_start(ap, format); 442 smb_xvasprintf(&kstr, format, ap); 443 va_end(ap); 444 445 key.dptr = kstr; 446 key.dsize = strlen(kstr); 447 data = tdb_fetch(wcache->tdb, key); 448 if (!data.dptr) { 449 /* a cache miss */ 450 free(kstr); 451 return NULL; 452 } 453 454 centry = SMB_XMALLOC_P(struct cache_entry); 455 centry->data = (unsigned char *)data.dptr; 456 centry->len = data.dsize; 457 centry->ofs = 0; 458 459 if (centry->len < 8) { 460 /* huh? corrupt cache? */ 461 DEBUG(10,("wcache_fetch: Corrupt cache for key %s domain %s (len < 8) ?\n", 462 kstr, domain->name )); 463 centry_free(centry); 464 free(kstr); 465 return NULL; 466 } 467 468 centry->status = NT_STATUS(centry_uint32(centry)); 469 centry->sequence_number = centry_uint32(centry); 470 471 if (centry_expired(domain, kstr, centry)) { 472 extern BOOL opt_dual_daemon; 473 474 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n", 475 kstr, domain->name )); 476 477 if (opt_dual_daemon) { 478 extern BOOL background_process; 479 background_process = True; 480 DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n", 481 kstr, domain->name )); 482 } else { 483 centry_free(centry); 484 free(kstr); 485 return NULL; 486 } 487 } 488 489 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n", 490 kstr, domain->name )); 491 492 free(kstr); 493 return centry; 494} 495 496/* 497 make sure we have at least len bytes available in a centry 498*/ 499static void centry_expand(struct cache_entry *centry, uint32 len) 500{ 501 uint8 *p; 502 if (centry->len - centry->ofs >= len) 503 return; 504 centry->len *= 2; 505 p = SMB_REALLOC(centry->data, centry->len); 506 if (!p) { 507 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len)); 508 smb_panic("out of memory in centry_expand"); 509 } 510 centry->data = p; 511} 512 513/* 514 push a uint32 into a centry 515*/ 516static void centry_put_uint32(struct cache_entry *centry, uint32 v) 517{ 518 centry_expand(centry, 4); 519 SIVAL(centry->data, centry->ofs, v); 520 centry->ofs += 4; 521} 522 523/* 524 push a uint8 into a centry 525*/ 526static void centry_put_uint8(struct cache_entry *centry, uint8 v) 527{ 528 centry_expand(centry, 1); 529 SCVAL(centry->data, centry->ofs, v); 530 centry->ofs += 1; 531} 532 533/* 534 push a string into a centry 535 */ 536static void centry_put_string(struct cache_entry *centry, const char *s) 537{ 538 int len; 539 540 if (!s) { 541 /* null strings are marked as len 0xFFFF */ 542 centry_put_uint8(centry, 0xFF); 543 return; 544 } 545 546 len = strlen(s); 547 /* can't handle more than 254 char strings. Truncating is probably best */ 548 if (len > 254) 549 len = 254; 550 centry_put_uint8(centry, len); 551 centry_expand(centry, len); 552 memcpy(centry->data + centry->ofs, s, len); 553 centry->ofs += len; 554} 555 556static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid) 557{ 558 fstring sid_string; 559 centry_put_string(centry, sid_to_string(sid_string, sid)); 560} 561 562/* 563 start a centry for output. When finished, call centry_end() 564*/ 565struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status) 566{ 567 struct cache_entry *centry; 568 569 if (!wcache->tdb) 570 return NULL; 571 572 centry = SMB_XMALLOC_P(struct cache_entry); 573 574 centry->len = 8192; /* reasonable default */ 575 centry->data = SMB_XMALLOC_ARRAY(char, centry->len); 576 centry->ofs = 0; 577 centry->sequence_number = domain->sequence_number; 578 centry_put_uint32(centry, NT_STATUS_V(status)); 579 centry_put_uint32(centry, centry->sequence_number); 580 return centry; 581} 582 583/* 584 finish a centry and write it to the tdb 585*/ 586static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3); 587static void centry_end(struct cache_entry *centry, const char *format, ...) 588{ 589 va_list ap; 590 char *kstr; 591 TDB_DATA key, data; 592 593 va_start(ap, format); 594 smb_xvasprintf(&kstr, format, ap); 595 va_end(ap); 596 597 key.dptr = kstr; 598 key.dsize = strlen(kstr); 599 data.dptr = (char *)centry->data; 600 data.dsize = centry->ofs; 601 602 tdb_store(wcache->tdb, key, data, TDB_REPLACE); 603 free(kstr); 604} 605 606static void wcache_save_name_to_sid(struct winbindd_domain *domain, 607 NTSTATUS status, const char *domain_name, 608 const char *name, const DOM_SID *sid, 609 enum SID_NAME_USE type) 610{ 611 struct cache_entry *centry; 612 fstring uname; 613 614 centry = centry_start(domain, status); 615 if (!centry) 616 return; 617 centry_put_uint32(centry, type); 618 centry_put_sid(centry, sid); 619 fstrcpy(uname, name); 620 strupper_m(uname); 621 centry_end(centry, "NS/%s/%s", domain_name, uname); 622 DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname, 623 sid_string_static(sid))); 624 centry_free(centry); 625} 626 627static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 628 const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type) 629{ 630 struct cache_entry *centry; 631 fstring sid_string; 632 633 centry = centry_start(domain, status); 634 if (!centry) 635 return; 636 if (NT_STATUS_IS_OK(status)) { 637 centry_put_uint32(centry, type); 638 centry_put_string(centry, domain_name); 639 centry_put_string(centry, name); 640 } 641 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid)); 642 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name)); 643 centry_free(centry); 644} 645 646 647static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info) 648{ 649 struct cache_entry *centry; 650 fstring sid_string; 651 652 centry = centry_start(domain, status); 653 if (!centry) 654 return; 655 centry_put_string(centry, info->acct_name); 656 centry_put_string(centry, info->full_name); 657 centry_put_sid(centry, info->user_sid); 658 centry_put_sid(centry, info->group_sid); 659 centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid)); 660 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name)); 661 centry_free(centry); 662} 663 664 665/* Query display info. This is the basic user list fn */ 666static NTSTATUS query_user_list(struct winbindd_domain *domain, 667 TALLOC_CTX *mem_ctx, 668 uint32 *num_entries, 669 WINBIND_USERINFO **info) 670{ 671 struct winbind_cache *cache = get_cache(domain); 672 struct cache_entry *centry = NULL; 673 NTSTATUS status; 674 unsigned int i, retry; 675 676 if (!cache->tdb) 677 goto do_query; 678 679 centry = wcache_fetch(cache, domain, "UL/%s", domain->name); 680 if (!centry) 681 goto do_query; 682 683 *num_entries = centry_uint32(centry); 684 685 if (*num_entries == 0) 686 goto do_cached; 687 688 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries); 689 if (! (*info)) 690 smb_panic("query_user_list out of memory"); 691 for (i=0; i<(*num_entries); i++) { 692 (*info)[i].acct_name = centry_string(centry, mem_ctx); 693 (*info)[i].full_name = centry_string(centry, mem_ctx); 694 (*info)[i].user_sid = centry_sid(centry, mem_ctx); 695 (*info)[i].group_sid = centry_sid(centry, mem_ctx); 696 } 697 698do_cached: 699 status = centry->status; 700 701 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status %s\n", 702 domain->name, get_friendly_nt_error_msg(status) )); 703 704 centry_free(centry); 705 return status; 706 707do_query: 708 *num_entries = 0; 709 *info = NULL; 710 711 /* Return status value returned by seq number check */ 712 713 if (!NT_STATUS_IS_OK(domain->last_status)) 714 return domain->last_status; 715 716 /* Put the query_user_list() in a retry loop. There appears to be 717 * some bug either with Windows 2000 or Samba's handling of large 718 * rpc replies. This manifests itself as sudden disconnection 719 * at a random point in the enumeration of a large (60k) user list. 720 * The retry loop simply tries the operation again. )-: It's not 721 * pretty but an acceptable workaround until we work out what the 722 * real problem is. */ 723 724 retry = 0; 725 do { 726 727 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n", 728 domain->name )); 729 730 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info); 731 if (!NT_STATUS_IS_OK(status)) 732 DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status))); 733 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) { 734 DEBUG(3, ("query_user_list: flushing connection cache\n")); 735 winbindd_cm_flush(); 736 } 737 738 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && 739 (retry++ < 5)); 740 741 /* and save it */ 742 refresh_sequence_number(domain, False); 743 centry = centry_start(domain, status); 744 if (!centry) 745 goto skip_save; 746 centry_put_uint32(centry, *num_entries); 747 for (i=0; i<(*num_entries); i++) { 748 centry_put_string(centry, (*info)[i].acct_name); 749 centry_put_string(centry, (*info)[i].full_name); 750 centry_put_sid(centry, (*info)[i].user_sid); 751 centry_put_sid(centry, (*info)[i].group_sid); 752 if (domain->backend->consistent) { 753 /* when the backend is consistent we can pre-prime some mappings */ 754 wcache_save_name_to_sid(domain, NT_STATUS_OK, 755 domain->name, 756 (*info)[i].acct_name, 757 (*info)[i].user_sid, 758 SID_NAME_USER); 759 wcache_save_sid_to_name(domain, NT_STATUS_OK, 760 (*info)[i].user_sid, 761 domain->name, 762 (*info)[i].acct_name, 763 SID_NAME_USER); 764 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]); 765 } 766 } 767 centry_end(centry, "UL/%s", domain->name); 768 centry_free(centry); 769 770skip_save: 771 return status; 772} 773 774/* list all domain groups */ 775static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, 776 TALLOC_CTX *mem_ctx, 777 uint32 *num_entries, 778 struct acct_info **info) 779{ 780 struct winbind_cache *cache = get_cache(domain); 781 struct cache_entry *centry = NULL; 782 NTSTATUS status; 783 unsigned int i; 784 785 if (!cache->tdb) 786 goto do_query; 787 788 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name); 789 if (!centry) 790 goto do_query; 791 792 *num_entries = centry_uint32(centry); 793 794 if (*num_entries == 0) 795 goto do_cached; 796 797 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries); 798 if (! (*info)) 799 smb_panic("enum_dom_groups out of memory"); 800 for (i=0; i<(*num_entries); i++) { 801 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx)); 802 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx)); 803 (*info)[i].rid = centry_uint32(centry); 804 } 805 806do_cached: 807 status = centry->status; 808 809 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status %s\n", 810 domain->name, get_friendly_nt_error_msg(status) )); 811 812 centry_free(centry); 813 return status; 814 815do_query: 816 *num_entries = 0; 817 *info = NULL; 818 819 /* Return status value returned by seq number check */ 820 821 if (!NT_STATUS_IS_OK(domain->last_status)) 822 return domain->last_status; 823 824 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n", 825 domain->name )); 826 827 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info); 828 829 /* and save it */ 830 refresh_sequence_number(domain, False); 831 centry = centry_start(domain, status); 832 if (!centry) 833 goto skip_save; 834 centry_put_uint32(centry, *num_entries); 835 for (i=0; i<(*num_entries); i++) { 836 centry_put_string(centry, (*info)[i].acct_name); 837 centry_put_string(centry, (*info)[i].acct_desc); 838 centry_put_uint32(centry, (*info)[i].rid); 839 } 840 centry_end(centry, "GL/%s/domain", domain->name); 841 centry_free(centry); 842 843skip_save: 844 return status; 845} 846 847/* list all domain groups */ 848static NTSTATUS enum_local_groups(struct winbindd_domain *domain, 849 TALLOC_CTX *mem_ctx, 850 uint32 *num_entries, 851 struct acct_info **info) 852{ 853 struct winbind_cache *cache = get_cache(domain); 854 struct cache_entry *centry = NULL; 855 NTSTATUS status; 856 unsigned int i; 857 858 if (!cache->tdb) 859 goto do_query; 860 861 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name); 862 if (!centry) 863 goto do_query; 864 865 *num_entries = centry_uint32(centry); 866 867 if (*num_entries == 0) 868 goto do_cached; 869 870 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries); 871 if (! (*info)) 872 smb_panic("enum_dom_groups out of memory"); 873 for (i=0; i<(*num_entries); i++) { 874 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx)); 875 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx)); 876 (*info)[i].rid = centry_uint32(centry); 877 } 878 879do_cached: 880 881 /* If we are returning cached data and the domain controller 882 is down then we don't know whether the data is up to date 883 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to 884 indicate this. */ 885 886 if (wcache_server_down(domain)) { 887 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n")); 888 status = NT_STATUS_MORE_PROCESSING_REQUIRED; 889 } else 890 status = centry->status; 891 892 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status %s\n", 893 domain->name, get_friendly_nt_error_msg(status) )); 894 895 centry_free(centry); 896 return status; 897 898do_query: 899 *num_entries = 0; 900 *info = NULL; 901 902 /* Return status value returned by seq number check */ 903 904 if (!NT_STATUS_IS_OK(domain->last_status)) 905 return domain->last_status; 906 907 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n", 908 domain->name )); 909 910 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info); 911 912 /* and save it */ 913 refresh_sequence_number(domain, False); 914 centry = centry_start(domain, status); 915 if (!centry) 916 goto skip_save; 917 centry_put_uint32(centry, *num_entries); 918 for (i=0; i<(*num_entries); i++) { 919 centry_put_string(centry, (*info)[i].acct_name); 920 centry_put_string(centry, (*info)[i].acct_desc); 921 centry_put_uint32(centry, (*info)[i].rid); 922 } 923 centry_end(centry, "GL/%s/local", domain->name); 924 centry_free(centry); 925 926skip_save: 927 return status; 928} 929 930/* convert a single name to a sid in a domain */ 931static NTSTATUS name_to_sid(struct winbindd_domain *domain, 932 TALLOC_CTX *mem_ctx, 933 const char *domain_name, 934 const char *name, 935 DOM_SID *sid, 936 enum SID_NAME_USE *type) 937{ 938 struct winbind_cache *cache = get_cache(domain); 939 struct cache_entry *centry = NULL; 940 NTSTATUS status; 941 fstring uname; 942 DOM_SID *sid2; 943 944 if (!cache->tdb) 945 goto do_query; 946 947 fstrcpy(uname, name); 948 strupper_m(uname); 949 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname); 950 if (!centry) 951 goto do_query; 952 *type = (enum SID_NAME_USE)centry_uint32(centry); 953 sid2 = centry_sid(centry, mem_ctx); 954 if (!sid2) { 955 ZERO_STRUCTP(sid); 956 } else { 957 sid_copy(sid, sid2); 958 } 959 960 status = centry->status; 961 962 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n", 963 domain->name, get_friendly_nt_error_msg(status) )); 964 965 centry_free(centry); 966 return status; 967 968do_query: 969 ZERO_STRUCTP(sid); 970 971 /* If the seq number check indicated that there is a problem 972 * with this DC, then return that status... except for 973 * access_denied. This is special because the dc may be in 974 * "restrict anonymous = 1" mode, in which case it will deny 975 * most unauthenticated operations, but *will* allow the LSA 976 * name-to-sid that we try as a fallback. */ 977 978 if (!(NT_STATUS_IS_OK(domain->last_status) 979 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED))) 980 return domain->last_status; 981 982 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n", 983 domain->name )); 984 985 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type); 986 987 /* and save it */ 988 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type); 989 990 /* We can't save the sid to name mapping as we don't know the 991 correct case of the name without looking it up */ 992 993 return status; 994} 995 996/* convert a sid to a user or group name. The sid is guaranteed to be in the domain 997 given */ 998static NTSTATUS sid_to_name(struct winbindd_domain *domain, 999 TALLOC_CTX *mem_ctx, 1000 const DOM_SID *sid, 1001 char **domain_name, 1002 char **name, 1003 enum SID_NAME_USE *type) 1004{ 1005 struct winbind_cache *cache = get_cache(domain); 1006 struct cache_entry *centry = NULL; 1007 NTSTATUS status; 1008 fstring sid_string; 1009 1010 if (!cache->tdb) 1011 goto do_query; 1012 1013 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid)); 1014 if (!centry) 1015 goto do_query; 1016 if (NT_STATUS_IS_OK(centry->status)) { 1017 *type = (enum SID_NAME_USE)centry_uint32(centry); 1018 *domain_name = centry_string(centry, mem_ctx); 1019 *name = centry_string(centry, mem_ctx); 1020 } 1021 status = centry->status; 1022 1023 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status %s\n", 1024 domain->name, get_friendly_nt_error_msg(status) )); 1025 1026 centry_free(centry); 1027 return status; 1028 1029do_query: 1030 *name = NULL; 1031 *domain_name = NULL; 1032 1033 /* If the seq number check indicated that there is a problem 1034 * with this DC, then return that status... except for 1035 * access_denied. This is special because the dc may be in 1036 * "restrict anonymous = 1" mode, in which case it will deny 1037 * most unauthenticated operations, but *will* allow the LSA 1038 * sid-to-name that we try as a fallback. */ 1039 1040 if (!(NT_STATUS_IS_OK(domain->last_status) 1041 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED))) 1042 return domain->last_status; 1043 1044 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n", 1045 domain->name )); 1046 1047 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type); 1048 1049 /* and save it */ 1050 refresh_sequence_number(domain, False); 1051 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type); 1052 1053 /* We can't save the name to sid mapping here, as with sid history a 1054 * later name2sid would give the wrong sid. */ 1055 1056 return status; 1057} 1058 1059 1060/* Lookup user information from a rid */ 1061static NTSTATUS query_user(struct winbindd_domain *domain, 1062 TALLOC_CTX *mem_ctx, 1063 const DOM_SID *user_sid, 1064 WINBIND_USERINFO *info) 1065{ 1066 struct winbind_cache *cache = get_cache(domain); 1067 struct cache_entry *centry = NULL; 1068 NTSTATUS status; 1069 1070 if (!cache->tdb) 1071 goto do_query; 1072 1073 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid)); 1074 1075 /* If we have an access denied cache entry and a cached info3 in the 1076 samlogon cache then do a query. This will force the rpc back end 1077 to return the info3 data. */ 1078 1079 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) && 1080 netsamlogon_cache_have(user_sid)) { 1081 DEBUG(10, ("query_user: cached access denied and have cached info3\n")); 1082 domain->last_status = NT_STATUS_OK; 1083 centry_free(centry); 1084 goto do_query; 1085 } 1086 1087 if (!centry) 1088 goto do_query; 1089 1090 info->acct_name = centry_string(centry, mem_ctx); 1091 info->full_name = centry_string(centry, mem_ctx); 1092 info->user_sid = centry_sid(centry, mem_ctx); 1093 info->group_sid = centry_sid(centry, mem_ctx); 1094 status = centry->status; 1095 1096 DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n", 1097 domain->name, get_friendly_nt_error_msg(status) )); 1098 1099 centry_free(centry); 1100 return status; 1101 1102do_query: 1103 ZERO_STRUCTP(info); 1104 1105 /* Return status value returned by seq number check */ 1106 1107 if (!NT_STATUS_IS_OK(domain->last_status)) 1108 return domain->last_status; 1109 1110 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n", 1111 domain->name )); 1112 1113 status = domain->backend->query_user(domain, mem_ctx, user_sid, info); 1114 1115 /* and save it */ 1116 refresh_sequence_number(domain, False); 1117 wcache_save_user(domain, status, info); 1118 1119 return status; 1120} 1121 1122 1123/* Lookup groups a user is a member of. */ 1124static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, 1125 TALLOC_CTX *mem_ctx, 1126 const DOM_SID *user_sid, 1127 uint32 *num_groups, DOM_SID ***user_gids) 1128{ 1129 struct winbind_cache *cache = get_cache(domain); 1130 struct cache_entry *centry = NULL; 1131 NTSTATUS status; 1132 unsigned int i; 1133 fstring sid_string; 1134 1135 if (!cache->tdb) 1136 goto do_query; 1137 1138 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid)); 1139 1140 /* If we have an access denied cache entry and a cached info3 in the 1141 samlogon cache then do a query. This will force the rpc back end 1142 to return the info3 data. */ 1143 1144 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) && 1145 netsamlogon_cache_have(user_sid)) { 1146 DEBUG(10, ("query_user: cached access denied and have cached info3\n")); 1147 domain->last_status = NT_STATUS_OK; 1148 centry_free(centry); 1149 goto do_query; 1150 } 1151 1152 if (!centry) 1153 goto do_query; 1154 1155 *num_groups = centry_uint32(centry); 1156 1157 if (*num_groups == 0) 1158 goto do_cached; 1159 1160 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups); 1161 if (! (*user_gids)) 1162 smb_panic("lookup_usergroups out of memory"); 1163 for (i=0; i<(*num_groups); i++) { 1164 (*user_gids)[i] = centry_sid(centry, mem_ctx); 1165 } 1166 1167do_cached: 1168 status = centry->status; 1169 1170 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status %s\n", 1171 domain->name, get_friendly_nt_error_msg(status) )); 1172 1173 centry_free(centry); 1174 return status; 1175 1176do_query: 1177 (*num_groups) = 0; 1178 (*user_gids) = NULL; 1179 1180 /* Return status value returned by seq number check */ 1181 1182 if (!NT_STATUS_IS_OK(domain->last_status)) 1183 return domain->last_status; 1184 1185 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n", 1186 domain->name )); 1187 1188 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids); 1189 1190 /* and save it */ 1191 refresh_sequence_number(domain, False); 1192 centry = centry_start(domain, status); 1193 if (!centry) 1194 goto skip_save; 1195 centry_put_uint32(centry, *num_groups); 1196 for (i=0; i<(*num_groups); i++) { 1197 centry_put_sid(centry, (*user_gids)[i]); 1198 } 1199 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid)); 1200 centry_free(centry); 1201 1202skip_save: 1203 return status; 1204} 1205 1206static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, 1207 TALLOC_CTX *mem_ctx, 1208 uint32 num_sids, DOM_SID **sids, 1209 uint32 *num_aliases, uint32 **alias_rids) 1210{ 1211 struct winbind_cache *cache = get_cache(domain); 1212 struct cache_entry *centry = NULL; 1213 NTSTATUS status; 1214 char *sidlist = talloc_strdup(mem_ctx, ""); 1215 int i; 1216 1217 if (!cache->tdb) 1218 goto do_query; 1219 1220 if (num_sids == 0) { 1221 *num_aliases = 0; 1222 *alias_rids = NULL; 1223 return NT_STATUS_OK; 1224 } 1225 1226 /* We need to cache indexed by the whole list of SIDs, the aliases 1227 * resulting might come from any of the SIDs. */ 1228 1229 for (i=0; i<num_sids; i++) { 1230 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist, 1231 sid_string_static(sids[i])); 1232 if (sidlist == NULL) 1233 return NT_STATUS_NO_MEMORY; 1234 } 1235 1236 centry = wcache_fetch(cache, domain, "UA%s", sidlist); 1237 1238 if (!centry) 1239 goto do_query; 1240 1241 *num_aliases = centry_uint32(centry); 1242 *alias_rids = NULL; 1243 1244 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases); 1245 1246 if ((*num_aliases != 0) && ((*alias_rids) == NULL)) 1247 return NT_STATUS_NO_MEMORY; 1248 1249 for (i=0; i<(*num_aliases); i++) 1250 (*alias_rids)[i] = centry_uint32(centry); 1251 1252 status = centry->status; 1253 1254 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain %s " 1255 "status %s\n", domain->name, 1256 get_friendly_nt_error_msg(status))); 1257 1258 centry_free(centry); 1259 return status; 1260 1261 do_query: 1262 (*num_aliases) = 0; 1263 (*alias_rids) = NULL; 1264 1265 if (!NT_STATUS_IS_OK(domain->last_status)) 1266 return domain->last_status; 1267 1268 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info " 1269 "for domain %s\n", domain->name )); 1270 1271 status = domain->backend->lookup_useraliases(domain, mem_ctx, 1272 num_sids, sids, 1273 num_aliases, alias_rids); 1274 1275 /* and save it */ 1276 refresh_sequence_number(domain, False); 1277 centry = centry_start(domain, status); 1278 if (!centry) 1279 goto skip_save; 1280 centry_put_uint32(centry, *num_aliases); 1281 for (i=0; i<(*num_aliases); i++) 1282 centry_put_uint32(centry, (*alias_rids)[i]); 1283 centry_end(centry, "UA%s", sidlist); 1284 centry_free(centry); 1285 1286 skip_save: 1287 return status; 1288} 1289 1290 1291static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, 1292 TALLOC_CTX *mem_ctx, 1293 const DOM_SID *group_sid, uint32 *num_names, 1294 DOM_SID ***sid_mem, char ***names, 1295 uint32 **name_types) 1296{ 1297 struct winbind_cache *cache = get_cache(domain); 1298 struct cache_entry *centry = NULL; 1299 NTSTATUS status; 1300 unsigned int i; 1301 fstring sid_string; 1302 1303 if (!cache->tdb) 1304 goto do_query; 1305 1306 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid)); 1307 if (!centry) 1308 goto do_query; 1309 1310 *num_names = centry_uint32(centry); 1311 1312 if (*num_names == 0) 1313 goto do_cached; 1314 1315 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_names); 1316 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names); 1317 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names); 1318 1319 if (! (*sid_mem) || ! (*names) || ! (*name_types)) { 1320 smb_panic("lookup_groupmem out of memory"); 1321 } 1322 1323 for (i=0; i<(*num_names); i++) { 1324 (*sid_mem)[i] = centry_sid(centry, mem_ctx); 1325 (*names)[i] = centry_string(centry, mem_ctx); 1326 (*name_types)[i] = centry_uint32(centry); 1327 } 1328 1329do_cached: 1330 status = centry->status; 1331 1332 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status %s\n", 1333 domain->name, get_friendly_nt_error_msg(status) )); 1334 1335 centry_free(centry); 1336 return status; 1337 1338do_query: 1339 (*num_names) = 0; 1340 (*sid_mem) = NULL; 1341 (*names) = NULL; 1342 (*name_types) = NULL; 1343 1344 /* Return status value returned by seq number check */ 1345 1346 if (!NT_STATUS_IS_OK(domain->last_status)) 1347 return domain->last_status; 1348 1349 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n", 1350 domain->name )); 1351 1352 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names, 1353 sid_mem, names, name_types); 1354 1355 /* and save it */ 1356 refresh_sequence_number(domain, False); 1357 centry = centry_start(domain, status); 1358 if (!centry) 1359 goto skip_save; 1360 centry_put_uint32(centry, *num_names); 1361 for (i=0; i<(*num_names); i++) { 1362 centry_put_sid(centry, (*sid_mem)[i]); 1363 centry_put_string(centry, (*names)[i]); 1364 centry_put_uint32(centry, (*name_types)[i]); 1365 } 1366 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid)); 1367 centry_free(centry); 1368 1369skip_save: 1370 return status; 1371} 1372 1373/* find the sequence number for a domain */ 1374static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) 1375{ 1376 refresh_sequence_number(domain, False); 1377 1378 *seq = domain->sequence_number; 1379 1380 return NT_STATUS_OK; 1381} 1382 1383/* enumerate trusted domains */ 1384static NTSTATUS trusted_domains(struct winbindd_domain *domain, 1385 TALLOC_CTX *mem_ctx, 1386 uint32 *num_domains, 1387 char ***names, 1388 char ***alt_names, 1389 DOM_SID **dom_sids) 1390{ 1391 get_cache(domain); 1392 1393 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n", 1394 domain->name )); 1395 1396 /* we don't cache this call */ 1397 return domain->backend->trusted_domains(domain, mem_ctx, num_domains, 1398 names, alt_names, dom_sids); 1399} 1400 1401/* find the domain sid */ 1402static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid) 1403{ 1404 get_cache(domain); 1405 1406 DEBUG(10,("domain_sid: [Cached] - doing backend query for info for domain %s\n", 1407 domain->name )); 1408 1409 /* we don't cache this call */ 1410 return domain->backend->domain_sid(domain, sid); 1411} 1412 1413/* find the alternate names for the domain, if any */ 1414static NTSTATUS alternate_name(struct winbindd_domain *domain) 1415{ 1416 get_cache(domain); 1417 1418 DEBUG(10,("alternate_name: [Cached] - doing backend query for info for domain %s\n", 1419 domain->name )); 1420 1421 /* we don't cache this call */ 1422 return domain->backend->alternate_name(domain); 1423} 1424 1425/* Invalidate cached user and group lists coherently */ 1426 1427static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 1428 void *state) 1429{ 1430 if (strncmp(kbuf.dptr, "UL/", 3) == 0 || 1431 strncmp(kbuf.dptr, "GL/", 3) == 0) 1432 tdb_delete(the_tdb, kbuf); 1433 1434 return 0; 1435} 1436 1437/* Invalidate the getpwnam and getgroups entries for a winbindd domain */ 1438 1439void wcache_invalidate_samlogon(struct winbindd_domain *domain, 1440 NET_USER_INFO_3 *info3) 1441{ 1442 struct winbind_cache *cache; 1443 1444 if (!domain) 1445 return; 1446 1447 cache = get_cache(domain); 1448 netsamlogon_clear_cached_user(cache->tdb, info3); 1449} 1450 1451void wcache_invalidate_cache(void) 1452{ 1453 struct winbindd_domain *domain; 1454 1455 for (domain = domain_list(); domain; domain = domain->next) { 1456 struct winbind_cache *cache = get_cache(domain); 1457 1458 DEBUG(10, ("wcache_invalidate_cache: invalidating cache " 1459 "entries for %s\n", domain->name)); 1460 if (cache) 1461 tdb_traverse(cache->tdb, traverse_fn, NULL); 1462 } 1463} 1464 1465/* the ADS backend methods are exposed via this structure */ 1466struct winbindd_methods cache_methods = { 1467 True, 1468 query_user_list, 1469 enum_dom_groups, 1470 enum_local_groups, 1471 name_to_sid, 1472 sid_to_name, 1473 query_user, 1474 lookup_usergroups, 1475 lookup_useraliases, 1476 lookup_groupmem, 1477 sequence_number, 1478 trusted_domains, 1479 domain_sid, 1480 alternate_name 1481}; 1482