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 2014 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 return (NULL); 1227 domain_name = (char *)domain_name_item->value; 1228 1229 /* Get (optional) preferred DC. */ 1230 prefer_dc_item = validate_PreferredDC(ctx); 1231 if (prefer_dc_item != NULL) 1232 prefer_dc = prefer_dc_item->value; 1233 1234 if (req == AD_DISC_GLOBAL) 1235 validate_global = B_TRUE; 1236 else { 1237 if (is_fixed(&ctx->site_name)) 1238 validate_site = B_TRUE; 1239 else if (req == AD_DISC_PREFER_SITE) 1240 validate_global = B_TRUE; 1241 } 1242 1243 if (validate_global) { 1244 if (!is_valid(&ctx->domain_controller) || 1245 is_changed(&ctx->domain_controller, PARAM1, 1246 domain_name_item)) { 1247 1248 /* 1249 * Lookup DNS SRV RR named 1250 * _ldap._tcp.dc._msdcs.<DomainName> 1251 */ 1252 DEBUG1STATUS(ctx, "DNS SRV query, dom=%s", 1253 domain_name); 1254 DO_RES_NINIT(ctx); 1255 cdc = srv_query(&ctx->res_state, 1256 LDAP_SRV_HEAD DC_SRV_TAIL, 1257 domain_name, prefer_dc); 1258 1259 if (cdc == NULL) { 1260 DEBUG1STATUS(ctx, "(no DNS response)"); 1261 return (NULL); 1262 } 1263 log_cds(ctx, cdc); 1264 1265 /* 1266 * Filter out unresponsive servers, and 1267 * save the domain info we get back. 1268 */ 1269 dc = ldap_ping( 1270 ctx, 1271 cdc, 1272 domain_name, 1273 DS_DS_FLAG); 1274 srv_free(cdc); 1275 cdc = NULL; 1276 1277 if (dc == NULL) { 1278 DEBUG1STATUS(ctx, "(no LDAP response)"); 1279 return (NULL); 1280 } 1281 log_ds(ctx, dc); 1282 1283 update_item(&ctx->domain_controller, dc, 1284 AD_STATE_AUTO, dc->ttl); 1285 update_version(&ctx->domain_controller, PARAM1, 1286 domain_name_item); 1287 } 1288 return (&ctx->domain_controller); 1289 } 1290 1291 if (validate_site) { 1292 site_name_item = &ctx->site_name; 1293 site_name = (char *)site_name_item->value; 1294 1295 if (!is_valid(&ctx->site_domain_controller) || 1296 is_changed(&ctx->site_domain_controller, PARAM1, 1297 domain_name_item) || 1298 is_changed(&ctx->site_domain_controller, PARAM2, 1299 site_name_item)) { 1300 char rr_name[DNS_MAX_NAME]; 1301 1302 /* 1303 * Lookup DNS SRV RR named 1304 * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 1305 */ 1306 DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s", 1307 domain_name, site_name); 1308 (void) snprintf(rr_name, sizeof (rr_name), 1309 LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 1310 site_name); 1311 DO_RES_NINIT(ctx); 1312 cdc = srv_query(&ctx->res_state, rr_name, 1313 domain_name, prefer_dc); 1314 1315 if (cdc == NULL) { 1316 DEBUG1STATUS(ctx, "(no DNS response)"); 1317 return (NULL); 1318 } 1319 log_cds(ctx, cdc); 1320 1321 /* 1322 * Filter out unresponsive servers, and 1323 * save the domain info we get back. 1324 */ 1325 dc = ldap_ping( 1326 ctx, 1327 cdc, 1328 domain_name, 1329 DS_DS_FLAG); 1330 srv_free(cdc); 1331 cdc = NULL; 1332 1333 if (dc == NULL) { 1334 DEBUG1STATUS(ctx, "(no LDAP response)"); 1335 return (NULL); 1336 } 1337 log_ds(ctx, dc); 1338 1339 update_item(&ctx->site_domain_controller, dc, 1340 AD_STATE_AUTO, dc->ttl); 1341 update_version(&ctx->site_domain_controller, PARAM1, 1342 domain_name_item); 1343 update_version(&ctx->site_domain_controller, PARAM2, 1344 site_name_item); 1345 } 1346 return (&ctx->site_domain_controller); 1347 } 1348 return (NULL); 1349 } 1350 1351 ad_disc_ds_t * 1352 ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 1353 boolean_t *auto_discovered) 1354 { 1355 ad_item_t *domain_controller_item; 1356 ad_disc_ds_t *domain_controller = NULL; 1357 1358 domain_controller_item = validate_DomainController(ctx, req); 1359 1360 if (domain_controller_item != NULL) { 1361 domain_controller = ds_dup(domain_controller_item->value); 1362 if (auto_discovered != NULL) 1363 *auto_discovered = 1364 (domain_controller_item->state == AD_STATE_AUTO); 1365 } else if (auto_discovered != NULL) 1366 *auto_discovered = B_FALSE; 1367 1368 return (domain_controller); 1369 } 1370 1371 1372 /* 1373 * Discover the Domain GUID 1374 * This info comes from validate_DomainController() 1375 */ 1376 static ad_item_t * 1377 validate_DomainGUID(ad_disc_t ctx) 1378 { 1379 ad_item_t *domain_controller_item; 1380 1381 if (is_fixed(&ctx->domain_guid)) 1382 return (&ctx->domain_guid); 1383 1384 domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1385 if (domain_controller_item == NULL) 1386 return (NULL); 1387 1388 if (!is_valid(&ctx->domain_guid)) 1389 return (NULL); 1390 1391 return (&ctx->domain_guid); 1392 } 1393 1394 1395 uchar_t * 1396 ad_disc_get_DomainGUID(ad_disc_t ctx, boolean_t *auto_discovered) 1397 { 1398 ad_item_t *domain_guid_item; 1399 uchar_t *domain_guid = NULL; 1400 1401 domain_guid_item = validate_DomainGUID(ctx); 1402 if (domain_guid_item != NULL) { 1403 domain_guid = uuid_dup(domain_guid_item->value); 1404 if (auto_discovered != NULL) 1405 *auto_discovered = 1406 (domain_guid_item->state == AD_STATE_AUTO); 1407 } else if (auto_discovered != NULL) 1408 *auto_discovered = B_FALSE; 1409 1410 return (domain_guid); 1411 } 1412 1413 1414 /* 1415 * Discover site name (for multi-homed systems the first one found wins) 1416 * This info comes from validate_DomainController() 1417 */ 1418 static ad_item_t * 1419 validate_SiteName(ad_disc_t ctx) 1420 { 1421 ad_item_t *domain_controller_item; 1422 1423 if (is_fixed(&ctx->site_name)) 1424 return (&ctx->site_name); 1425 1426 domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1427 if (domain_controller_item == NULL) 1428 return (NULL); 1429 1430 if (!is_valid(&ctx->site_name)) 1431 return (NULL); 1432 1433 return (&ctx->site_name); 1434 } 1435 1436 1437 char * 1438 ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 1439 { 1440 ad_item_t *site_name_item; 1441 char *site_name = NULL; 1442 1443 site_name_item = validate_SiteName(ctx); 1444 if (site_name_item != NULL) { 1445 site_name = strdup(site_name_item->value); 1446 if (auto_discovered != NULL) 1447 *auto_discovered = 1448 (site_name_item->state == AD_STATE_AUTO); 1449 } else if (auto_discovered != NULL) 1450 *auto_discovered = B_FALSE; 1451 1452 return (site_name); 1453 } 1454 1455 1456 1457 /* 1458 * Discover forest name 1459 * This info comes from validate_DomainController() 1460 */ 1461 static ad_item_t * 1462 validate_ForestName(ad_disc_t ctx) 1463 { 1464 ad_item_t *domain_controller_item; 1465 1466 if (is_fixed(&ctx->forest_name)) 1467 return (&ctx->forest_name); 1468 1469 domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 1470 if (domain_controller_item == NULL) 1471 return (NULL); 1472 1473 if (!is_valid(&ctx->forest_name)) 1474 return (NULL); 1475 1476 return (&ctx->forest_name); 1477 } 1478 1479 1480 char * 1481 ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 1482 { 1483 ad_item_t *forest_name_item; 1484 char *forest_name = NULL; 1485 1486 forest_name_item = validate_ForestName(ctx); 1487 1488 if (forest_name_item != NULL) { 1489 forest_name = strdup(forest_name_item->value); 1490 if (auto_discovered != NULL) 1491 *auto_discovered = 1492 (forest_name_item->state == AD_STATE_AUTO); 1493 } else if (auto_discovered != NULL) 1494 *auto_discovered = B_FALSE; 1495 1496 return (forest_name); 1497 } 1498 1499 1500 /* Discover global catalog servers */ 1501 static ad_item_t * 1502 validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 1503 { 1504 ad_disc_ds_t *gc = NULL; 1505 ad_disc_cds_t *cgc = NULL; 1506 boolean_t validate_global = B_FALSE; 1507 boolean_t validate_site = B_FALSE; 1508 ad_item_t *dc_item; 1509 ad_item_t *forest_name_item; 1510 ad_item_t *site_name_item; 1511 char *forest_name; 1512 char *site_name; 1513 1514 /* If the values is fixed there will not be a site specific version */ 1515 if (is_fixed(&ctx->global_catalog)) 1516 return (&ctx->global_catalog); 1517 1518 forest_name_item = validate_ForestName(ctx); 1519 if (forest_name_item == NULL) 1520 return (NULL); 1521 forest_name = (char *)forest_name_item->value; 1522 1523 if (req == AD_DISC_GLOBAL) 1524 validate_global = B_TRUE; 1525 else { 1526 if (is_fixed(&ctx->site_name)) 1527 validate_site = B_TRUE; 1528 else if (req == AD_DISC_PREFER_SITE) 1529 validate_global = B_TRUE; 1530 } 1531 1532 if (validate_global) { 1533 if (!is_valid(&ctx->global_catalog) || 1534 is_changed(&ctx->global_catalog, PARAM1, 1535 forest_name_item)) { 1536 1537 /* 1538 * See if our DC is also a GC. 1539 */ 1540 dc_item = validate_DomainController(ctx, req); 1541 if (dc_item != NULL) { 1542 ad_disc_ds_t *ds = dc_item->value; 1543 if ((ds->flags & DS_GC_FLAG) != 0) { 1544 DEBUG1STATUS(ctx, 1545 "DC is also a GC for %s", 1546 forest_name); 1547 gc = ds_dup(ds); 1548 if (gc != NULL) { 1549 gc->port = GC_PORT; 1550 goto update_global; 1551 } 1552 } 1553 } 1554 1555 /* 1556 * Lookup DNS SRV RR named: 1557 * _ldap._tcp.gc._msdcs.<ForestName> 1558 */ 1559 DEBUG1STATUS(ctx, "DNS SRV query, forest=%s", 1560 forest_name); 1561 DO_RES_NINIT(ctx); 1562 cgc = srv_query(&ctx->res_state, 1563 LDAP_SRV_HEAD GC_SRV_TAIL, 1564 forest_name, NULL); 1565 1566 if (cgc == NULL) { 1567 DEBUG1STATUS(ctx, "(no DNS response)"); 1568 return (NULL); 1569 } 1570 log_cds(ctx, cgc); 1571 1572 /* 1573 * Filter out unresponsive servers, and 1574 * save the domain info we get back. 1575 */ 1576 gc = ldap_ping( 1577 NULL, 1578 cgc, 1579 forest_name, 1580 DS_GC_FLAG); 1581 srv_free(cgc); 1582 cgc = NULL; 1583 1584 if (gc == NULL) { 1585 DEBUG1STATUS(ctx, "(no LDAP response)"); 1586 return (NULL); 1587 } 1588 log_ds(ctx, gc); 1589 1590 update_global: 1591 update_item(&ctx->global_catalog, gc, 1592 AD_STATE_AUTO, gc->ttl); 1593 update_version(&ctx->global_catalog, PARAM1, 1594 forest_name_item); 1595 } 1596 return (&ctx->global_catalog); 1597 } 1598 1599 if (validate_site) { 1600 site_name_item = &ctx->site_name; 1601 site_name = (char *)site_name_item->value; 1602 1603 if (!is_valid(&ctx->site_global_catalog) || 1604 is_changed(&ctx->site_global_catalog, PARAM1, 1605 forest_name_item) || 1606 is_changed(&ctx->site_global_catalog, PARAM2, 1607 site_name_item)) { 1608 char rr_name[DNS_MAX_NAME]; 1609 1610 /* 1611 * See if our DC is also a GC. 1612 */ 1613 dc_item = validate_DomainController(ctx, req); 1614 if (dc_item != NULL) { 1615 ad_disc_ds_t *ds = dc_item->value; 1616 if ((ds->flags & DS_GC_FLAG) != 0) { 1617 DEBUG1STATUS(ctx, 1618 "DC is also a GC for %s in %s", 1619 forest_name, site_name); 1620 gc = ds_dup(ds); 1621 if (gc != NULL) { 1622 gc->port = GC_PORT; 1623 goto update_site; 1624 } 1625 } 1626 } 1627 1628 /* 1629 * Lookup DNS SRV RR named: 1630 * _ldap._tcp.<siteName>._sites.gc. 1631 * _msdcs.<ForestName> 1632 */ 1633 DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s", 1634 forest_name, site_name); 1635 (void) snprintf(rr_name, sizeof (rr_name), 1636 LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 1637 site_name); 1638 DO_RES_NINIT(ctx); 1639 cgc = srv_query(&ctx->res_state, rr_name, 1640 forest_name, NULL); 1641 1642 if (cgc == NULL) { 1643 DEBUG1STATUS(ctx, "(no DNS response)"); 1644 return (NULL); 1645 } 1646 log_cds(ctx, cgc); 1647 1648 /* 1649 * Filter out unresponsive servers, and 1650 * save the domain info we get back. 1651 */ 1652 gc = ldap_ping( 1653 NULL, 1654 cgc, 1655 forest_name, 1656 DS_GC_FLAG); 1657 srv_free(cgc); 1658 cgc = NULL; 1659 1660 if (gc == NULL) { 1661 DEBUG1STATUS(ctx, "(no LDAP response)"); 1662 return (NULL); 1663 } 1664 log_ds(ctx, gc); 1665 1666 update_site: 1667 update_item(&ctx->site_global_catalog, gc, 1668 AD_STATE_AUTO, gc->ttl); 1669 update_version(&ctx->site_global_catalog, PARAM1, 1670 forest_name_item); 1671 update_version(&ctx->site_global_catalog, PARAM2, 1672 site_name_item); 1673 } 1674 return (&ctx->site_global_catalog); 1675 } 1676 return (NULL); 1677 } 1678 1679 1680 ad_disc_ds_t * 1681 ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 1682 boolean_t *auto_discovered) 1683 { 1684 ad_disc_ds_t *global_catalog = NULL; 1685 ad_item_t *global_catalog_item; 1686 1687 global_catalog_item = validate_GlobalCatalog(ctx, req); 1688 1689 if (global_catalog_item != NULL) { 1690 global_catalog = ds_dup(global_catalog_item->value); 1691 if (auto_discovered != NULL) 1692 *auto_discovered = 1693 (global_catalog_item->state == AD_STATE_AUTO); 1694 } else if (auto_discovered != NULL) 1695 *auto_discovered = B_FALSE; 1696 1697 return (global_catalog); 1698 } 1699 1700 1701 static ad_item_t * 1702 validate_TrustedDomains(ad_disc_t ctx) 1703 { 1704 LDAP *ld = NULL; 1705 ad_item_t *global_catalog_item; 1706 ad_item_t *forest_name_item; 1707 ad_disc_trusteddomains_t *trusted_domains; 1708 char *dn = NULL; 1709 char *forest_name_dn; 1710 int len; 1711 int num_parts; 1712 1713 if (is_fixed(&ctx->trusted_domains)) 1714 return (&ctx->trusted_domains); 1715 1716 global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 1717 if (global_catalog_item == NULL) 1718 return (NULL); 1719 1720 forest_name_item = validate_ForestName(ctx); 1721 if (forest_name_item == NULL) 1722 return (NULL); 1723 1724 if (!is_valid(&ctx->trusted_domains) || 1725 is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 1726 is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 1727 1728 forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 1729 &num_parts); 1730 if (forest_name_dn == NULL) 1731 return (NULL); 1732 1733 len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 1734 dn = malloc(len); 1735 if (dn == NULL) { 1736 free(forest_name_dn); 1737 return (NULL); 1738 } 1739 (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 1740 free(forest_name_dn); 1741 1742 trusted_domains = ldap_lookup_trusted_domains( 1743 &ld, global_catalog_item->value, dn); 1744 1745 if (ld != NULL) 1746 (void) ldap_unbind(ld); 1747 free(dn); 1748 1749 if (trusted_domains == NULL) 1750 return (NULL); 1751 1752 update_item(&ctx->trusted_domains, trusted_domains, 1753 AD_STATE_AUTO, 0); 1754 update_version(&ctx->trusted_domains, PARAM1, 1755 global_catalog_item); 1756 update_version(&ctx->trusted_domains, PARAM2, 1757 forest_name_item); 1758 } 1759 1760 return (&ctx->trusted_domains); 1761 } 1762 1763 1764 ad_disc_trusteddomains_t * 1765 ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 1766 { 1767 ad_disc_trusteddomains_t *trusted_domains = NULL; 1768 ad_item_t *trusted_domains_item; 1769 1770 trusted_domains_item = validate_TrustedDomains(ctx); 1771 1772 if (trusted_domains_item != NULL) { 1773 trusted_domains = td_dup(trusted_domains_item->value); 1774 if (auto_discovered != NULL) 1775 *auto_discovered = 1776 (trusted_domains_item->state == AD_STATE_AUTO); 1777 } else if (auto_discovered != NULL) 1778 *auto_discovered = B_FALSE; 1779 1780 return (trusted_domains); 1781 } 1782 1783 1784 static ad_item_t * 1785 validate_DomainsInForest(ad_disc_t ctx) 1786 { 1787 ad_item_t *global_catalog_item; 1788 LDAP *ld = NULL; 1789 ad_disc_domainsinforest_t *domains_in_forest; 1790 1791 if (is_fixed(&ctx->domains_in_forest)) 1792 return (&ctx->domains_in_forest); 1793 1794 global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 1795 if (global_catalog_item == NULL) 1796 return (NULL); 1797 1798 if (!is_valid(&ctx->domains_in_forest) || 1799 is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 1800 1801 domains_in_forest = ldap_lookup_domains_in_forest( 1802 &ld, global_catalog_item->value); 1803 1804 if (ld != NULL) 1805 (void) ldap_unbind(ld); 1806 1807 if (domains_in_forest == NULL) 1808 return (NULL); 1809 1810 update_item(&ctx->domains_in_forest, domains_in_forest, 1811 AD_STATE_AUTO, 0); 1812 update_version(&ctx->domains_in_forest, PARAM1, 1813 global_catalog_item); 1814 } 1815 return (&ctx->domains_in_forest); 1816 } 1817 1818 1819 ad_disc_domainsinforest_t * 1820 ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 1821 { 1822 ad_disc_domainsinforest_t *domains_in_forest = NULL; 1823 ad_item_t *domains_in_forest_item; 1824 1825 domains_in_forest_item = validate_DomainsInForest(ctx); 1826 1827 if (domains_in_forest_item != NULL) { 1828 domains_in_forest = df_dup(domains_in_forest_item->value); 1829 if (auto_discovered != NULL) 1830 *auto_discovered = 1831 (domains_in_forest_item->state == AD_STATE_AUTO); 1832 } else if (auto_discovered != NULL) 1833 *auto_discovered = B_FALSE; 1834 1835 return (domains_in_forest); 1836 } 1837 1838 static ad_item_t * 1839 validate_PreferredDC(ad_disc_t ctx) 1840 { 1841 if (is_valid(&ctx->preferred_dc)) 1842 return (&ctx->preferred_dc); 1843 1844 return (NULL); 1845 } 1846 1847 ad_disc_ds_t * 1848 ad_disc_get_PreferredDC(ad_disc_t ctx, boolean_t *auto_discovered) 1849 { 1850 ad_disc_ds_t *preferred_dc = NULL; 1851 ad_item_t *preferred_dc_item; 1852 1853 preferred_dc_item = validate_PreferredDC(ctx); 1854 1855 if (preferred_dc_item != NULL) { 1856 preferred_dc = ds_dup(preferred_dc_item->value); 1857 if (auto_discovered != NULL) 1858 *auto_discovered = 1859 (preferred_dc_item->state == AD_STATE_AUTO); 1860 } else if (auto_discovered != NULL) 1861 *auto_discovered = B_FALSE; 1862 1863 return (preferred_dc); 1864 } 1865 1866 1867 1868 int 1869 ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 1870 { 1871 char *domain_name = NULL; 1872 if (domainName != NULL) { 1873 domain_name = strdup(domainName); 1874 if (domain_name == NULL) 1875 return (-1); 1876 update_item(&ctx->domain_name, domain_name, 1877 AD_STATE_FIXED, 0); 1878 } else if (ctx->domain_name.state == AD_STATE_FIXED) 1879 ctx->domain_name.state = AD_STATE_INVALID; 1880 return (0); 1881 } 1882 1883 int 1884 ad_disc_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1885 { 1886 char *domain_guid = NULL; 1887 if (u != NULL) { 1888 domain_guid = uuid_dup(u); 1889 if (domain_guid == NULL) 1890 return (-1); 1891 update_item(&ctx->domain_guid, domain_guid, 1892 AD_STATE_FIXED, 0); 1893 } else if (ctx->domain_guid.state == AD_STATE_FIXED) 1894 ctx->domain_guid.state = AD_STATE_INVALID; 1895 return (0); 1896 } 1897 1898 void 1899 auto_set_DomainGUID(ad_disc_t ctx, uchar_t *u) 1900 { 1901 char *domain_guid = NULL; 1902 1903 if (is_fixed(&ctx->domain_guid)) 1904 return; 1905 1906 domain_guid = uuid_dup(u); 1907 if (domain_guid == NULL) 1908 return; 1909 update_item(&ctx->domain_guid, domain_guid, AD_STATE_AUTO, 0); 1910 } 1911 1912 int 1913 ad_disc_set_DomainController(ad_disc_t ctx, 1914 const ad_disc_ds_t *domainController) 1915 { 1916 ad_disc_ds_t *domain_controller = NULL; 1917 if (domainController != NULL) { 1918 domain_controller = ds_dup(domainController); 1919 if (domain_controller == NULL) 1920 return (-1); 1921 update_item(&ctx->domain_controller, domain_controller, 1922 AD_STATE_FIXED, 0); 1923 } else if (ctx->domain_controller.state == AD_STATE_FIXED) 1924 ctx->domain_controller.state = AD_STATE_INVALID; 1925 return (0); 1926 } 1927 1928 int 1929 ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 1930 { 1931 char *site_name = NULL; 1932 if (siteName != NULL) { 1933 site_name = strdup(siteName); 1934 if (site_name == NULL) 1935 return (-1); 1936 update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 1937 } else if (ctx->site_name.state == AD_STATE_FIXED) 1938 ctx->site_name.state = AD_STATE_INVALID; 1939 return (0); 1940 } 1941 1942 void 1943 auto_set_SiteName(ad_disc_t ctx, char *siteName) 1944 { 1945 char *site_name = NULL; 1946 1947 if (is_fixed(&ctx->site_name)) 1948 return; 1949 1950 site_name = strdup(siteName); 1951 if (site_name == NULL) 1952 return; 1953 update_item(&ctx->site_name, site_name, AD_STATE_AUTO, 0); 1954 } 1955 1956 int 1957 ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 1958 { 1959 char *forest_name = NULL; 1960 if (forestName != NULL) { 1961 forest_name = strdup(forestName); 1962 if (forest_name == NULL) 1963 return (-1); 1964 update_item(&ctx->forest_name, forest_name, 1965 AD_STATE_FIXED, 0); 1966 } else if (ctx->forest_name.state == AD_STATE_FIXED) 1967 ctx->forest_name.state = AD_STATE_INVALID; 1968 return (0); 1969 } 1970 1971 void 1972 auto_set_ForestName(ad_disc_t ctx, char *forestName) 1973 { 1974 char *forest_name = NULL; 1975 1976 if (is_fixed(&ctx->forest_name)) 1977 return; 1978 1979 forest_name = strdup(forestName); 1980 if (forest_name == NULL) 1981 return; 1982 update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 1983 } 1984 1985 int 1986 ad_disc_set_GlobalCatalog(ad_disc_t ctx, 1987 const ad_disc_ds_t *globalCatalog) 1988 { 1989 ad_disc_ds_t *global_catalog = NULL; 1990 if (globalCatalog != NULL) { 1991 global_catalog = ds_dup(globalCatalog); 1992 if (global_catalog == NULL) 1993 return (-1); 1994 update_item(&ctx->global_catalog, global_catalog, 1995 AD_STATE_FIXED, 0); 1996 } else if (ctx->global_catalog.state == AD_STATE_FIXED) 1997 ctx->global_catalog.state = AD_STATE_INVALID; 1998 return (0); 1999 } 2000 2001 int 2002 ad_disc_set_PreferredDC(ad_disc_t ctx, const ad_disc_ds_t *pref_dc) 2003 { 2004 ad_disc_ds_t *new_pref_dc = NULL; 2005 if (pref_dc != NULL) { 2006 new_pref_dc = ds_dup(pref_dc); 2007 if (new_pref_dc == NULL) 2008 return (-1); 2009 update_item(&ctx->preferred_dc, new_pref_dc, 2010 AD_STATE_FIXED, 0); 2011 } else if (ctx->preferred_dc.state == AD_STATE_FIXED) 2012 ctx->preferred_dc.state = AD_STATE_INVALID; 2013 return (0); 2014 } 2015 2016 void 2017 ad_disc_set_StatusFP(ad_disc_t ctx, struct __FILE_TAG *fp) 2018 { 2019 ctx->status_fp = fp; 2020 } 2021 2022 2023 int 2024 ad_disc_unset(ad_disc_t ctx) 2025 { 2026 if (ctx->domain_name.state == AD_STATE_FIXED) 2027 ctx->domain_name.state = AD_STATE_INVALID; 2028 2029 if (ctx->domain_controller.state == AD_STATE_FIXED) 2030 ctx->domain_controller.state = AD_STATE_INVALID; 2031 2032 if (ctx->preferred_dc.state == AD_STATE_FIXED) 2033 ctx->preferred_dc.state = AD_STATE_INVALID; 2034 2035 if (ctx->site_name.state == AD_STATE_FIXED) 2036 ctx->site_name.state = AD_STATE_INVALID; 2037 2038 if (ctx->forest_name.state == AD_STATE_FIXED) 2039 ctx->forest_name.state = AD_STATE_INVALID; 2040 2041 if (ctx->global_catalog.state == AD_STATE_FIXED) 2042 ctx->global_catalog.state = AD_STATE_INVALID; 2043 2044 return (0); 2045 } 2046 2047 /* 2048 * ad_disc_get_TTL 2049 * 2050 * This routines the time to live for AD 2051 * auto discovered items. 2052 * 2053 * Returns: 2054 * -1 if there are no TTL items 2055 * 0 if there are expired items 2056 * else the number of seconds 2057 * 2058 * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 2059 * is positive -- min() greater than zero. 2060 */ 2061 #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 2062 (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 2063 int 2064 ad_disc_get_TTL(ad_disc_t ctx) 2065 { 2066 time_t expires; 2067 int ttl; 2068 2069 expires = MIN_GT_ZERO(ctx->domain_controller.expires, 2070 ctx->global_catalog.expires); 2071 expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires); 2072 expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires); 2073 2074 if (expires == -1) { 2075 return (-1); 2076 } 2077 2078 if (ctx->expires_not_before != 0 && 2079 expires < ctx->expires_not_before) { 2080 expires = ctx->expires_not_before; 2081 } 2082 2083 if (ctx->expires_not_after != 0 && 2084 expires > ctx->expires_not_after) { 2085 expires = ctx->expires_not_after; 2086 } 2087 2088 ttl = expires - time(NULL); 2089 2090 if (ttl < 0) { 2091 return (0); 2092 } 2093 return (ttl); 2094 } 2095 2096 boolean_t 2097 ad_disc_SubnetChanged(ad_disc_t ctx) 2098 { 2099 ad_subnet_t *subnets; 2100 2101 if (ctx->subnets_changed || ctx->subnets == NULL) 2102 return (B_TRUE); 2103 2104 if ((subnets = find_subnets()) != NULL) { 2105 if (cmpsubnets(subnets, ctx->subnets) != 0) 2106 ctx->subnets_changed = B_TRUE; 2107 free(subnets); 2108 } 2109 2110 return (ctx->subnets_changed); 2111 } 2112