1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind ADS backend functions 5 6 Copyright (C) Andrew Tridgell 2001 7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 8 Copyright (C) Gerald (Jerry) Carter 2004 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 2 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23*/ 24 25#include "includes.h" 26#include "winbindd.h" 27 28#ifdef HAVE_ADS 29 30#undef DBGC_CLASS 31#define DBGC_CLASS DBGC_WINBIND 32 33/* 34 return our ads connections structure for a domain. We keep the connection 35 open to make things faster 36*/ 37static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) 38{ 39 ADS_STRUCT *ads; 40 ADS_STATUS status; 41 42 if (domain->private) { 43 ads = (ADS_STRUCT *)domain->private; 44 45 /* check for a valid structure */ 46 47 DEBUG(7, ("Current tickets expire at %d, time is now %d\n", 48 (uint32) ads->auth.expire, (uint32) time(NULL))); 49 if ( ads->config.realm && (ads->auth.expire > time(NULL))) { 50 return ads; 51 } 52 else { 53 /* we own this ADS_STRUCT so make sure it goes away */ 54 ads->is_mine = True; 55 ads_destroy( &ads ); 56 ads_kdestroy("MEMORY:winbind_ccache"); 57 domain->private = NULL; 58 } 59 } 60 61 /* we don't want this to affect the users ccache */ 62 setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1); 63 64 ads = ads_init(domain->alt_name, domain->name, NULL); 65 if (!ads) { 66 DEBUG(1,("ads_init for domain %s failed\n", domain->name)); 67 return NULL; 68 } 69 70 /* the machine acct password might have change - fetch it every time */ 71 SAFE_FREE(ads->auth.password); 72 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); 73 74 SAFE_FREE(ads->auth.realm); 75 ads->auth.realm = SMB_STRDUP(lp_realm()); 76 77 status = ads_connect(ads); 78 if (!ADS_ERR_OK(status) || !ads->config.realm) { 79 extern struct winbindd_methods msrpc_methods, cache_methods; 80 DEBUG(1,("ads_connect for domain %s failed: %s\n", 81 domain->name, ads_errstr(status))); 82 ads_destroy(&ads); 83 84 /* if we get ECONNREFUSED then it might be a NT4 85 server, fall back to MSRPC */ 86 if (status.error_type == ENUM_ADS_ERROR_SYSTEM && 87 status.err.rc == ECONNREFUSED) { 88 DEBUG(1,("Trying MSRPC methods\n")); 89 if (domain->methods == &cache_methods) { 90 domain->backend = &msrpc_methods; 91 } else { 92 domain->methods = &msrpc_methods; 93 } 94 } 95 return NULL; 96 } 97 98 /* set the flag that says we don't own the memory even 99 though we do so that ads_destroy() won't destroy the 100 structure we pass back by reference */ 101 102 ads->is_mine = False; 103 104 domain->private = (void *)ads; 105 return ads; 106} 107 108 109/* Query display info for a realm. This is the basic user list fn */ 110static NTSTATUS query_user_list(struct winbindd_domain *domain, 111 TALLOC_CTX *mem_ctx, 112 uint32 *num_entries, 113 WINBIND_USERINFO **info) 114{ 115 ADS_STRUCT *ads = NULL; 116 const char *attrs[] = {"userPrincipalName", 117 "sAMAccountName", 118 "name", "objectSid", "primaryGroupID", 119 "sAMAccountType", NULL}; 120 int i, count; 121 ADS_STATUS rc; 122 void *res = NULL; 123 void *msg = NULL; 124 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 125 126 *num_entries = 0; 127 128 DEBUG(3,("ads: query_user_list\n")); 129 130 ads = ads_cached_connection(domain); 131 132 if (!ads) { 133 domain->last_status = NT_STATUS_SERVER_DISABLED; 134 goto done; 135 } 136 137 rc = ads_search_retry(ads, &res, "(objectClass=user)", attrs); 138 if (!ADS_ERR_OK(rc) || !res) { 139 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); 140 goto done; 141 } 142 143 count = ads_count_replies(ads, res); 144 if (count == 0) { 145 DEBUG(1,("query_user_list: No users found\n")); 146 goto done; 147 } 148 149 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, count); 150 if (!*info) { 151 status = NT_STATUS_NO_MEMORY; 152 goto done; 153 } 154 155 i = 0; 156 157 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { 158 char *name, *gecos; 159 DOM_SID sid; 160 DOM_SID *sid2; 161 DOM_SID *group_sid; 162 uint32 group; 163 uint32 atype; 164 165 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) || 166 ads_atype_map(atype) != SID_NAME_USER) { 167 DEBUG(1,("Not a user account? atype=0x%x\n", atype)); 168 continue; 169 } 170 171 name = ads_pull_username(ads, mem_ctx, msg); 172 gecos = ads_pull_string(ads, mem_ctx, msg, "name"); 173 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) { 174 DEBUG(1,("No sid for %s !?\n", name)); 175 continue; 176 } 177 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) { 178 DEBUG(1,("No primary group for %s !?\n", name)); 179 continue; 180 } 181 182 sid2 = TALLOC_P(mem_ctx, DOM_SID); 183 if (!sid2) { 184 status = NT_STATUS_NO_MEMORY; 185 goto done; 186 } 187 188 sid_copy(sid2, &sid); 189 190 group_sid = rid_to_talloced_sid(domain, mem_ctx, group); 191 192 (*info)[i].acct_name = name; 193 (*info)[i].full_name = gecos; 194 (*info)[i].user_sid = sid2; 195 (*info)[i].group_sid = group_sid; 196 i++; 197 } 198 199 (*num_entries) = i; 200 status = NT_STATUS_OK; 201 202 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries))); 203 204done: 205 if (res) 206 ads_msgfree(ads, res); 207 208 return status; 209} 210 211/* list all domain groups */ 212static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, 213 TALLOC_CTX *mem_ctx, 214 uint32 *num_entries, 215 struct acct_info **info) 216{ 217 ADS_STRUCT *ads = NULL; 218 const char *attrs[] = {"userPrincipalName", "sAMAccountName", 219 "name", "objectSid", 220 "sAMAccountType", NULL}; 221 int i, count; 222 ADS_STATUS rc; 223 void *res = NULL; 224 void *msg = NULL; 225 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 226 uint32 group_flags; 227 228 *num_entries = 0; 229 230 DEBUG(3,("ads: enum_dom_groups\n")); 231 232 ads = ads_cached_connection(domain); 233 234 if (!ads) { 235 domain->last_status = NT_STATUS_SERVER_DISABLED; 236 goto done; 237 } 238 239 rc = ads_search_retry(ads, &res, "(objectCategory=group)", attrs); 240 if (!ADS_ERR_OK(rc) || !res) { 241 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc))); 242 goto done; 243 } 244 245 count = ads_count_replies(ads, res); 246 if (count == 0) { 247 DEBUG(1,("enum_dom_groups: No groups found\n")); 248 goto done; 249 } 250 251 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count); 252 if (!*info) { 253 status = NT_STATUS_NO_MEMORY; 254 goto done; 255 } 256 257 i = 0; 258 259 group_flags = ATYPE_GLOBAL_GROUP; 260 261 /* only grab domain local groups for our domain */ 262 if ( domain->native_mode && strequal(lp_realm(), domain->alt_name) ) 263 group_flags |= ATYPE_LOCAL_GROUP; 264 265 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { 266 char *name, *gecos; 267 DOM_SID sid; 268 uint32 rid; 269 uint32 account_type; 270 271 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &account_type) || !(account_type & group_flags) ) 272 continue; 273 274 name = ads_pull_username(ads, mem_ctx, msg); 275 gecos = ads_pull_string(ads, mem_ctx, msg, "name"); 276 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) { 277 DEBUG(1,("No sid for %s !?\n", name)); 278 continue; 279 } 280 281 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) { 282 DEBUG(1,("No rid for %s !?\n", name)); 283 continue; 284 } 285 286 fstrcpy((*info)[i].acct_name, name); 287 fstrcpy((*info)[i].acct_desc, gecos); 288 (*info)[i].rid = rid; 289 i++; 290 } 291 292 (*num_entries) = i; 293 294 status = NT_STATUS_OK; 295 296 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries))); 297 298done: 299 if (res) 300 ads_msgfree(ads, res); 301 302 return status; 303} 304 305/* list all domain local groups */ 306static NTSTATUS enum_local_groups(struct winbindd_domain *domain, 307 TALLOC_CTX *mem_ctx, 308 uint32 *num_entries, 309 struct acct_info **info) 310{ 311 /* 312 * This is a stub function only as we returned the domain 313 * local groups in enum_dom_groups() if the domain->native field 314 * was true. This is a simple performance optimization when 315 * using LDAP. 316 * 317 * if we ever need to enumerate domain local groups separately, 318 * then this the optimization in enum_dom_groups() will need 319 * to be split out 320 */ 321 *num_entries = 0; 322 323 return NT_STATUS_OK; 324} 325 326/* convert a DN to a name, SID and name type 327 this might become a major speed bottleneck if groups have 328 lots of users, in which case we could cache the results 329*/ 330static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, 331 const char *dn, 332 char **name, uint32 *name_type, DOM_SID *sid) 333{ 334 void *res = NULL; 335 const char *attrs[] = {"userPrincipalName", "sAMAccountName", 336 "objectSid", "sAMAccountType", NULL}; 337 ADS_STATUS rc; 338 uint32 atype; 339 DEBUG(3,("ads: dn_lookup\n")); 340 341 rc = ads_search_retry_dn(ads, &res, dn, attrs); 342 343 if (!ADS_ERR_OK(rc) || !res) { 344 goto failed; 345 } 346 347 (*name) = ads_pull_username(ads, mem_ctx, res); 348 349 if (!ads_pull_uint32(ads, res, "sAMAccountType", &atype)) { 350 goto failed; 351 } 352 (*name_type) = ads_atype_map(atype); 353 354 if (!ads_pull_sid(ads, res, "objectSid", sid)) { 355 goto failed; 356 } 357 358 if (res) 359 ads_msgfree(ads, res); 360 361 return True; 362 363failed: 364 if (res) 365 ads_msgfree(ads, res); 366 367 return False; 368} 369 370/* Lookup user information from a rid */ 371static NTSTATUS query_user(struct winbindd_domain *domain, 372 TALLOC_CTX *mem_ctx, 373 const DOM_SID *sid, 374 WINBIND_USERINFO *info) 375{ 376 ADS_STRUCT *ads = NULL; 377 const char *attrs[] = {"userPrincipalName", 378 "sAMAccountName", 379 "name", 380 "primaryGroupID", NULL}; 381 ADS_STATUS rc; 382 int count; 383 void *msg = NULL; 384 char *ldap_exp; 385 char *sidstr; 386 uint32 group_rid; 387 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 388 DOM_SID *sid2; 389 fstring sid_string; 390 391 DEBUG(3,("ads: query_user\n")); 392 393 ads = ads_cached_connection(domain); 394 395 if (!ads) { 396 domain->last_status = NT_STATUS_SERVER_DISABLED; 397 goto done; 398 } 399 400 sidstr = sid_binstring(sid); 401 asprintf(&ldap_exp, "(objectSid=%s)", sidstr); 402 rc = ads_search_retry(ads, &msg, ldap_exp, attrs); 403 free(ldap_exp); 404 free(sidstr); 405 if (!ADS_ERR_OK(rc) || !msg) { 406 DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_to_string(sid_string, sid), ads_errstr(rc))); 407 goto done; 408 } 409 410 count = ads_count_replies(ads, msg); 411 if (count != 1) { 412 DEBUG(1,("query_user(sid=%s): Not found\n", sid_to_string(sid_string, sid))); 413 goto done; 414 } 415 416 info->acct_name = ads_pull_username(ads, mem_ctx, msg); 417 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); 418 419 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) { 420 DEBUG(1,("No primary group for %s !?\n", sid_to_string(sid_string, sid))); 421 goto done; 422 } 423 424 sid2 = TALLOC_P(mem_ctx, DOM_SID); 425 if (!sid2) { 426 status = NT_STATUS_NO_MEMORY; 427 goto done; 428 } 429 sid_copy(sid2, sid); 430 431 info->user_sid = sid2; 432 433 info->group_sid = rid_to_talloced_sid(domain, mem_ctx, group_rid); 434 435 status = NT_STATUS_OK; 436 437 DEBUG(3,("ads query_user gave %s\n", info->acct_name)); 438done: 439 if (msg) 440 ads_msgfree(ads, msg); 441 442 return status; 443} 444 445/* Lookup groups a user is a member of - alternate method, for when 446 tokenGroups are not available. */ 447static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, 448 TALLOC_CTX *mem_ctx, 449 const char *user_dn, 450 DOM_SID *primary_group, 451 uint32 *num_groups, DOM_SID ***user_gids) 452{ 453 ADS_STATUS rc; 454 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 455 int count; 456 void *res = NULL; 457 void *msg = NULL; 458 char *ldap_exp; 459 ADS_STRUCT *ads; 460 const char *group_attrs[] = {"objectSid", NULL}; 461 char *escaped_dn; 462 463 DEBUG(3,("ads: lookup_usergroups_alt\n")); 464 465 ads = ads_cached_connection(domain); 466 467 if (!ads) { 468 domain->last_status = NT_STATUS_SERVER_DISABLED; 469 goto done; 470 } 471 472 if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) { 473 status = NT_STATUS_NO_MEMORY; 474 goto done; 475 } 476 477 /* buggy server, no tokenGroups. Instead lookup what groups this user 478 is a member of by DN search on member*/ 479 480 if (!(ldap_exp = talloc_asprintf(mem_ctx, "(&(member=%s)(objectClass=group))", escaped_dn))) { 481 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn)); 482 SAFE_FREE(escaped_dn); 483 status = NT_STATUS_NO_MEMORY; 484 goto done; 485 } 486 487 SAFE_FREE(escaped_dn); 488 489 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs); 490 491 if (!ADS_ERR_OK(rc) || !res) { 492 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc))); 493 return ads_ntstatus(rc); 494 } 495 496 count = ads_count_replies(ads, res); 497 if (count == 0) { 498 DEBUG(5,("lookup_usergroups: No supp groups found\n")); 499 500 status = ads_ntstatus(rc); 501 goto done; 502 } 503 504 (*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1); 505 (*user_gids)[0] = primary_group; 506 507 *num_groups = 1; 508 509 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) { 510 DOM_SID group_sid; 511 512 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) { 513 DEBUG(1,("No sid for this group ?!?\n")); 514 continue; 515 } 516 517 if (sid_equal(&group_sid, primary_group)) continue; 518 519 (*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID); 520 if (!(*user_gids)[*num_groups]) { 521 status = NT_STATUS_NO_MEMORY; 522 goto done; 523 } 524 525 sid_copy((*user_gids)[*num_groups], &group_sid); 526 527 (*num_groups)++; 528 529 } 530 531 status = NT_STATUS_OK; 532 533 DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn)); 534done: 535 if (res) 536 ads_msgfree(ads, res); 537 538 return status; 539} 540 541/* Lookup groups a user is a member of. */ 542static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, 543 TALLOC_CTX *mem_ctx, 544 const DOM_SID *sid, 545 uint32 *num_groups, DOM_SID ***user_gids) 546{ 547 ADS_STRUCT *ads = NULL; 548 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL}; 549 ADS_STATUS rc; 550 int count; 551 LDAPMessage *msg = NULL; 552 char *user_dn; 553 DOM_SID *sids; 554 int i; 555 DOM_SID *primary_group; 556 uint32 primary_group_rid; 557 fstring sid_string; 558 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 559 560 DEBUG(3,("ads: lookup_usergroups\n")); 561 *num_groups = 0; 562 563 ads = ads_cached_connection(domain); 564 565 if (!ads) { 566 domain->last_status = NT_STATUS_SERVER_DISABLED; 567 status = NT_STATUS_SERVER_DISABLED; 568 goto done; 569 } 570 571 rc = ads_sid_to_dn(ads, mem_ctx, sid, &user_dn); 572 if (!ADS_ERR_OK(rc)) { 573 status = ads_ntstatus(rc); 574 goto done; 575 } 576 577 rc = ads_search_retry_dn(ads, (void**)&msg, user_dn, attrs); 578 if (!ADS_ERR_OK(rc)) { 579 status = ads_ntstatus(rc); 580 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n", 581 sid_to_string(sid_string, sid), ads_errstr(rc))); 582 goto done; 583 } 584 585 if (!msg) { 586 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 587 sid_to_string(sid_string, sid))); 588 status = NT_STATUS_UNSUCCESSFUL; 589 goto done; 590 } 591 592 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) { 593 DEBUG(1,("%s: No primary group for sid=%s !?\n", 594 domain->name, sid_to_string(sid_string, sid))); 595 goto done; 596 } 597 598 primary_group = rid_to_talloced_sid(domain, mem_ctx, primary_group_rid); 599 600 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids); 601 602 if (msg) 603 ads_msgfree(ads, msg); 604 605 /* there must always be at least one group in the token, 606 unless we are talking to a buggy Win2k server */ 607 if (count == 0) { 608 return lookup_usergroups_alt(domain, mem_ctx, user_dn, 609 primary_group, 610 num_groups, user_gids); 611 } 612 613 (*user_gids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, count + 1); 614 (*user_gids)[0] = primary_group; 615 616 *num_groups = 1; 617 618 for (i=0;i<count;i++) { 619 if (sid_equal(&sids[i], primary_group)) continue; 620 621 (*user_gids)[*num_groups] = TALLOC_P(mem_ctx, DOM_SID); 622 if (!(*user_gids)[*num_groups]) { 623 status = NT_STATUS_NO_MEMORY; 624 goto done; 625 } 626 627 sid_copy((*user_gids)[*num_groups], &sids[i]); 628 (*num_groups)++; 629 } 630 631 status = NT_STATUS_OK; 632 DEBUG(3,("ads lookup_usergroups for sid=%s\n", sid_to_string(sid_string, sid))); 633done: 634 return status; 635} 636 637/* 638 find the members of a group, given a group rid and domain 639 */ 640static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, 641 TALLOC_CTX *mem_ctx, 642 const DOM_SID *group_sid, uint32 *num_names, 643 DOM_SID ***sid_mem, char ***names, 644 uint32 **name_types) 645{ 646 ADS_STATUS rc; 647 int count; 648 void *res=NULL; 649 ADS_STRUCT *ads = NULL; 650 char *ldap_exp; 651 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 652 char *sidstr; 653 char **members; 654 int i; 655 size_t num_members; 656 fstring sid_string; 657 BOOL more_values; 658 const char **attrs; 659 uint32 first_usn; 660 uint32 current_usn; 661 int num_retries = 0; 662 663 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, 664 sid_string_static(group_sid))); 665 666 *num_names = 0; 667 668 ads = ads_cached_connection(domain); 669 670 if (!ads) { 671 domain->last_status = NT_STATUS_SERVER_DISABLED; 672 goto done; 673 } 674 675 sidstr = sid_binstring(group_sid); 676 677 /* search for all members of the group */ 678 if (!(ldap_exp = talloc_asprintf(mem_ctx, "(objectSid=%s)",sidstr))) { 679 SAFE_FREE(sidstr); 680 DEBUG(1, ("ads: lookup_groupmem: tallloc_asprintf for ldap_exp failed!\n")); 681 status = NT_STATUS_NO_MEMORY; 682 goto done; 683 } 684 SAFE_FREE(sidstr); 685 686 members = NULL; 687 num_members = 0; 688 689 attrs = TALLOC_ARRAY(mem_ctx, const char *, 3); 690 attrs[1] = talloc_strdup(mem_ctx, "usnChanged"); 691 attrs[2] = NULL; 692 693 do { 694 if (num_members == 0) 695 attrs[0] = talloc_strdup(mem_ctx, "member"); 696 697 DEBUG(10, ("Searching for attrs[0] = %s, attrs[1] = %s\n", attrs[0], attrs[1])); 698 699 rc = ads_search_retry(ads, &res, ldap_exp, attrs); 700 701 if (!ADS_ERR_OK(rc) || !res) { 702 DEBUG(1,("ads: lookup_groupmem ads_search: %s\n", 703 ads_errstr(rc))); 704 status = ads_ntstatus(rc); 705 goto done; 706 } 707 708 count = ads_count_replies(ads, res); 709 if (count == 0) 710 break; 711 712 if (num_members == 0) { 713 if (!ads_pull_uint32(ads, res, "usnChanged", &first_usn)) { 714 DEBUG(1, ("ads: lookup_groupmem could not pull usnChanged!\n")); 715 goto done; 716 } 717 } 718 719 if (!ads_pull_uint32(ads, res, "usnChanged", ¤t_usn)) { 720 DEBUG(1, ("ads: lookup_groupmem could not pull usnChanged!\n")); 721 goto done; 722 } 723 724 if (first_usn != current_usn) { 725 DEBUG(5, ("ads: lookup_groupmem USN on this record changed" 726 " - restarting search\n")); 727 if (num_retries < 5) { 728 num_retries++; 729 num_members = 0; 730 continue; 731 } else { 732 DEBUG(5, ("ads: lookup_groupmem USN on this record changed" 733 " - restarted search too many times, aborting!\n")); 734 status = NT_STATUS_UNSUCCESSFUL; 735 goto done; 736 } 737 } 738 739 members = ads_pull_strings_range(ads, mem_ctx, res, 740 "member", 741 members, 742 &attrs[0], 743 &num_members, 744 &more_values); 745 746 if ((members == NULL) || (num_members == 0)) 747 break; 748 749 } while (more_values); 750 751 /* now we need to turn a list of members into rids, names and name types 752 the problem is that the members are in the form of distinguised names 753 */ 754 755 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID *, num_members); 756 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members); 757 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members); 758 759 for (i=0;i<num_members;i++) { 760 uint32 name_type; 761 char *name; 762 DOM_SID sid; 763 764 if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &sid)) { 765 (*names)[*num_names] = name; 766 (*name_types)[*num_names] = name_type; 767 (*sid_mem)[*num_names] = TALLOC_P(mem_ctx, DOM_SID); 768 if (!(*sid_mem)[*num_names]) { 769 status = NT_STATUS_NO_MEMORY; 770 goto done; 771 } 772 sid_copy((*sid_mem)[*num_names], &sid); 773 (*num_names)++; 774 } 775 } 776 777 status = NT_STATUS_OK; 778 DEBUG(3,("ads lookup_groupmem for sid=%s\n", sid_to_string(sid_string, group_sid))); 779done: 780 781 if (res) 782 ads_msgfree(ads, res); 783 784 return status; 785} 786 787/* find the sequence number for a domain */ 788static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) 789{ 790 ADS_STRUCT *ads = NULL; 791 ADS_STATUS rc; 792 793 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name)); 794 795 *seq = DOM_SEQUENCE_NONE; 796 797 ads = ads_cached_connection(domain); 798 799 if (!ads) { 800 domain->last_status = NT_STATUS_SERVER_DISABLED; 801 return NT_STATUS_UNSUCCESSFUL; 802 } 803 804 rc = ads_USN(ads, seq); 805 806 if (!ADS_ERR_OK(rc)) { 807 808 /* its a dead connection ; don't destroy it 809 through since ads_USN() has already done 810 that indirectly */ 811 812 domain->private = NULL; 813 } 814 return ads_ntstatus(rc); 815} 816 817/* get a list of trusted domains */ 818static NTSTATUS trusted_domains(struct winbindd_domain *domain, 819 TALLOC_CTX *mem_ctx, 820 uint32 *num_domains, 821 char ***names, 822 char ***alt_names, 823 DOM_SID **dom_sids) 824{ 825 NTSTATUS result = NT_STATUS_UNSUCCESSFUL; 826 struct ds_domain_trust *domains = NULL; 827 int count = 0; 828 int i; 829 struct cli_state *cli = NULL; 830 /* i think we only need our forest and downlevel trusted domains */ 831 uint32 flags = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND; 832 833 DEBUG(3,("ads: trusted_domains\n")); 834 835 *num_domains = 0; 836 *alt_names = NULL; 837 *names = NULL; 838 *dom_sids = NULL; 839 840 if ( !NT_STATUS_IS_OK(result = cm_fresh_connection(domain, PI_NETLOGON, &cli)) ) { 841 DEBUG(5, ("trusted_domains: Could not open a connection to %s for PIPE_NETLOGON (%s)\n", 842 domain->name, nt_errstr(result))); 843 return NT_STATUS_UNSUCCESSFUL; 844 } 845 846 if ( NT_STATUS_IS_OK(result) ) 847 result = cli_ds_enum_domain_trusts( cli, mem_ctx, cli->desthost, 848 flags, &domains, (unsigned int *)&count ); 849 850 if ( NT_STATUS_IS_OK(result) && count) { 851 852 /* Allocate memory for trusted domain names and sids */ 853 854 if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) { 855 DEBUG(0, ("trusted_domains: out of memory\n")); 856 result = NT_STATUS_NO_MEMORY; 857 goto done; 858 } 859 860 if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) { 861 DEBUG(0, ("trusted_domains: out of memory\n")); 862 result = NT_STATUS_NO_MEMORY; 863 goto done; 864 } 865 866 if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) { 867 DEBUG(0, ("trusted_domains: out of memory\n")); 868 result = NT_STATUS_NO_MEMORY; 869 goto done; 870 } 871 872 /* Copy across names and sids */ 873 874 for (i = 0; i < count; i++) { 875 (*names)[i] = domains[i].netbios_domain; 876 (*alt_names)[i] = domains[i].dns_domain; 877 878 sid_copy(&(*dom_sids)[i], &domains[i].sid); 879 } 880 881 *num_domains = count; 882 } 883 884done: 885 886 /* remove connection; This is a special case to the \NETLOGON pipe */ 887 888 if ( cli ) 889 cli_shutdown( cli ); 890 891 return result; 892} 893 894/* find the domain sid for a domain */ 895static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid) 896{ 897 ADS_STRUCT *ads; 898 ADS_STATUS rc; 899 900 DEBUG(3,("ads: domain_sid\n")); 901 902 ads = ads_cached_connection(domain); 903 904 if (!ads) { 905 domain->last_status = NT_STATUS_SERVER_DISABLED; 906 return NT_STATUS_UNSUCCESSFUL; 907 } 908 909 rc = ads_domain_sid(ads, sid); 910 911 if (!ADS_ERR_OK(rc)) { 912 913 /* its a dead connection; don't destroy it though 914 since that has already been done indirectly 915 by ads_domain_sid() */ 916 917 domain->private = NULL; 918 } 919 920 return ads_ntstatus(rc); 921} 922 923 924/* find alternate names list for the domain - for ADS this is the 925 netbios name */ 926static NTSTATUS alternate_name(struct winbindd_domain *domain) 927{ 928 ADS_STRUCT *ads; 929 ADS_STATUS rc; 930 TALLOC_CTX *ctx; 931 const char *workgroup; 932 933 DEBUG(3,("ads: alternate_name\n")); 934 935 ads = ads_cached_connection(domain); 936 937 if (!ads) { 938 domain->last_status = NT_STATUS_SERVER_DISABLED; 939 return NT_STATUS_UNSUCCESSFUL; 940 } 941 942 if (!(ctx = talloc_init("alternate_name"))) { 943 return NT_STATUS_NO_MEMORY; 944 } 945 946 rc = ads_workgroup_name(ads, ctx, &workgroup); 947 948 if (ADS_ERR_OK(rc)) { 949 fstrcpy(domain->name, workgroup); 950 fstrcpy(domain->alt_name, ads->config.realm); 951 strupper_m(domain->alt_name); 952 strupper_m(domain->name); 953 } 954 955 talloc_destroy(ctx); 956 957 return ads_ntstatus(rc); 958} 959 960/* the ADS backend methods are exposed via this structure */ 961struct winbindd_methods ads_methods = { 962 True, 963 query_user_list, 964 enum_dom_groups, 965 enum_local_groups, 966 msrpc_name_to_sid, 967 msrpc_sid_to_name, 968 query_user, 969 lookup_usergroups, 970 msrpc_lookup_useraliases, 971 lookup_groupmem, 972 sequence_number, 973 trusted_domains, 974 domain_sid, 975 alternate_name 976}; 977 978#endif 979