1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2019 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * Active Directory Auto-Discovery. 29 * 30 * This [project private] API allows the caller to provide whatever 31 * details it knows a priori (i.e., provided via configuration so as to 32 * override auto-discovery) and in any order. Then the caller can ask 33 * for any of the auto-discoverable parameters in any order. 34 * 35 * But there is an actual order in which discovery must be done. Given 36 * the discovery mechanism implemented here, that order is: 37 * 38 * - the domain name joined must be discovered first 39 * - then the domain controllers 40 * - then the forest name and site name 41 * - then the global catalog servers, and site-specific domain 42 * controllers and global catalog servers. 43 * 44 * The API does not require it be called in the same order because there 45 * may be other discovery mechanisms in the future, and exposing 46 * ordering requirements of the current mechanism now can create trouble 47 * down the line. Also, this makes the API easier to use now, which 48 * means less work to do some day when we make this a public API. 49 * 50 * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 51 * domain controllers. As long as the joined domain appears in the DNS 52 * resolver's search list then we'll find it. 53 * 54 * Domain controller discovery is a matter of formatting the DNS SRV RR 55 * FQDN for domain controllers and doing a lookup for them. Knowledge 56 * of the domain name is not fundamentally required, but we separate the 57 * two processes, which in practice can lead to one more DNS lookup than 58 * is strictly required. 59 * 60 * Forest and site name discovery require an LDAP search of the AD 61 * "configuration partition" at a domain controller for the joined 62 * domain. Forest and site name discovery depend on knowing the joined 63 * domain name and domain controllers for that domain. 64 * 65 * Global catalog server discovery requires knowledge of the forest 66 * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 67 * domain controller discovery depends on knowing the site name (and, 68 * therefore, joined domain, ...). Site-specific global catalog server 69 * discovery depends on knowledge of the forest and site names, which 70 * depend on... 71 * 72 * All the work of discovering particular items is done by functions 73 * named validate_<item>(). Each such function calls validate_<item>() 74 * for any items that it depends on. 75 * 76 * This API is not thread-safe. 77 */ 78 79 80 #include <stdio.h> 81 #include <string.h> 82 #include <strings.h> 83 #include <unistd.h> 84 #include <assert.h> 85 #include <stdlib.h> 86 #include <net/if.h> 87 #include <sys/types.h> 88 #include <sys/socket.h> 89 #include <sys/sockio.h> 90 #include <netinet/in.h> 91 #include <arpa/inet.h> 92 #include <arpa/nameser.h> 93 #include <resolv.h> 94 #include <netdb.h> 95 #include <ctype.h> 96 #include <errno.h> 97 #include <ldap.h> 98 #include <note.h> 99 #include <sasl/sasl.h> 100 #include <sys/u8_textprep.h> 101 #include <syslog.h> 102 #include <uuid/uuid.h> 103 #include <ads/dsgetdc.h> 104 #include "adutils_impl.h" 105 #include "addisc_impl.h" 106 107 /* 108 * These set some sanity policies for discovery. After a discovery 109 * cycle, we will consider the results (successful or unsuccessful) 110 * to be valid for at least MINIMUM_TTL seconds, and for at most 111 * MAXIMUM_TTL seconds. Note that the caller is free to request 112 * discovery cycles sooner than MINIMUM_TTL if it has reason to believe 113 * that the situation has changed. 114 */ 115 #define MINIMUM_TTL (5 * 60) 116 #define MAXIMUM_TTL (20 * 60) 117 118 119 #define DNS_MAX_NAME NS_MAXDNAME 120 121 #define GC_PORT 3268 122 123 /* SRV RR names for various queries */ 124 #define LDAP_SRV_HEAD "_ldap._tcp." 125 #define SITE_SRV_MIDDLE "%s._sites." 126 #define GC_SRV_TAIL "gc._msdcs" 127 #define DC_SRV_TAIL "dc._msdcs" 128 #define ALL_GC_SRV_TAIL "_gc._tcp" 129 #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 130 131 /* A RR name for all GCs -- last resort this works */ 132 #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 133 134 135 /* 136 * We try res_ninit() whenever we don't have one. res_ninit() fails if 137 * idmapd is running before the network is up! 138 */ 139 #define DO_RES_NINIT(ctx) \ 140 if (!(ctx)->res_ninitted) \ 141 (void) do_res_ninit(ctx) 142 143 #define DO_GETNAMEINFO(b, l, s) \ 144 if (ad_disc_getnameinfo(b, l, s) != 0) \ 145 (void) strlcpy(b, "?", l) 146 147 #define DEBUG1STATUS(ctx, ...) do { \ 148 if (DBG(DISC, 1)) \ 149 logger(LOG_DEBUG, __VA_ARGS__); \ 150 if (ctx->status_fp) { \ 151 (void) fprintf(ctx->status_fp, __VA_ARGS__); \ 152 (void) fprintf(ctx->status_fp, "\n"); \ 153 } \ 154 _NOTE(CONSTCOND) \ 155 } while (0) 156 157 #define is_fixed(item) \ 158 ((item)->state == AD_STATE_FIXED) 159 160 #define is_changed(item, num, param) \ 161 ((item)->param_version[num] != (param)->version) 162 163 void * uuid_dup(void *); 164 165 static ad_item_t *validate_SiteName(ad_disc_t ctx); 166 static ad_item_t *validate_PreferredDC(ad_disc_t ctx); 167 168 /* 169 * Function definitions 170 */ 171 172 173 static int 174 do_res_ninit(ad_disc_t ctx) 175 { 176 int rc; 177 178 rc = res_ninit(&ctx->res_state); 179 if (rc != 0) 180 return (rc); 181 ctx->res_ninitted = 1; 182 /* 183 * The SRV records returnd by AD can be larger than 512 bytes, 184 * so we'd like to use TCP for those searches. Unfortunately, 185 * the TCP connect timeout seen by the resolver is very long 186 * (more than a couple minutes) and we can't wait that long. 187 * Don't do use TCP until we can override the timeout. 188 * 189 * Note that some queries will try TCP anyway. 190 */ 191 #if 0 192 ctx->res_state.options |= RES_USEVC; 193 #endif 194 return (0); 195 } 196 197 /* 198 * Private getnameinfo(3socket) variant tailored to our needs. 199 */ 200 int 201 ad_disc_getnameinfo(char *obuf, int olen, struct sockaddr_storage *ss) 202 { 203 struct sockaddr *sa; 204 int eai, slen; 205 206 sa = (void *)ss; 207 switch (sa->sa_family) { 208 case AF_INET: 209 slen = sizeof (struct sockaddr_in); 210 break; 211 case AF_INET6: 212 slen = sizeof (struct sockaddr_in6); 213 break; 214 default: 215 return (EAI_FAMILY); 216 } 217 218 eai = getnameinfo(sa, slen, obuf, olen, NULL, 0, NI_NUMERICHOST); 219 220 return (eai); 221 } 222 223 static void 224 update_version(ad_item_t *item, int num, ad_item_t *param) 225 { 226 item->param_version[num] = param->version; 227 } 228 229 230 231 static boolean_t 232 is_valid(ad_item_t *item) 233 { 234 if (item->value != NULL) { 235 if (item->state == AD_STATE_FIXED) 236 return (B_TRUE); 237 if (item->state == AD_STATE_AUTO && 238 (item->expires == 0 || item->expires > time(NULL))) 239 return (B_TRUE); 240 } 241 return (B_FALSE); 242 } 243 244 245 static void 246 update_item(ad_item_t *item, void *value, enum ad_item_state state, 247 uint32_t ttl) 248 { 249 if (item->value != NULL && value != NULL) { 250 if ((item->type == AD_STRING && 251 strcmp(item->value, value) != 0) || 252 (item->type == AD_UUID && 253 ad_disc_compare_uuid(item->value, value) != 0)|| 254 (item->type == AD_DIRECTORY && 255 ad_disc_compare_ds(item->value, value) != 0)|| 256 (item->type == AD_DOMAINS_IN_FOREST && 257 ad_disc_compare_domainsinforest(item->value, value) != 0) || 258 (item->type == AD_TRUSTED_DOMAINS && 259 ad_disc_compare_trusteddomains(item->value, value) != 0)) 260 item->version++; 261 } else if (item->value != value) 262 item->version++; 263 264 if (item->value != NULL) 265 free(item->value); 266 267 item->value = value; 268 item->state = state; 269 270 if (ttl == 0) 271 item->expires = 0; 272 else 273 item->expires = time(NULL) + ttl; 274 } 275 276 /* Compare UUIDs */ 277 int 278 ad_disc_compare_uuid(uuid_t *u1, uuid_t *u2) 279 { 280 int rc; 281 282 rc = memcmp(u1, u2, UUID_LEN); 283 return (rc); 284 } 285 286 void * 287 uuid_dup(void *src) 288 { 289 void *dst; 290 dst = malloc(UUID_LEN); 291 if (dst != NULL) 292 (void) memcpy(dst, src, UUID_LEN); 293 return (dst); 294 } 295 296 /* Compare DS lists */ 297 int 298 ad_disc_compare_ds(ad_disc_ds_t *ds1, ad_disc_ds_t *ds2) 299 { 300 int i, j; 301 int num_ds1; 302 int num_ds2; 303 boolean_t match; 304 305 for (i = 0; ds1[i].host[0] != '\0'; i++) 306 continue; 307 num_ds1 = i; 308 for (j = 0; ds2[j].host[0] != '\0'; j++) 309 continue; 310 num_ds2 = j; 311 if (num_ds1 != num_ds2) 312 return (1); 313 314 for (i = 0; i < num_ds1; i++) { 315 match = B_FALSE; 316 for (j = 0; j < num_ds2; j++) { 317 if (strcmp(ds1[i].host, ds2[j].host) == 0 && 318 ds1[i].port == ds2[j].port) { 319 match = B_TRUE; 320 break; 321 } 322 } 323 if (!match) 324 return (1); 325 } 326 return (0); 327 } 328 329 330 /* Copy a list of DSs */ 331 static ad_disc_ds_t * 332 ds_dup(const ad_disc_ds_t *srv) 333 { 334 int i; 335 int size; 336 ad_disc_ds_t *new = NULL; 337 338 for (i = 0; srv[i].host[0] != '\0'; i++) 339 continue; 340 341 size = (i + 1) * sizeof (ad_disc_ds_t); 342 new = malloc(size); 343 if (new != NULL) 344 (void) memcpy(new, srv, size); 345 return (new); 346 } 347 348 349 int 350 ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 351 ad_disc_trusteddomains_t *td2) 352 { 353 int i, j; 354 int num_td1; 355 int num_td2; 356 boolean_t match; 357 358 for (i = 0; td1[i].domain[0] != '\0'; i++) 359 continue; 360 num_td1 = i; 361 362 for (j = 0; td2[j].domain[0] != '\0'; j++) 363 continue; 364 num_td2 = j; 365 366 if (num_td1 != num_td2) 367 return (1); 368 369 for (i = 0; i < num_td1; i++) { 370 match = B_FALSE; 371 for (j = 0; j < num_td2; j++) { 372 if (domain_eq(td1[i].domain, td2[j].domain)) { 373 match = B_TRUE; 374 break; 375 } 376 } 377 if (!match) 378 return (1); 379 } 380 return (0); 381 } 382 383 384 385 /* Copy a list of Trusted Domains */ 386 static ad_disc_trusteddomains_t * 387 td_dup(const ad_disc_trusteddomains_t *td) 388 { 389 int i; 390 int size; 391 ad_disc_trusteddomains_t *new = NULL; 392 393 for (i = 0; td[i].domain[0] != '\0'; i++) 394 continue; 395 396 size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 397 new = malloc(size); 398 if (new != NULL) 399 (void) memcpy(new, td, size); 400 return (new); 401 } 402 403 404 405 int 406 ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 407 ad_disc_domainsinforest_t *df2) 408 { 409 int i, j; 410 int num_df1; 411 int num_df2; 412 boolean_t match; 413 414 for (i = 0; df1[i].domain[0] != '\0'; i++) 415 continue; 416 num_df1 = i; 417 418 for (j = 0; df2[j].domain[0] != '\0'; j++) 419 continue; 420 num_df2 = j; 421 422 if (num_df1 != num_df2) 423 return (1); 424 425 for (i = 0; i < num_df1; i++) { 426 match = B_FALSE; 427 for (j = 0; j < num_df2; j++) { 428 if (domain_eq(df1[i].domain, df2[j].domain) && 429 strcmp(df1[i].sid, df2[j].sid) == 0) { 430 match = B_TRUE; 431 break; 432 } 433 } 434 if (!match) 435 return (1); 436 } 437 return (0); 438 } 439 440 441 442 /* Copy a list of Trusted Domains */ 443 static ad_disc_domainsinforest_t * 444 df_dup(const ad_disc_domainsinforest_t *df) 445 { 446 int i; 447 int size; 448 ad_disc_domainsinforest_t *new = NULL; 449 450 for (i = 0; df[i].domain[0] != '\0'; i++) 451 continue; 452 453 size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 454 new = malloc(size); 455 if (new != NULL) 456 (void) memcpy(new, df, size); 457 return (new); 458 } 459 460 461 462 463 464 /* 465 * Returns an array of IPv4 address/prefix length 466 * The last subnet is NULL 467 */ 468 static ad_subnet_t * 469 find_subnets() 470 { 471 int sock, n, i; 472 struct lifconf lifc; 473 struct lifreq lifr, *lifrp; 474 struct lifnum lifn; 475 uint32_t prefix_len; 476 char *s; 477 ad_subnet_t *results; 478 479 lifrp = &lifr; 480 481 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 482 logger(LOG_ERR, "Failed to open IPv4 socket for " 483 "listing network interfaces (%s)", strerror(errno)); 484 return (NULL); 485 } 486 487 lifn.lifn_family = AF_INET; 488 lifn.lifn_flags = 0; 489 if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 490 logger(LOG_ERR, 491 "Failed to find the number of network interfaces (%s)", 492 strerror(errno)); 493 (void) close(sock); 494 return (NULL); 495 } 496 497 if (lifn.lifn_count < 1) { 498 logger(LOG_ERR, "No IPv4 network interfaces found"); 499 (void) close(sock); 500 return (NULL); 501 } 502 503 lifc.lifc_family = AF_INET; 504 lifc.lifc_flags = 0; 505 lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 506 lifc.lifc_buf = malloc(lifc.lifc_len); 507 508 if (lifc.lifc_buf == NULL) { 509 logger(LOG_ERR, "Out of memory"); 510 (void) close(sock); 511 return (NULL); 512 } 513 514 if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 515 logger(LOG_ERR, "Failed to list network interfaces (%s)", 516 strerror(errno)); 517 free(lifc.lifc_buf); 518 (void) close(sock); 519 return (NULL); 520 } 521 522 n = lifc.lifc_len / (int)sizeof (struct lifreq); 523 524 if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 525 free(lifc.lifc_buf); 526 (void) close(sock); 527 return (NULL); 528 } 529 530 for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 531 if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 532 continue; 533 534 if ((lifrp->lifr_flags & IFF_UP) == 0) 535 continue; 536 537 if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 538 continue; 539 540 prefix_len = lifrp->lifr_addrlen; 541 542 s = inet_ntoa(((struct sockaddr_in *) 543 &lifrp->lifr_addr)->sin_addr); 544 545 (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 546 "%s/%d", s, prefix_len); 547 } 548 549 free(lifc.lifc_buf); 550 (void) close(sock); 551 552 return (results); 553 } 554 555 static int 556 cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 557 { 558 int num_subnets1; 559 int num_subnets2; 560 boolean_t matched; 561 int i, j; 562 563 for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 564 continue; 565 num_subnets1 = i; 566 567 for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 568 continue; 569 num_subnets2 = i; 570 571 if (num_subnets1 != num_subnets2) 572 return (1); 573 574 for (i = 0; i < num_subnets1; i++) { 575 matched = B_FALSE; 576 for (j = 0; j < num_subnets2; j++) { 577 if (strcmp(subnets1[i].subnet, 578 subnets2[j].subnet) == 0) { 579 matched = B_TRUE; 580 break; 581 } 582 } 583 if (!matched) 584 return (1); 585 } 586 return (0); 587 } 588 589 590 591 592 /* Convert a DN's DC components into a DNS domainname */ 593 char * 594 DN_to_DNS(const char *dn_name) 595 { 596 char dns[DNS_MAX_NAME]; 597 char *dns_name; 598 int i, j; 599 int num = 0; 600 601 j = 0; 602 i = 0; 603 604 if (dn_name == NULL) 605 return (NULL); 606 /* 607 * Find all DC=<value> and form DNS name of the 608 * form <value1>.<value2>... 609 */ 610 while (dn_name[i] != '\0') { 611 if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 612 i += 3; 613 if (dn_name[i] != '\0' && num > 0) 614 dns[j++] = '.'; 615 while (dn_name[i] != '\0' && 616 dn_name[i] != ',' && dn_name[i] != '+') 617 dns[j++] = dn_name[i++]; 618 num++; 619 } else { 620 /* Skip attr=value as it is not DC= */ 621 while (dn_name[i] != '\0' && 622 dn_name[i] != ',' && dn_name[i] != '+') 623 i++; 624 } 625 /* Skip over separator ',' or '+' */ 626 if (dn_name[i] != '\0') i++; 627 } 628 dns[j] = '\0'; 629 dns_name = malloc(j + 1); 630 if (dns_name != NULL) 631 (void) strlcpy(dns_name, dns, j + 1); 632 return (dns_name); 633 } 634 635 636 /* 637 * A utility function to bind to a Directory server 638 */ 639 640 static 641 LDAP * 642 ldap_lookup_init(ad_disc_ds_t *ds) 643 { 644 int i; 645 int rc, ldversion; 646 int zero = 0; 647 int timeoutms = 5 * 1000; 648 char *saslmech = "GSSAPI"; 649 uint32_t saslflags = LDAP_SASL_INTERACTIVE; 650 LDAP *ld = NULL; 651 652 for (i = 0; ds[i].host[0] != '\0'; i++) { 653 if (DBG(LDAP, 2)) { 654 logger(LOG_DEBUG, "adutils: ldap_lookup_init, host %s", 655 ds[i].host); 656 } 657 658 ld = ldap_init(ds[i].host, ds[i].port); 659 if (ld == NULL) { 660 if (DBG(LDAP, 1)) { 661 logger(LOG_DEBUG, 662 "Couldn't connect to AD DC %s:%d (%s)", 663 ds[i].host, ds[i].port, 664 strerror(errno)); 665 } 666 continue; 667 } 668 669 ldversion = LDAP_VERSION3; 670 (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 671 &ldversion); 672 (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 673 LDAP_OPT_OFF); 674 (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 675 (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 676 /* setup TCP/IP connect timeout */ 677 (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 678 &timeoutms); 679 (void) ldap_set_option(ld, LDAP_OPT_RESTART, 680 LDAP_OPT_ON); 681 682 rc = adutils_set_thread_functions(ld); 683 if (rc != LDAP_SUCCESS) { 684 /* Error has already been logged */ 685 (void) ldap_unbind(ld); 686 ld = NULL; 687 continue; 688 } 689 690 rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 691 saslmech, NULL, NULL, saslflags, &saslcallback, 692 NULL /* defaults */); 693 if (rc == LDAP_SUCCESS) 694 break; 695 696 if (DBG(LDAP, 0)) { 697 logger(LOG_INFO, "LDAP: %s:%d: %s", 698 ds[i].host, ds[i].port, ldap_err2string(rc)); 699 ldap_perror(ld, ds[i].host); 700 } 701 (void) ldap_unbind(ld); 702 ld = NULL; 703 } 704 return (ld); 705 } 706 707 708 709 /* 710 * Lookup the trusted domains in the global catalog. 711 * 712 * Returns: 713 * array of trusted domains which is terminated by 714 * an empty trusted domain. 715 * NULL an error occured 716 */ 717 ad_disc_trusteddomains_t * 718 ldap_lookup_trusted_domains(LDAP **ld, ad_disc_ds_t *globalCatalog, 719 char *base_dn) 720 { 721 int scope = LDAP_SCOPE_SUBTREE; 722 char *attrs[3]; 723 int rc; 724 LDAPMessage *results = NULL; 725 LDAPMessage *entry; 726 char *filter; 727 char **partner = NULL; 728 char **direction = NULL; 729 int num = 0; 730 ad_disc_trusteddomains_t *trusted_domains = NULL; 731 732 if (DBG(DISC, 1)) 733 logger(LOG_DEBUG, "Looking for trusted domains..."); 734 735 if (*ld == NULL) 736 *ld = ldap_lookup_init(globalCatalog); 737 738 if (*ld == NULL) { 739 logger(LOG_ERR, "adutils: ldap_lookup_init failed"); 740 return (NULL); 741 } 742 743 attrs[0] = "trustPartner"; 744 attrs[1] = "trustDirection"; 745 attrs[2] = NULL; 746 747 /* 748 * Trust direction values: 749 * 1 - inbound (they trust us) 750 * 2 - outbound (we trust them) 751 * 3 - bidirectional (we trust each other) 752 */ 753 filter = "(&(objectclass=trustedDomain)" 754 "(|(trustDirection=3)(trustDirection=2)))"; 755 756 rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); 757 if (DBG(DISC, 1)) 758 logger(LOG_DEBUG, "Trusted domains:"); 759 if (rc == LDAP_SUCCESS) { 760 for (entry = ldap_first_entry(*ld, results); 761 entry != NULL; entry = ldap_next_entry(*ld, entry)) { 762 partner = ldap_get_values(*ld, entry, "trustPartner"); 763 direction = ldap_get_values( 764 *ld, entry, "trustDirection"); 765 766 if (partner != NULL && direction != NULL) { 767 if (DBG(DISC, 1)) { 768 logger(LOG_DEBUG, " %s (%s)", 769 partner[0], direction[0]); 770 } 771 num++; 772 void *tmp = realloc(trusted_domains, 773 (num + 1) * 774 sizeof (ad_disc_trusteddomains_t)); 775 if (tmp == NULL) { 776 free(trusted_domains); 777 ldap_value_free(partner); 778 ldap_value_free(direction); 779 (void) ldap_msgfree(results); 780 return (NULL); 781 } 782 trusted_domains = tmp; 783 /* Last element should be zero */ 784 (void) memset(&trusted_domains[num], 0, 785 sizeof (ad_disc_trusteddomains_t)); 786 (void) strcpy(trusted_domains[num - 1].domain, 787 partner[0]); 788 trusted_domains[num - 1].direction = 789 atoi(direction[0]); 790 } 791 if (partner != NULL) 792 ldap_value_free(partner); 793 if (direction != NULL) 794 ldap_value_free(direction); 795 } 796 } else if (rc == LDAP_NO_RESULTS_RETURNED) { 797 /* This is not an error - return empty trusted domain */ 798 trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 799 if (DBG(DISC, 1)) 800 logger(LOG_DEBUG, " not found"); 801 } else { 802 if (DBG(DISC, 1)) 803 logger(LOG_DEBUG, " rc=%d", rc); 804 } 805 if (results != NULL) 806 (void) ldap_msgfree(results); 807 808 return (trusted_domains); 809 } 810 811 812 /* 813 * This functions finds all the domains in a forest. 814 */ 815 ad_disc_domainsinforest_t * 816 ldap_lookup_domains_in_forest(LDAP **ld, ad_disc_ds_t *globalCatalogs) 817 { 818 static char *attrs[] = { 819 "objectSid", 820 NULL, 821 }; 822 int rc; 823 LDAPMessage *result = NULL; 824 LDAPMessage *entry; 825 int ndomains = 0; 826 int nresults; 827 ad_disc_domainsinforest_t *domains = NULL; 828 829 if (DBG(DISC, 1)) 830 logger(LOG_DEBUG, "Looking for domains in forest..."); 831 832 if (*ld == NULL) 833 *ld = ldap_lookup_init(globalCatalogs); 834 835 if (*ld == NULL) { 836 logger(LOG_ERR, "adutils: ldap_lookup_init failed"); 837 return (NULL); 838 } 839 840 /* Find domains */ 841 rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, 842 "(objectClass=Domain)", attrs, 0, &result); 843 if (rc != LDAP_SUCCESS) { 844 logger(LOG_ERR, "adutils: ldap_search, rc=%d", rc); 845 goto err; 846 } 847 if (DBG(DISC, 1)) 848 logger(LOG_DEBUG, "Domains in forest:"); 849 850 nresults = ldap_count_entries(*ld, result); 851 domains = calloc(nresults + 1, sizeof (*domains)); 852 if (domains == NULL) { 853 if (DBG(DISC, 1)) 854 logger(LOG_DEBUG, " (nomem)"); 855 goto err; 856 } 857 858 for (entry = ldap_first_entry(*ld, result); 859 entry != NULL; 860 entry = ldap_next_entry(*ld, entry)) { 861 struct berval **sid_ber; 862 adutils_sid_t sid; 863 char *sid_str; 864 char *name; 865 char *dn; 866 867 sid_ber = ldap_get_values_len(*ld, entry, 868 "objectSid"); 869 if (sid_ber == NULL) 870 continue; 871 872 rc = adutils_getsid(sid_ber[0], &sid); 873 ldap_value_free_len(sid_ber); 874 if (rc < 0) 875 goto err; 876 877 if ((sid_str = adutils_sid2txt(&sid)) == NULL) 878 goto err; 879 880 (void) strcpy(domains[ndomains].sid, sid_str); 881 free(sid_str); 882 883 dn = ldap_get_dn(*ld, entry); 884 name = DN_to_DNS(dn); 885 free(dn); 886 if (name == NULL) 887 goto err; 888 889 (void) strcpy(domains[ndomains].domain, name); 890 free(name); 891 892 if (DBG(DISC, 1)) 893 logger(LOG_DEBUG, " %s", domains[ndomains].domain); 894 895 ndomains++; 896 } 897 898 if (ndomains == 0) { 899 if (DBG(DISC, 1)) 900 logger(LOG_DEBUG, " not found"); 901 goto err; 902 } 903 904 if (ndomains < nresults) { 905 ad_disc_domainsinforest_t *tmp; 906 tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); 907 if (tmp == NULL) 908 goto err; 909 domains = tmp; 910 } 911 912 if (result != NULL) 913 (void) ldap_msgfree(result); 914 915 return (domains); 916 917 err: 918 free(domains); 919 if (result != NULL) 920 (void) ldap_msgfree(result); 921 return (NULL); 922 } 923 924 925 ad_disc_t 926 ad_disc_init(void) 927 { 928 struct ad_disc *ctx; 929 ctx = calloc(1, sizeof (struct ad_disc)); 930 if (ctx != NULL) 931 DO_RES_NINIT(ctx); 932 933 ctx->domain_name.type = AD_STRING; 934 ctx->domain_guid.type = AD_UUID; 935 ctx->domain_controller.type = AD_DIRECTORY; 936 ctx->preferred_dc.type = AD_DIRECTORY; 937 ctx->site_name.type = AD_STRING; 938 ctx->forest_name.type = AD_STRING; 939 ctx->global_catalog.type = AD_DIRECTORY; 940 ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 941 ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 942 /* Site specific versions */ 943 ctx->site_domain_controller.type = AD_DIRECTORY; 944 ctx->site_global_catalog.type = AD_DIRECTORY; 945 return (ctx); 946 } 947 948 void 949 ad_disc_fini(ad_disc_t ctx) 950 { 951 if (ctx == NULL) 952 return; 953 954 if (ctx->res_ninitted) 955 res_ndestroy(&ctx->res_state); 956 957 if (ctx->subnets != NULL) 958 free(ctx->subnets); 959 960 if (ctx->domain_name.value != NULL) 961 free(ctx->domain_name.value); 962 963 if (ctx->domain_guid.value != NULL) 964 free(ctx->domain_guid.value); 965 966 if (ctx->domain_controller.value != NULL) 967 free(ctx->domain_controller.value); 968 969 if (ctx->preferred_dc.value != NULL) 970 free(ctx->preferred_dc.value); 971 972 if (ctx->site_name.value != NULL) 973 free(ctx->site_name.value); 974 975 if (ctx->forest_name.value != NULL) 976 free(ctx->forest_name.value); 977 978 if (ctx->global_catalog.value != NULL) 979 free(ctx->global_catalog.value); 980 981 if (ctx->domains_in_forest.value != NULL) 982 free(ctx->domains_in_forest.value); 983 984 if (ctx->trusted_domains.value != NULL) 985 free(ctx->trusted_domains.value); 986 987 /* Site specific versions */ 988 if (ctx->site_domain_controller.value != NULL) 989 free(ctx->site_domain_controller.value); 990 991 if (ctx->site_global_catalog.value != NULL) 992 free(ctx->site_global_catalog.value); 993 994 free(ctx); 995 } 996 997 void 998 ad_disc_refresh(ad_disc_t ctx) 999 { 1000 if (ctx->res_ninitted) { 1001 res_ndestroy(&ctx->res_state); 1002 ctx->res_ninitted = 0; 1003 } 1004 (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 1005 DO_RES_NINIT(ctx); 1006 1007 if (ctx->domain_name.state == AD_STATE_AUTO) 1008 ctx->domain_name.state = AD_STATE_INVALID; 1009 1010 if (ctx->domain_guid.state == AD_STATE_AUTO) 1011 ctx->domain_guid.state = AD_STATE_INVALID; 1012 1013 if (ctx->domain_controller.state == AD_STATE_AUTO) 1014 ctx->domain_controller.state = AD_STATE_INVALID; 1015 1016 if (ctx->preferred_dc.state == AD_STATE_AUTO) 1017 ctx->preferred_dc.state = AD_STATE_INVALID; 1018 1019 if (ctx->site_name.state == AD_STATE_AUTO) 1020 ctx->site_name.state = AD_STATE_INVALID; 1021 1022 if (ctx->forest_name.state == AD_STATE_AUTO) 1023 ctx->forest_name.state = AD_STATE_INVALID; 1024 1025 if (ctx->global_catalog.state == AD_STATE_AUTO) 1026 ctx->global_catalog.state = AD_STATE_INVALID; 1027 1028 if (ctx->domains_in_forest.state == AD_STATE_AUTO) 1029 ctx->domains_in_forest.state = AD_STATE_INVALID; 1030 1031 if (ctx->trusted_domains.state == AD_STATE_AUTO) 1032 ctx->trusted_domains.state = AD_STATE_INVALID; 1033 1034 if (ctx->site_domain_controller.state == AD_STATE_AUTO) 1035 ctx->site_domain_controller.state = AD_STATE_INVALID; 1036 1037 if (ctx->site_global_catalog.state == AD_STATE_AUTO) 1038 ctx->site_global_catalog.state = AD_STATE_INVALID; 1039 } 1040 1041 1042 /* 1043 * Called when the discovery cycle is done. Sets a master TTL 1044 * that will avoid doing new time-based discoveries too soon after 1045 * the last discovery cycle. Most interesting when the discovery 1046 * cycle failed, because then the TTLs on the individual items will 1047 * not be updated and may go stale. 1048 */ 1049 void 1050 ad_disc_done(ad_disc_t ctx) 1051 { 1052 time_t now = time(NULL); 1053 1054 ctx->expires_not_before = now + MINIMUM_TTL; 1055 ctx->expires_not_after = now + MAXIMUM_TTL; 1056 } 1057 1058 static void 1059 log_cds(ad_disc_t ctx, ad_disc_cds_t *cds) 1060 { 1061 char buf[INET6_ADDRSTRLEN]; 1062 struct addrinfo *ai; 1063 1064 if (!DBG(DISC, 1) && ctx->status_fp == NULL) 1065 return; 1066 1067 DEBUG1STATUS(ctx, "Candidate servers:"); 1068 if (cds->cds_ds.host[0] == '\0') { 1069 DEBUG1STATUS(ctx, " (empty list)"); 1070 return; 1071 } 1072 1073 while (cds->cds_ds.host[0] != '\0') { 1074 1075 DEBUG1STATUS(ctx, " %s p=%d w=%d", 1076 cds->cds_ds.host, 1077 cds->cds_ds.priority, 1078 cds->cds_ds.weight); 1079 1080 ai = cds->cds_ai; 1081 if (ai == NULL) { 1082 DEBUG1STATUS(ctx, " (no address)"); 1083 } 1084 while (ai != NULL) { 1085 int eai; 1086 1087 eai = getnameinfo(ai->ai_addr, ai->ai_addrlen, 1088 buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); 1089 if (eai != 0) 1090 (void) strlcpy(buf, "?", sizeof (buf)); 1091 1092 DEBUG1STATUS(ctx, " %s", buf); 1093 ai = ai->ai_next; 1094 } 1095 cds++; 1096 } 1097 } 1098 1099 static void 1100 log_ds(ad_disc_t ctx, ad_disc_ds_t *ds) 1101 { 1102 char buf[INET6_ADDRSTRLEN]; 1103 1104 if (!DBG(DISC, 1) && ctx->status_fp == NULL) 1105 return; 1106 1107 DEBUG1STATUS(ctx, "Responding servers:"); 1108 if (ds->host[0] == '\0') { 1109 DEBUG1STATUS(ctx, " (empty list)"); 1110 return; 1111 } 1112 1113 while (ds->host[0] != '\0') { 1114 1115 DEBUG1STATUS(ctx, " %s", ds->host); 1116 DO_GETNAMEINFO(buf, sizeof (buf), &ds->addr); 1117 DEBUG1STATUS(ctx, " %s", buf); 1118 1119 ds++; 1120 } 1121 } 1122 1123 /* Discover joined Active Directory domainName */ 1124 static ad_item_t * 1125 validate_DomainName(ad_disc_t ctx) 1126 { 1127 char *dname, *srvname; 1128 int len, rc; 1129 1130 if (is_valid(&ctx->domain_name)) 1131 return (&ctx->domain_name); 1132 1133 1134 /* Try to find our domain by searching for DCs for it */ 1135 DO_RES_NINIT(ctx); 1136 if (DBG(DISC, 1)) 1137 logger(LOG_DEBUG, "Looking for our AD domain name..."); 1138 rc = srv_getdom(&ctx->res_state, 1139 LDAP_SRV_HEAD DC_SRV_TAIL, &srvname); 1140 1141 /* 1142 * If we can't find DCs by via res_nsearch() then there's no 1143 * point in trying anything else to discover the AD domain name. 1144 */ 1145 if (rc < 0) { 1146 if (DBG(DISC, 1)) 1147 logger(LOG_DEBUG, "Can't find our domain name."); 1148 return (NULL); 1149 } 1150 1151 /* 1152 * We have the FQDN of the SRV RR name, so now we extract the 1153 * domainname suffix from it. 1154 */ 1155 dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 1156 1 /* for the dot between RR name and domainname */); 1157 1158 free(srvname); 1159 1160 if (dname == NULL) { 1161 logger(LOG_ERR, "Out of memory"); 1162 return (NULL); 1163 } 1164 1165 /* Eat any trailing dot */ 1166 len = strlen(dname); 1167 if (len > 0 && dname[len - 1] == '.') 1168 dname[len - 1] = '\0'; 1169 1170 if (DBG(DISC, 1)) 1171 logger(LOG_DEBUG, "Our domain name: %s", dname); 1172 1173 /* 1174 * There is no "time to live" on the discovered domain, 1175 * so passing zero as TTL here, making it non-expiring. 1176 * Note that current consumers do not auto-discover the 1177 * domain name, though a future installer could. 1178 */ 1179 update_item(&ctx->domain_name, dname, AD_STATE_AUTO, 0); 1180 1181 return (&ctx->domain_name); 1182 } 1183 1184 1185 char * 1186 ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 1187 { 1188 char *domain_name = NULL; 1189 ad_item_t *domain_name_item; 1190 1191 domain_name_item = validate_DomainName(ctx); 1192 1193 if (domain_name_item) { 1194 domain_name = strdup(domain_name_item->value); 1195 if (auto_discovered != NULL) 1196 *auto_discovered = 1197 (domain_name_item->state == AD_STATE_AUTO); 1198 } else if (auto_discovered != NULL) 1199 *auto_discovered = B_FALSE; 1200 1201 return (domain_name); 1202 } 1203 1204 1205 /* Discover domain controllers */ 1206 static ad_item_t * 1207 validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 1208 { 1209 ad_disc_ds_t *dc = NULL; 1210 ad_disc_cds_t *cdc = NULL; 1211 boolean_t validate_global = B_FALSE; 1212 boolean_t validate_site = B_FALSE; 1213 ad_item_t *domain_name_item; 1214 char *domain_name; 1215 ad_item_t *site_name_item = NULL; 1216 char *site_name; 1217 ad_item_t *prefer_dc_item; 1218 ad_disc_ds_t *prefer_dc = NULL; 1219 1220 /* If the values is fixed there will not be a site specific version */ 1221 if (is_fixed(&ctx->domain_controller)) 1222 return (&ctx->domain_controller); 1223 1224 domain_name_item = validate_DomainName(ctx); 1225 if (domain_name_item == NULL) { 1226 DEBUG1STATUS(ctx, "(no domain name)"); 1227 return (NULL); 1228 } 1229 domain_name = (char *)domain_name_item->value; 1230 1231 /* Get (optional) preferred DC. */ 1232 prefer_dc_item = validate_PreferredDC(ctx); 1233 if (prefer_dc_item != NULL) 1234 prefer_dc = prefer_dc_item->value; 1235 1236 if (req == AD_DISC_GLOBAL) 1237 validate_global = B_TRUE; 1238 else { 1239 if (is_fixed(&ctx->site_name)) 1240 validate_site = B_TRUE; 1241 if (req == AD_DISC_PREFER_SITE) 1242 validate_global = B_TRUE; 1243 } 1244 1245 /* 1246 * If we're trying both site-specific and global, 1247 * try the site-specific first, then fall-back. 1248 */ 1249 if (validate_site) { 1250 site_name_item = &ctx->site_name; 1251 site_name = (char *)site_name_item->value; 1252 1253 if (!is_valid(&ctx->site_domain_controller) || 1254 is_changed(&ctx->site_domain_controller, PARAM1, 1255 domain_name_item) || 1256 is_changed(&ctx->site_domain_controller, PARAM2, 1257 site_name_item)) { 1258 char rr_name[DNS_MAX_NAME]; 1259 1260 /* 1261 * Lookup DNS SRV RR named 1262 * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 1263 */ 1264 DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s", 1265 domain_name, site_name); 1266 (void) snprintf(rr_name, sizeof (rr_name), 1267 LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 1268 site_name); 1269 DO_RES_NINIT(ctx); 1270 cdc = srv_query(&ctx->res_state, rr_name, 1271 domain_name, prefer_dc); 1272 1273 if (cdc == NULL) { 1274 DEBUG1STATUS(ctx, "(no DNS response)"); 1275 goto try_global; 1276 } 1277 log_cds(ctx, cdc); 1278 1279 /* 1280 * Filter out unresponsive servers, and 1281 * save the domain info we get back. 1282 */ 1283 dc = ldap_ping( 1284 ctx, 1285 cdc, 1286 domain_name, 1287 DS_DS_FLAG); 1288 srv_free(cdc); 1289 cdc = NULL; 1290 1291 if (dc == NULL) { 1292 DEBUG1STATUS(ctx, "(no LDAP response)"); 1293 goto try_global; 1294 } 1295 log_ds(ctx, dc); 1296 1297 update_item(&ctx->site_domain_controller, dc, 1298 AD_STATE_AUTO, dc->ttl); 1299 update_version(&ctx->site_domain_controller, PARAM1, 1300 domain_name_item); 1301 update_version(&ctx->site_domain_controller, PARAM2, 1302 site_name_item); 1303 } 1304 return (&ctx->site_domain_controller); 1305 } 1306 1307 try_global: 1308 1309 if (validate_global) { 1310 if (!is_valid(&ctx->domain_controller) || 1311 is_changed(&ctx->domain_controller, PARAM1, 1312 domain_name_item)) { 1313 1314 /* 1315 * Lookup DNS SRV RR named 1316 * _ldap._tcp.dc._msdcs.<DomainName> 1317 */ 1318 DEBUG1STATUS(ctx, "DNS SRV query, dom=%s", 1319 domain_name); 1320 DO_RES_NINIT(ctx); 1321 cdc = srv_query(&ctx->res_state, 1322 LDAP_SRV_HEAD DC_SRV_TAIL, 1323 domain_name, prefer_dc); 1324 1325 if (cdc == NULL) { 1326 DEBUG1STATUS(ctx, "(no DNS response)"); 1327 return (NULL); 1328 } 1329 log_cds(ctx, cdc); 1330 1331 /* 1332 * Filter out unresponsive servers, and 1333 * save the domain info we get back. 1334 */ 1335 dc = ldap_ping( 1336 ctx, 1337 cdc, 1338 domain_name, 1339 DS_DS_FLAG); 1340 srv_free(cdc); 1341 cdc = NULL; 1342 1343 if (dc == NULL) { 1344 DEBUG1STATUS(ctx, "(no LDAP response)"); 1345 return (NULL); 1346 } 1347 log_ds(ctx, dc); 1348 1349 update_item(&ctx->domain_controller, dc, 1350 AD_STATE_AUTO, dc->ttl); 1351 update_version(&ctx->domain_controller, PARAM1, 1352 domain_name_item); 1353 } 1354 return (&ctx->domain_controller); 1355 } 1356 1357 return (NULL); 1358 } 1359 1360 ad_disc_ds_t * 1361 ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 1362 boolean_t *auto_discovered) 1363 { 1364 ad_item_t *domain_controller_item; 1365 ad_disc_ds_t *domain_controller = NULL; 1366 1367 domain_controller_item = validate_DomainController(ctx, req); 1368 1369 if (domain_controller_item != NULL) { 1370 domain_controller = ds_dup(domain_controller_item->value); 1371 if (auto_discovered != NULL) 1372 *auto_discovered = 1373 (domain_controller_item->state == AD_STATE_AUTO); 1374 } else if (auto_discovered != NULL) 1375 *auto_discovered = B_FALSE; 1376 1377 return (domain_controller); 1378 } 1379 1380 1381 /* 1382 * Discover the Domain GUID 1383 * This info comes from validate_DomainController() 1384 */ 1385 static ad_item_t * 1386 validate_DomainGUID(ad_disc_t ctx) 1387 { 1388 ad_item_t *domain_controller_item; 1389 1390 if (is_fixed(&ctx->domain_guid)) 1391 return (&ctx->domain_guid); 1392 1393 domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1394 if (domain_controller_item == NULL) 1395 return (NULL); 1396 1397 if (!is_valid(&ctx->domain_guid)) 1398 return (NULL); 1399 1400 return (&ctx->domain_guid); 1401 } 1402 1403 1404 uchar_t * 1405 ad_disc_get_DomainGUID(ad_disc_t ctx, boolean_t *auto_discovered) 1406 { 1407 ad_item_t *domain_guid_item; 1408 uchar_t *domain_guid = NULL; 1409 1410 domain_guid_item = validate_DomainGUID(ctx); 1411 if (domain_guid_item != NULL) { 1412 domain_guid = uuid_dup(domain_guid_item->value); 1413 if (auto_discovered != NULL) 1414 *auto_discovered = 1415 (domain_guid_item->state == AD_STATE_AUTO); 1416 } else if (auto_discovered != NULL) 1417 *auto_discovered = B_FALSE; 1418 1419 return (domain_guid); 1420 } 1421 1422 1423 /* 1424 * Discover site name (for multi-homed systems the first one found wins) 1425 * This info comes from validate_DomainController() 1426 */ 1427 static ad_item_t * 1428 validate_SiteName(ad_disc_t ctx) 1429 { 1430 ad_item_t *domain_controller_item; 1431 1432 if (is_fixed(&ctx->site_name)) 1433 return (&ctx->site_name); 1434 1435 domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1436 if (domain_controller_item == NULL) 1437 return (NULL); 1438 1439 if (!is_valid(&ctx->site_name)) 1440 return (NULL); 1441 1442 return (&ctx->site_name); 1443 } 1444 1445 1446 char * 1447 ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 1448 { 1449 ad_item_t *site_name_item; 1450 char *site_name = NULL; 1451 1452 site_name_item = validate_SiteName(ctx); 1453 if (site_name_item != NULL) { 1454 site_name = strdup(site_name_item->value); 1455 if (auto_discovered != NULL) 1456 *auto_discovered = 1457 (site_name_item->state == AD_STATE_AUTO); 1458 } else if (auto_discovered != NULL) 1459 *auto_discovered = B_FALSE; 1460 1461 return (site_name); 1462 } 1463 1464 1465 1466 /* 1467 * Discover forest name 1468 * This info comes from validate_DomainController() 1469 */ 1470 static ad_item_t * 1471 validate_ForestName(ad_disc_t ctx) 1472 { 1473 ad_item_t *domain_controller_item; 1474 1475 if (is_fixed(&ctx->forest_name)) 1476 return (&ctx->forest_name); 1477 1478 domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1479 if (domain_controller_item == NULL) 1480 return (NULL); 1481 1482 if (!is_valid(&ctx->forest_name)) 1483 return (NULL); 1484 1485 return (&ctx->forest_name); 1486 } 1487 1488 1489 char * 1490 ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 1491 { 1492 ad_item_t *forest_name_item; 1493 char *forest_name = NULL; 1494 1495 forest_name_item = validate_ForestName(ctx); 1496 1497 if (forest_name_item != NULL) { 1498 forest_name = strdup(forest_name_item->value); 1499 if (auto_discovered != NULL) 1500 *auto_discovered = 1501 (forest_name_item->state == AD_STATE_AUTO); 1502 } else if (auto_discovered != NULL) 1503 *auto_discovered = B_FALSE; 1504 1505 return (forest_name); 1506 } 1507 1508 1509 /* Discover global catalog servers */ 1510 static ad_item_t * 1511 validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 1512 { 1513 ad_disc_ds_t *gc = NULL; 1514 ad_disc_cds_t *cgc = NULL; 1515 boolean_t validate_global = B_FALSE; 1516 boolean_t validate_site = B_FALSE; 1517 ad_item_t *dc_item; 1518 ad_item_t *forest_name_item; 1519 ad_item_t *site_name_item; 1520 char *forest_name; 1521 char *site_name; 1522 1523 /* If the values is fixed there will not be a site specific version */ 1524 if (is_fixed(&ctx->global_catalog)) 1525 return (&ctx->global_catalog); 1526 1527 forest_name_item = validate_ForestName(ctx); 1528 if (forest_name_item == NULL) { 1529 DEBUG1STATUS(ctx, "(no forrest name)"); 1530 return (NULL); 1531 } 1532 forest_name = (char *)forest_name_item->value; 1533 1534 if (req == AD_DISC_GLOBAL) 1535 validate_global = B_TRUE; 1536 else { 1537 if (is_fixed(&ctx->site_name)) 1538 validate_site = B_TRUE; 1539 if (req == AD_DISC_PREFER_SITE) 1540 validate_global = B_TRUE; 1541 } 1542 1543 /* 1544 * If we're trying both site-specific and global, 1545 * try the site-specific first, then fall-back. 1546 */ 1547 if (validate_site) { 1548 site_name_item = &ctx->site_name; 1549 site_name = (char *)site_name_item->value; 1550 1551 if (!is_valid(&ctx->site_global_catalog) || 1552 is_changed(&ctx->site_global_catalog, PARAM1, 1553 forest_name_item) || 1554 is_changed(&ctx->site_global_catalog, PARAM2, 1555 site_name_item)) { 1556 char rr_name[DNS_MAX_NAME]; 1557 1558 /* 1559 * See if our DC is also a GC. 1560 */ 1561 dc_item = validate_DomainController(ctx, req); 1562 if (dc_item != NULL) { 1563 ad_disc_ds_t *ds = dc_item->value; 1564 if ((ds->flags & DS_GC_FLAG) != 0) { 1565 DEBUG1STATUS(ctx, 1566 "DC is also a GC for %s in %s", 1567 forest_name, site_name); 1568 gc = ds_dup(ds); 1569 if (gc != NULL) { 1570 gc->port = GC_PORT; 1571 goto update_site; 1572 } 1573 } 1574 } 1575 1576 /* 1577 * Lookup DNS SRV RR named: 1578 * _ldap._tcp.<siteName>._sites.gc. 1579 * _msdcs.<ForestName> 1580 */ 1581 DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s", 1582 forest_name, site_name); 1583 (void) snprintf(rr_name, sizeof (rr_name), 1584 LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 1585 site_name); 1586 DO_RES_NINIT(ctx); 1587 cgc = srv_query(&ctx->res_state, rr_name, 1588 forest_name, NULL); 1589 1590 if (cgc == NULL) { 1591 DEBUG1STATUS(ctx, "(no DNS response)"); 1592 goto try_global; 1593 } 1594 log_cds(ctx, cgc); 1595 1596 /* 1597 * Filter out unresponsive servers, and 1598 * save the domain info we get back. 1599 */ 1600 gc = ldap_ping( 1601 NULL, 1602 cgc, 1603 forest_name, 1604 DS_GC_FLAG); 1605 srv_free(cgc); 1606 cgc = NULL; 1607 1608 if (gc == NULL) { 1609 DEBUG1STATUS(ctx, "(no LDAP response)"); 1610 goto try_global; 1611 } 1612 log_ds(ctx, gc); 1613 1614 update_site: 1615 update_item(&ctx->site_global_catalog, gc, 1616 AD_STATE_AUTO, gc->ttl); 1617 update_version(&ctx->site_global_catalog, PARAM1, 1618 forest_name_item); 1619 update_version(&ctx->site_global_catalog, PARAM2, 1620 site_name_item); 1621 } 1622 return (&ctx->site_global_catalog); 1623 } 1624 1625 try_global: 1626 1627 if (validate_global) { 1628 if (!is_valid(&ctx->global_catalog) || 1629 is_changed(&ctx->global_catalog, PARAM1, 1630 forest_name_item)) { 1631 1632 /* 1633 * See if our DC is also a GC. 1634 */ 1635 dc_item = validate_DomainController(ctx, req); 1636 if (dc_item != NULL) { 1637 ad_disc_ds_t *ds = dc_item->value; 1638 if ((ds->flags & DS_GC_FLAG) != 0) { 1639 DEBUG1STATUS(ctx, 1640 "DC is also a GC for %s", 1641 forest_name); 1642 gc = ds_dup(ds); 1643 if (gc != NULL) { 1644 gc->port = GC_PORT; 1645 goto update_global; 1646 } 1647 } 1648 } 1649 1650 /* 1651 * Lookup DNS SRV RR named: 1652 * _ldap._tcp.gc._msdcs.<ForestName> 1653 */ 1654 DEBUG1STATUS(ctx, "DNS SRV query, forest=%s", 1655 forest_name); 1656 DO_RES_NINIT(ctx); 1657 cgc = srv_query(&ctx->res_state, 1658 LDAP_SRV_HEAD GC_SRV_TAIL, 1659 forest_name, NULL); 1660 1661 if (cgc == NULL) { 1662 DEBUG1STATUS(ctx, "(no DNS response)"); 1663 return (NULL); 1664 } 1665 log_cds(ctx, cgc); 1666 1667 /* 1668 * Filter out unresponsive servers, and 1669 * save the domain info we get back. 1670 */ 1671 gc = ldap_ping( 1672 NULL, 1673 cgc, 1674 forest_name, 1675 DS_GC_FLAG); 1676 srv_free(cgc); 1677 cgc = NULL; 1678 1679 if (gc == NULL) { 1680 DEBUG1STATUS(ctx, "(no LDAP response)"); 1681 return (NULL); 1682 } 1683 log_ds(ctx, gc); 1684 1685 update_global: 1686 update_item(&ctx->global_catalog, gc, 1687 AD_STATE_AUTO, gc->ttl); 1688 update_version(&ctx->global_catalog, PARAM1, 1689 forest_name_item); 1690 } 1691 return (&ctx->global_catalog); 1692 } 1693 return (NULL); 1694 } 1695 1696 1697 ad_disc_ds_t * 1698 ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 1699 boolean_t *auto_discovered) 1700 { 1701 ad_disc_ds_t *global_catalog = NULL; 1702 ad_item_t *global_catalog_item; 1703 1704 global_catalog_item = validate_GlobalCatalog(ctx, req); 1705 1706 if (global_catalog_item != NULL) { 1707 global_catalog = ds_dup(global_catalog_item->value); 1708 if (auto_discovered != NULL) 1709 *auto_discovered = 1710 (global_catalog_item->state == AD_STATE_AUTO); 1711 } else if (auto_discovered != NULL) 1712 *auto_discovered = B_FALSE; 1713 1714 return (global_catalog); 1715 } 1716 1717 1718 static ad_item_t * 1719 validate_TrustedDomains(ad_disc_t ctx) 1720 { 1721 LDAP *ld = NULL; 1722 ad_item_t *global_catalog_item; 1723 ad_item_t *forest_name_item; 1724 ad_disc_trusteddomains_t *trusted_domains; 1725 char *dn = NULL; 1726 char *forest_name_dn; 1727 int len; 1728 int num_parts; 1729 1730 if (is_fixed(&ctx->trusted_domains)) 1731 return (&ctx->trusted_domains); 1732 1733 global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 1734 if (global_catalog_item == NULL) 1735 return (NULL); 1736 1737 forest_name_item = validate_ForestName(ctx); 1738 if (forest_name_item == NULL) 1739 return (NULL); 1740 1741 if (!is_valid(&ctx->trusted_domains) || 1742 is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 1743 is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 1744 1745 forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 1746 &num_parts); 1747 if (forest_name_dn == NULL) 1748 return (NULL); 1749 1750 len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 1751 dn = malloc(len); 1752 if (dn == NULL) { 1753 free(forest_name_dn); 1754 return (NULL); 1755 } 1756 (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 1757 free(forest_name_dn); 1758 1759 trusted_domains = ldap_lookup_trusted_domains( 1760 &ld, global_catalog_item->value, dn); 1761 1762 if (ld != NULL) 1763 (void) ldap_unbind(ld); 1764 free(dn); 1765 1766 if (trusted_domains == NULL) 1767 return (NULL); 1768 1769 update_item(&ctx->trusted_domains, trusted_domains, 1770 AD_STATE_AUTO, 0); 1771 update_version(&ctx->trusted_domains, PARAM1, 1772 global_catalog_item); 1773 update_version(&ctx->trusted_domains, PARAM2, 1774 forest_name_item); 1775 } 1776 1777 return (&ctx->trusted_domains); 1778 } 1779 1780 1781 ad_disc_trusteddomains_t * 1782 ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 1783 { 1784 ad_disc_trusteddomains_t *trusted_domains = NULL; 1785 ad_item_t *trusted_domains_item; 1786 1787 trusted_domains_item = validate_TrustedDomains(ctx); 1788 1789 if (trusted_domains_item != NULL) { 1790 trusted_domains = td_dup(trusted_domains_item->value); 1791 if (auto_discovered != NULL) 1792 *auto_discovered = 1793 (trusted_domains_item->state == AD_STATE_AUTO); 1794 } else if (auto_discovered != NULL) 1795 *auto_discovered = B_FALSE; 1796 1797 return (trusted_domains); 1798 } 1799 1800 1801 static ad_item_t * 1802 validate_DomainsInForest(ad_disc_t ctx) 1803 { 1804 ad_item_t *global_catalog_item; 1805 LDAP *ld = NULL; 1806 ad_disc_domainsinforest_t *domains_in_forest; 1807 1808 if (is_fixed(&ctx->domains_in_forest)) 1809 return (&ctx->domains_in_forest); 1810 1811 global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 1812 if (global_catalog_item == NULL) 1813 return (NULL); 1814 1815 if (!is_valid(&ctx->domains_in_forest) || 1816 is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 1817 1818 domains_in_forest = ldap_lookup_domains_in_forest( 1819 &ld, global_catalog_item->value); 1820 1821 if (ld != NULL) 1822 (void) ldap_unbind(ld); 1823 1824 if (domains_in_forest == NULL) 1825 return (NULL); 1826 1827 update_item(&ctx->domains_in_forest, domains_in_forest, 1828 AD_STATE_AUTO, 0); 1829 update_version(&ctx->domains_in_forest, PARAM1, 1830 global_catalog_item); 1831 } 1832 return (&ctx->domains_in_forest); 1833 } 1834 1835 1836 ad_disc_domainsinforest_t * 1837 ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 1838 { 1839 ad_disc_domainsinforest_t *domains_in_forest = NULL; 1840 ad_item_t *domains_in_forest_item; 1841 1842 domains_in_forest_item = validate_DomainsInForest(ctx); 1843 1844 if (domains_in_forest_item != NULL) { 1845 domains_in_forest = df_dup(domains_in_forest_item->value); 1846 if (auto_discovered != NULL) 1847 *auto_discovered = 1848 (domains_in_forest_item->state == AD_STATE_AUTO); 1849 } else if (auto_discovered != NULL) 1850 *auto_discovered = B_FALSE; 1851 1852 return (domains_in_forest); 1853 } 1854 1855 static ad_item_t * 1856 validate_PreferredDC(ad_disc_t ctx) 1857 { 1858 if (is_valid(&ctx->preferred_dc)) 1859 return (&ctx->preferred_dc); 1860 1861 return (NULL); 1862 } 1863 1864 ad_disc_ds_t * 1865 ad_disc_get_PreferredDC(ad_disc_t ctx, boolean_t *auto_discovered) 1866 { 1867 ad_disc_ds_t *preferred_dc = NULL; 1868 ad_item_t *preferred_dc_item; 1869 1870 preferred_dc_item = validate_PreferredDC(ctx); 1871 1872 if (preferred_dc_item != NULL) { 1873 preferred_dc = ds_dup(preferred_dc_item->value); 1874 if (auto_discovered != NULL) 1875 *auto_discovered = 1876 (preferred_dc_item->state == AD_STATE_AUTO); 1877 } else if (auto_discovered != NULL) 1878 *auto_discovered = B_FALSE; 1879 1880 return (preferred_dc); 1881 } 1882 1883 1884 1885 int 1886 ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 1887 { 1888 char *domain_name = NULL; 1889 if (domainName != NULL) { 1890 domain_name = strdup(domainName); 1891 if (domain_name == NULL) 1892 return (-1); 1893 update_item(&ctx->domain_name, domain_name, 1894 AD_STATE_FIXED, 0); 1895 } else if (ctx->domain_name.state == AD_STATE_FIXED) 1896 ctx->domain_name.state = AD_STATE_INVALID; 1897 return (0); 1898 } 1899 1900 int 1901 ad_disc_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1902 { 1903 char *domain_guid = NULL; 1904 if (u != NULL) { 1905 domain_guid = uuid_dup(u); 1906 if (domain_guid == NULL) 1907 return (-1); 1908 update_item(&ctx->domain_guid, domain_guid, 1909 AD_STATE_FIXED, 0); 1910 } else if (ctx->domain_guid.state == AD_STATE_FIXED) 1911 ctx->domain_guid.state = AD_STATE_INVALID; 1912 return (0); 1913 } 1914 1915 void 1916 auto_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1917 { 1918 char *domain_guid = NULL; 1919 1920 if (is_fixed(&ctx->domain_guid)) 1921 return; 1922 1923 domain_guid = uuid_dup(u); 1924 if (domain_guid == NULL) 1925 return; 1926 update_item(&ctx->domain_guid, domain_guid, AD_STATE_AUTO, 0); 1927 } 1928 1929 int 1930 ad_disc_set_DomainController(ad_disc_t ctx, 1931 const ad_disc_ds_t *domainController) 1932 { 1933 ad_disc_ds_t *domain_controller = NULL; 1934 if (domainController != NULL) { 1935 domain_controller = ds_dup(domainController); 1936 if (domain_controller == NULL) 1937 return (-1); 1938 update_item(&ctx->domain_controller, domain_controller, 1939 AD_STATE_FIXED, 0); 1940 } else if (ctx->domain_controller.state == AD_STATE_FIXED) 1941 ctx->domain_controller.state = AD_STATE_INVALID; 1942 return (0); 1943 } 1944 1945 int 1946 ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 1947 { 1948 char *site_name = NULL; 1949 if (siteName != NULL) { 1950 site_name = strdup(siteName); 1951 if (site_name == NULL) 1952 return (-1); 1953 update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 1954 } else if (ctx->site_name.state == AD_STATE_FIXED) 1955 ctx->site_name.state = AD_STATE_INVALID; 1956 return (0); 1957 } 1958 1959 void 1960 auto_set_SiteName(ad_disc_t ctx, char *siteName) 1961 { 1962 char *site_name = NULL; 1963 1964 if (is_fixed(&ctx->site_name)) 1965 return; 1966 1967 site_name = strdup(siteName); 1968 if (site_name == NULL) 1969 return; 1970 update_item(&ctx->site_name, site_name, AD_STATE_AUTO, 0); 1971 } 1972 1973 int 1974 ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 1975 { 1976 char *forest_name = NULL; 1977 if (forestName != NULL) { 1978 forest_name = strdup(forestName); 1979 if (forest_name == NULL) 1980 return (-1); 1981 update_item(&ctx->forest_name, forest_name, 1982 AD_STATE_FIXED, 0); 1983 } else if (ctx->forest_name.state == AD_STATE_FIXED) 1984 ctx->forest_name.state = AD_STATE_INVALID; 1985 return (0); 1986 } 1987 1988 void 1989 auto_set_ForestName(ad_disc_t ctx, char *forestName) 1990 { 1991 char *forest_name = NULL; 1992 1993 if (is_fixed(&ctx->forest_name)) 1994 return; 1995 1996 forest_name = strdup(forestName); 1997 if (forest_name == NULL) 1998 return; 1999 update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 2000 } 2001 2002 int 2003 ad_disc_set_GlobalCatalog(ad_disc_t ctx, 2004 const ad_disc_ds_t *globalCatalog) 2005 { 2006 ad_disc_ds_t *global_catalog = NULL; 2007 if (globalCatalog != NULL) { 2008 global_catalog = ds_dup(globalCatalog); 2009 if (global_catalog == NULL) 2010 return (-1); 2011 update_item(&ctx->global_catalog, global_catalog, 2012 AD_STATE_FIXED, 0); 2013 } else if (ctx->global_catalog.state == AD_STATE_FIXED) 2014 ctx->global_catalog.state = AD_STATE_INVALID; 2015 return (0); 2016 } 2017 2018 int 2019 ad_disc_set_PreferredDC(ad_disc_t ctx, const ad_disc_ds_t *pref_dc) 2020 { 2021 ad_disc_ds_t *new_pref_dc = NULL; 2022 if (pref_dc != NULL) { 2023 new_pref_dc = ds_dup(pref_dc); 2024 if (new_pref_dc == NULL) 2025 return (-1); 2026 update_item(&ctx->preferred_dc, new_pref_dc, 2027 AD_STATE_FIXED, 0); 2028 } else if (ctx->preferred_dc.state == AD_STATE_FIXED) 2029 ctx->preferred_dc.state = AD_STATE_INVALID; 2030 return (0); 2031 } 2032 2033 void 2034 ad_disc_set_StatusFP(ad_disc_t ctx, struct __FILE_TAG *fp) 2035 { 2036 ctx->status_fp = fp; 2037 } 2038 2039 2040 int 2041 ad_disc_unset(ad_disc_t ctx) 2042 { 2043 if (ctx->domain_name.state == AD_STATE_FIXED) 2044 ctx->domain_name.state = AD_STATE_INVALID; 2045 2046 if (ctx->domain_controller.state == AD_STATE_FIXED) 2047 ctx->domain_controller.state = AD_STATE_INVALID; 2048 2049 if (ctx->preferred_dc.state == AD_STATE_FIXED) 2050 ctx->preferred_dc.state = AD_STATE_INVALID; 2051 2052 if (ctx->site_name.state == AD_STATE_FIXED) 2053 ctx->site_name.state = AD_STATE_INVALID; 2054 2055 if (ctx->forest_name.state == AD_STATE_FIXED) 2056 ctx->forest_name.state = AD_STATE_INVALID; 2057 2058 if (ctx->global_catalog.state == AD_STATE_FIXED) 2059 ctx->global_catalog.state = AD_STATE_INVALID; 2060 2061 return (0); 2062 } 2063 2064 /* 2065 * ad_disc_get_TTL 2066 * 2067 * This routines the time to live for AD 2068 * auto discovered items. 2069 * 2070 * Returns: 2071 * -1 if there are no TTL items 2072 * 0 if there are expired items 2073 * else the number of seconds 2074 * 2075 * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 2076 * is positive -- min() greater than zero. 2077 */ 2078 #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 2079 (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 2080 int 2081 ad_disc_get_TTL(ad_disc_t ctx) 2082 { 2083 time_t expires; 2084 int ttl; 2085 2086 expires = MIN_GT_ZERO(ctx->domain_controller.expires, 2087 ctx->global_catalog.expires); 2088 expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires); 2089 expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires); 2090 2091 if (expires == -1) { 2092 return (-1); 2093 } 2094 2095 if (ctx->expires_not_before != 0 && 2096 expires < ctx->expires_not_before) { 2097 expires = ctx->expires_not_before; 2098 } 2099 2100 if (ctx->expires_not_after != 0 && 2101 expires > ctx->expires_not_after) { 2102 expires = ctx->expires_not_after; 2103 } 2104 2105 ttl = expires - time(NULL); 2106 2107 if (ttl < 0) { 2108 return (0); 2109 } 2110 return (ttl); 2111 } 2112 2113 boolean_t 2114 ad_disc_SubnetChanged(ad_disc_t ctx) 2115 { 2116 ad_subnet_t *subnets; 2117 2118 if (ctx->subnets_changed || ctx->subnets == NULL) 2119 return (B_TRUE); 2120 2121 if ((subnets = find_subnets()) != NULL) { 2122 if (cmpsubnets(subnets, ctx->subnets) != 0) 2123 ctx->subnets_changed = B_TRUE; 2124 free(subnets); 2125 } 2126 2127 return (ctx->subnets_changed); 2128 } 2129