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