17a8a68f5SJulian Pullen /* 27a8a68f5SJulian Pullen * CDDL HEADER START 37a8a68f5SJulian Pullen * 47a8a68f5SJulian Pullen * The contents of this file are subject to the terms of the 57a8a68f5SJulian Pullen * Common Development and Distribution License (the "License"). 67a8a68f5SJulian Pullen * You may not use this file except in compliance with the License. 77a8a68f5SJulian Pullen * 87a8a68f5SJulian Pullen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97a8a68f5SJulian Pullen * or http://www.opensolaris.org/os/licensing. 107a8a68f5SJulian Pullen * See the License for the specific language governing permissions 117a8a68f5SJulian Pullen * and limitations under the License. 127a8a68f5SJulian Pullen * 137a8a68f5SJulian Pullen * When distributing Covered Code, include this CDDL HEADER in each 147a8a68f5SJulian Pullen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157a8a68f5SJulian Pullen * If applicable, add the following below this CDDL HEADER, with the 167a8a68f5SJulian Pullen * fields enclosed by brackets "[]" replaced with your own identifying 177a8a68f5SJulian Pullen * information: Portions Copyright [yyyy] [name of copyright owner] 187a8a68f5SJulian Pullen * 197a8a68f5SJulian Pullen * CDDL HEADER END 207a8a68f5SJulian Pullen */ 217a8a68f5SJulian Pullen 227a8a68f5SJulian Pullen /* 23*c5866007SKeyur Desai * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 247a8a68f5SJulian Pullen */ 257a8a68f5SJulian Pullen 267a8a68f5SJulian Pullen /* 277a8a68f5SJulian Pullen * Active Directory Auto-Discovery. 287a8a68f5SJulian Pullen * 297a8a68f5SJulian Pullen * This [project private] API allows the caller to provide whatever 307a8a68f5SJulian Pullen * details it knows a priori (i.e., provided via configuration so as to 317a8a68f5SJulian Pullen * override auto-discovery) and in any order. Then the caller can ask 327a8a68f5SJulian Pullen * for any of the auto-discoverable parameters in any order. 337a8a68f5SJulian Pullen * 347a8a68f5SJulian Pullen * But there is an actual order in which discovery must be done. Given 357a8a68f5SJulian Pullen * the discovery mechanism implemented here, that order is: 367a8a68f5SJulian Pullen * 377a8a68f5SJulian Pullen * - the domain name joined must be discovered first 387a8a68f5SJulian Pullen * - then the domain controllers 397a8a68f5SJulian Pullen * - then the forest name and site name 407a8a68f5SJulian Pullen * - then the global catalog servers, and site-specific domain 417a8a68f5SJulian Pullen * controllers and global catalog servers. 427a8a68f5SJulian Pullen * 437a8a68f5SJulian Pullen * The API does not require it be called in the same order because there 447a8a68f5SJulian Pullen * may be other discovery mechanisms in the future, and exposing 457a8a68f5SJulian Pullen * ordering requirements of the current mechanism now can create trouble 467a8a68f5SJulian Pullen * down the line. Also, this makes the API easier to use now, which 477a8a68f5SJulian Pullen * means less work to do some day when we make this a public API. 487a8a68f5SJulian Pullen * 497a8a68f5SJulian Pullen * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 507a8a68f5SJulian Pullen * domain controllers. As long as the joined domain appears in the DNS 517a8a68f5SJulian Pullen * resolver's search list then we'll find it. 527a8a68f5SJulian Pullen * 537a8a68f5SJulian Pullen * Domain controller discovery is a matter of formatting the DNS SRV RR 547a8a68f5SJulian Pullen * FQDN for domain controllers and doing a lookup for them. Knowledge 557a8a68f5SJulian Pullen * of the domain name is not fundamentally required, but we separate the 567a8a68f5SJulian Pullen * two processes, which in practice can lead to one more DNS lookup than 577a8a68f5SJulian Pullen * is strictly required. 587a8a68f5SJulian Pullen * 597a8a68f5SJulian Pullen * Forest and site name discovery require an LDAP search of the AD 607a8a68f5SJulian Pullen * "configuration partition" at a domain controller for the joined 617a8a68f5SJulian Pullen * domain. Forest and site name discovery depend on knowing the joined 627a8a68f5SJulian Pullen * domain name and domain controllers for that domain. 637a8a68f5SJulian Pullen * 647a8a68f5SJulian Pullen * Global catalog server discovery requires knowledge of the forest 657a8a68f5SJulian Pullen * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 667a8a68f5SJulian Pullen * domain controller discovery depends on knowing the site name (and, 677a8a68f5SJulian Pullen * therefore, joined domain, ...). Site-specific global catalog server 687a8a68f5SJulian Pullen * discovery depends on knowledge of the forest and site names, which 697a8a68f5SJulian Pullen * depend on... 707a8a68f5SJulian Pullen * 717a8a68f5SJulian Pullen * All the work of discovering particular items is done by functions 727a8a68f5SJulian Pullen * named validate_<item>(). Each such function calls validate_<item>() 737a8a68f5SJulian Pullen * for any items that it depends on. 747a8a68f5SJulian Pullen * 757a8a68f5SJulian Pullen * This API is not thread-safe. 767a8a68f5SJulian Pullen */ 777a8a68f5SJulian Pullen 787a8a68f5SJulian Pullen 797a8a68f5SJulian Pullen #include <stdio.h> 807a8a68f5SJulian Pullen #include <string.h> 817a8a68f5SJulian Pullen #include <strings.h> 827a8a68f5SJulian Pullen #include <unistd.h> 837a8a68f5SJulian Pullen #include <assert.h> 847a8a68f5SJulian Pullen #include <stdlib.h> 857a8a68f5SJulian Pullen #include <net/if.h> 867a8a68f5SJulian Pullen #include <net/if.h> 877a8a68f5SJulian Pullen #include <sys/types.h> 887a8a68f5SJulian Pullen #include <sys/socket.h> 897a8a68f5SJulian Pullen #include <sys/sockio.h> 907a8a68f5SJulian Pullen #include <netinet/in.h> 917a8a68f5SJulian Pullen #include <netinet/in.h> 927a8a68f5SJulian Pullen #include <arpa/inet.h> 937a8a68f5SJulian Pullen #include <arpa/nameser.h> 947a8a68f5SJulian Pullen #include <resolv.h> 957a8a68f5SJulian Pullen #include <netdb.h> 967a8a68f5SJulian Pullen #include <ctype.h> 977a8a68f5SJulian Pullen #include <errno.h> 987a8a68f5SJulian Pullen #include <ldap.h> 997a8a68f5SJulian Pullen #include <sasl/sasl.h> 1007a8a68f5SJulian Pullen #include <sys/u8_textprep.h> 1017a8a68f5SJulian Pullen #include <syslog.h> 1027a8a68f5SJulian Pullen #include "adutils_impl.h" 1037a8a68f5SJulian Pullen #include "addisc.h" 1047a8a68f5SJulian Pullen 105*c5866007SKeyur Desai /* 106*c5866007SKeyur Desai * These set some sanity policies for discovery. After a discovery 107*c5866007SKeyur Desai * cycle, we will consider the results (successful or unsuccessful) 108*c5866007SKeyur Desai * to be valid for at least MINIMUM_TTL seconds, and for at most 109*c5866007SKeyur Desai * MAXIMUM_TTL seconds. Note that the caller is free to request 110*c5866007SKeyur Desai * discovery cycles sooner than MINIMUM_TTL if it has reason to believe 111*c5866007SKeyur Desai * that the situation has changed. 112*c5866007SKeyur Desai */ 113*c5866007SKeyur Desai #define MINIMUM_TTL (5 * 60) 114*c5866007SKeyur Desai #define MAXIMUM_TTL (20 * 60) 1157a8a68f5SJulian Pullen 1167a8a68f5SJulian Pullen enum ad_item_state { 1177a8a68f5SJulian Pullen AD_STATE_INVALID = 0, /* The value is not valid */ 1187a8a68f5SJulian Pullen AD_STATE_FIXED, /* The value was fixed by caller */ 1197a8a68f5SJulian Pullen AD_STATE_AUTO /* The value is auto discovered */ 1207a8a68f5SJulian Pullen }; 1217a8a68f5SJulian Pullen 1227a8a68f5SJulian Pullen enum ad_data_type { 1237a8a68f5SJulian Pullen AD_STRING = 123, 1247a8a68f5SJulian Pullen AD_DIRECTORY, 1257a8a68f5SJulian Pullen AD_DOMAINS_IN_FOREST, 1267a8a68f5SJulian Pullen AD_TRUSTED_DOMAINS 1277a8a68f5SJulian Pullen }; 1287a8a68f5SJulian Pullen 1297a8a68f5SJulian Pullen 1307a8a68f5SJulian Pullen typedef struct ad_subnet { 1317a8a68f5SJulian Pullen char subnet[24]; 1327a8a68f5SJulian Pullen } ad_subnet_t; 1337a8a68f5SJulian Pullen 1347a8a68f5SJulian Pullen 1357a8a68f5SJulian Pullen typedef struct ad_item { 1367a8a68f5SJulian Pullen enum ad_item_state state; 1377a8a68f5SJulian Pullen enum ad_data_type type; 1387a8a68f5SJulian Pullen void *value; 139*c5866007SKeyur Desai time_t expires; 1407a8a68f5SJulian Pullen unsigned int version; /* Version is only changed */ 1417a8a68f5SJulian Pullen /* if the value changes */ 1427a8a68f5SJulian Pullen #define PARAM1 0 1437a8a68f5SJulian Pullen #define PARAM2 1 1447a8a68f5SJulian Pullen int param_version[2]; 1457a8a68f5SJulian Pullen /* These holds the version of */ 1467a8a68f5SJulian Pullen /* dependents so that a dependent */ 1477a8a68f5SJulian Pullen /* change can be detected */ 1487a8a68f5SJulian Pullen } ad_item_t; 1497a8a68f5SJulian Pullen 1507a8a68f5SJulian Pullen typedef struct ad_disc { 1517a8a68f5SJulian Pullen struct __res_state res_state; 1527a8a68f5SJulian Pullen int res_ninitted; 1537a8a68f5SJulian Pullen ad_subnet_t *subnets; 1547a8a68f5SJulian Pullen boolean_t subnets_changed; 1557a8a68f5SJulian Pullen time_t subnets_last_check; 156*c5866007SKeyur Desai time_t expires_not_before; 157*c5866007SKeyur Desai time_t expires_not_after; 1587a8a68f5SJulian Pullen ad_item_t domain_name; /* DNS hostname string */ 1597a8a68f5SJulian Pullen ad_item_t domain_controller; /* Directory hostname and */ 1607a8a68f5SJulian Pullen /* port array */ 1617a8a68f5SJulian Pullen ad_item_t site_name; /* String */ 1627a8a68f5SJulian Pullen ad_item_t forest_name; /* DNS forestname string */ 1637a8a68f5SJulian Pullen ad_item_t global_catalog; /* Directory hostname and */ 1647a8a68f5SJulian Pullen /* port array */ 1657a8a68f5SJulian Pullen ad_item_t domains_in_forest; /* DNS domainname and SID */ 1667a8a68f5SJulian Pullen /* array */ 1677a8a68f5SJulian Pullen ad_item_t trusted_domains; /* DNS domainname and trust */ 1687a8a68f5SJulian Pullen /* direction array */ 1697a8a68f5SJulian Pullen /* Site specfic versions */ 1707a8a68f5SJulian Pullen ad_item_t site_domain_controller; /* Directory hostname and */ 1717a8a68f5SJulian Pullen /* port array */ 1727a8a68f5SJulian Pullen ad_item_t site_global_catalog; /* Directory hostname and */ 1737a8a68f5SJulian Pullen /* port array */ 1747a8a68f5SJulian Pullen } ad_disc; 1757a8a68f5SJulian Pullen 1767a8a68f5SJulian Pullen 1777a8a68f5SJulian Pullen #define DNS_MAX_NAME NS_MAXDNAME 1787a8a68f5SJulian Pullen 1797a8a68f5SJulian Pullen 1807a8a68f5SJulian Pullen /* SRV RR names for various queries */ 1817a8a68f5SJulian Pullen #define LDAP_SRV_HEAD "_ldap._tcp." 1827a8a68f5SJulian Pullen #define SITE_SRV_MIDDLE "%s._sites." 1837a8a68f5SJulian Pullen #define GC_SRV_TAIL "gc._msdcs" 1847a8a68f5SJulian Pullen #define DC_SRV_TAIL "dc._msdcs" 1857a8a68f5SJulian Pullen #define ALL_GC_SRV_TAIL "_gc._tcp" 1867a8a68f5SJulian Pullen #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 1877a8a68f5SJulian Pullen 1887a8a68f5SJulian Pullen /* A RR name for all GCs -- last resort this works */ 1897a8a68f5SJulian Pullen #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 1907a8a68f5SJulian Pullen 1917a8a68f5SJulian Pullen 1927a8a68f5SJulian Pullen /* 1937a8a68f5SJulian Pullen * We try res_ninit() whenever we don't have one. res_ninit() fails if 1947a8a68f5SJulian Pullen * idmapd is running before the network is up! 1957a8a68f5SJulian Pullen */ 1967a8a68f5SJulian Pullen #define DO_RES_NINIT(ctx) if (!(ctx)->res_ninitted) \ 1977a8a68f5SJulian Pullen (ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1) 1987a8a68f5SJulian Pullen 1997a8a68f5SJulian Pullen #define is_fixed(item) \ 2007a8a68f5SJulian Pullen ((item)->state == AD_STATE_FIXED) 2017a8a68f5SJulian Pullen 2027a8a68f5SJulian Pullen #define is_changed(item, num, param) \ 2037a8a68f5SJulian Pullen ((item)->param_version[num] != (param)->version) 2047a8a68f5SJulian Pullen 2057a8a68f5SJulian Pullen /*LINTLIBRARY*/ 2067a8a68f5SJulian Pullen 2077a8a68f5SJulian Pullen /* 2087a8a68f5SJulian Pullen * Function definitions 2097a8a68f5SJulian Pullen */ 2107a8a68f5SJulian Pullen static ad_item_t * 2117a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx); 2127a8a68f5SJulian Pullen 2137a8a68f5SJulian Pullen 2147a8a68f5SJulian Pullen 2157a8a68f5SJulian Pullen static void 2167a8a68f5SJulian Pullen update_version(ad_item_t *item, int num, ad_item_t *param) 2177a8a68f5SJulian Pullen { 2187a8a68f5SJulian Pullen item->param_version[num] = param->version; 2197a8a68f5SJulian Pullen } 2207a8a68f5SJulian Pullen 2217a8a68f5SJulian Pullen 2227a8a68f5SJulian Pullen 2237a8a68f5SJulian Pullen static boolean_t 2247a8a68f5SJulian Pullen is_valid(ad_item_t *item) 2257a8a68f5SJulian Pullen { 2267a8a68f5SJulian Pullen if (item->value != NULL) { 2277a8a68f5SJulian Pullen if (item->state == AD_STATE_FIXED) 2287a8a68f5SJulian Pullen return (B_TRUE); 2297a8a68f5SJulian Pullen if (item->state == AD_STATE_AUTO && 230*c5866007SKeyur Desai (item->expires == 0 || item->expires > time(NULL))) 2317a8a68f5SJulian Pullen return (B_TRUE); 2327a8a68f5SJulian Pullen } 2337a8a68f5SJulian Pullen return (B_FALSE); 2347a8a68f5SJulian Pullen } 2357a8a68f5SJulian Pullen 2367a8a68f5SJulian Pullen 2377a8a68f5SJulian Pullen static void 2387a8a68f5SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state, 2397a8a68f5SJulian Pullen uint32_t ttl) 2407a8a68f5SJulian Pullen { 2417a8a68f5SJulian Pullen if (item->value != NULL && value != NULL) { 2427a8a68f5SJulian Pullen if ((item->type == AD_STRING && 2437a8a68f5SJulian Pullen strcmp(item->value, value) != 0) || 2447a8a68f5SJulian Pullen (item->type == AD_DIRECTORY && 2457a8a68f5SJulian Pullen ad_disc_compare_ds(item->value, value) != 0)|| 2467a8a68f5SJulian Pullen (item->type == AD_DOMAINS_IN_FOREST && 2477a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(item->value, value) != 0) || 2487a8a68f5SJulian Pullen (item->type == AD_TRUSTED_DOMAINS && 2497a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(item->value, value) != 0)) 2507a8a68f5SJulian Pullen item->version++; 2517a8a68f5SJulian Pullen } else if (item->value != value) 2527a8a68f5SJulian Pullen item->version++; 2537a8a68f5SJulian Pullen 2547a8a68f5SJulian Pullen if (item->value != NULL) 2557a8a68f5SJulian Pullen free(item->value); 2567a8a68f5SJulian Pullen 2577a8a68f5SJulian Pullen item->value = value; 2587a8a68f5SJulian Pullen item->state = state; 2597a8a68f5SJulian Pullen 2607a8a68f5SJulian Pullen if (ttl == 0) 261*c5866007SKeyur Desai item->expires = 0; 2627a8a68f5SJulian Pullen else 263*c5866007SKeyur Desai item->expires = time(NULL) + ttl; 2647a8a68f5SJulian Pullen } 2657a8a68f5SJulian Pullen 2667a8a68f5SJulian Pullen 2677a8a68f5SJulian Pullen /* Compare DS lists */ 2687a8a68f5SJulian Pullen int 2697a8a68f5SJulian Pullen ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) 2707a8a68f5SJulian Pullen { 2717a8a68f5SJulian Pullen int i, j; 2727a8a68f5SJulian Pullen int num_ds1; 2737a8a68f5SJulian Pullen int num_ds2; 2747a8a68f5SJulian Pullen boolean_t match; 2757a8a68f5SJulian Pullen 2767a8a68f5SJulian Pullen for (i = 0; ds1[i].host[0] != '\0'; i++) 2777a8a68f5SJulian Pullen continue; 2787a8a68f5SJulian Pullen num_ds1 = i; 2797a8a68f5SJulian Pullen for (j = 0; ds2[j].host[0] != '\0'; j++) 2807a8a68f5SJulian Pullen continue; 2817a8a68f5SJulian Pullen num_ds2 = j; 2827a8a68f5SJulian Pullen if (num_ds1 != num_ds2) 2837a8a68f5SJulian Pullen return (1); 2847a8a68f5SJulian Pullen 2857a8a68f5SJulian Pullen for (i = 0; i < num_ds1; i++) { 2867a8a68f5SJulian Pullen match = B_FALSE; 2877a8a68f5SJulian Pullen for (j = 0; j < num_ds2; j++) { 288928e1f97SJordan Brown if (strcmp(ds1[i].host, ds2[j].host) == 0 && 289928e1f97SJordan Brown ds1[i].port == ds2[j].port) { 2907a8a68f5SJulian Pullen match = B_TRUE; 2917a8a68f5SJulian Pullen break; 2927a8a68f5SJulian Pullen } 2937a8a68f5SJulian Pullen } 2947a8a68f5SJulian Pullen if (!match) 2957a8a68f5SJulian Pullen return (1); 2967a8a68f5SJulian Pullen } 2977a8a68f5SJulian Pullen return (0); 2987a8a68f5SJulian Pullen } 2997a8a68f5SJulian Pullen 3007a8a68f5SJulian Pullen 3017a8a68f5SJulian Pullen /* Copy a list of DSs */ 3027a8a68f5SJulian Pullen static idmap_ad_disc_ds_t * 3037a8a68f5SJulian Pullen ds_dup(const idmap_ad_disc_ds_t *srv) 3047a8a68f5SJulian Pullen { 3057a8a68f5SJulian Pullen int i; 3067a8a68f5SJulian Pullen int size; 3077a8a68f5SJulian Pullen idmap_ad_disc_ds_t *new = NULL; 3087a8a68f5SJulian Pullen 3097a8a68f5SJulian Pullen for (i = 0; srv[i].host[0] != '\0'; i++) 3107a8a68f5SJulian Pullen continue; 3117a8a68f5SJulian Pullen 3127a8a68f5SJulian Pullen size = (i + 1) * sizeof (idmap_ad_disc_ds_t); 3137a8a68f5SJulian Pullen new = malloc(size); 3147a8a68f5SJulian Pullen if (new != NULL) 3157a8a68f5SJulian Pullen memcpy(new, srv, size); 3167a8a68f5SJulian Pullen return (new); 3177a8a68f5SJulian Pullen } 3187a8a68f5SJulian Pullen 3197a8a68f5SJulian Pullen 3207a8a68f5SJulian Pullen int 3217a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 3227a8a68f5SJulian Pullen ad_disc_trusteddomains_t *td2) 3237a8a68f5SJulian Pullen { 3247a8a68f5SJulian Pullen int i, j; 3257a8a68f5SJulian Pullen int num_td1; 3267a8a68f5SJulian Pullen int num_td2; 3277a8a68f5SJulian Pullen boolean_t match; 3287a8a68f5SJulian Pullen 3297a8a68f5SJulian Pullen for (i = 0; td1[i].domain[0] != '\0'; i++) 3307a8a68f5SJulian Pullen continue; 3317a8a68f5SJulian Pullen num_td1 = i; 3327a8a68f5SJulian Pullen 3337a8a68f5SJulian Pullen for (j = 0; td2[j].domain[0] != '\0'; j++) 3347a8a68f5SJulian Pullen continue; 3357a8a68f5SJulian Pullen num_td2 = j; 3367a8a68f5SJulian Pullen 3377a8a68f5SJulian Pullen if (num_td1 != num_td2) 3387a8a68f5SJulian Pullen return (1); 3397a8a68f5SJulian Pullen 3407a8a68f5SJulian Pullen for (i = 0; i < num_td1; i++) { 3417a8a68f5SJulian Pullen match = B_FALSE; 3427a8a68f5SJulian Pullen for (j = 0; j < num_td2; j++) { 3431fcced4cSJordan Brown if (domain_eq(td1[i].domain, td2[j].domain)) { 3447a8a68f5SJulian Pullen match = B_TRUE; 3457a8a68f5SJulian Pullen break; 3467a8a68f5SJulian Pullen } 3477a8a68f5SJulian Pullen } 3487a8a68f5SJulian Pullen if (!match) 3497a8a68f5SJulian Pullen return (1); 3507a8a68f5SJulian Pullen } 3517a8a68f5SJulian Pullen return (0); 3527a8a68f5SJulian Pullen } 3537a8a68f5SJulian Pullen 3547a8a68f5SJulian Pullen 3557a8a68f5SJulian Pullen 3567a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 3577a8a68f5SJulian Pullen static ad_disc_trusteddomains_t * 3587a8a68f5SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td) 3597a8a68f5SJulian Pullen { 3607a8a68f5SJulian Pullen int i; 3617a8a68f5SJulian Pullen int size; 3627a8a68f5SJulian Pullen ad_disc_trusteddomains_t *new = NULL; 3637a8a68f5SJulian Pullen 3647a8a68f5SJulian Pullen for (i = 0; td[i].domain[0] != '\0'; i++) 3657a8a68f5SJulian Pullen continue; 3667a8a68f5SJulian Pullen 3677a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 3687a8a68f5SJulian Pullen new = malloc(size); 3697a8a68f5SJulian Pullen if (new != NULL) 3707a8a68f5SJulian Pullen memcpy(new, td, size); 3717a8a68f5SJulian Pullen return (new); 3727a8a68f5SJulian Pullen } 3737a8a68f5SJulian Pullen 3747a8a68f5SJulian Pullen 3757a8a68f5SJulian Pullen 3767a8a68f5SJulian Pullen int 3777a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 3787a8a68f5SJulian Pullen ad_disc_domainsinforest_t *df2) 3797a8a68f5SJulian Pullen { 3807a8a68f5SJulian Pullen int i, j; 3817a8a68f5SJulian Pullen int num_df1; 3827a8a68f5SJulian Pullen int num_df2; 3837a8a68f5SJulian Pullen boolean_t match; 3847a8a68f5SJulian Pullen 3857a8a68f5SJulian Pullen for (i = 0; df1[i].domain[0] != '\0'; i++) 3867a8a68f5SJulian Pullen continue; 3877a8a68f5SJulian Pullen num_df1 = i; 3887a8a68f5SJulian Pullen 3897a8a68f5SJulian Pullen for (j = 0; df2[j].domain[0] != '\0'; j++) 3907a8a68f5SJulian Pullen continue; 3917a8a68f5SJulian Pullen num_df2 = j; 3927a8a68f5SJulian Pullen 3937a8a68f5SJulian Pullen if (num_df1 != num_df2) 3947a8a68f5SJulian Pullen return (1); 3957a8a68f5SJulian Pullen 3967a8a68f5SJulian Pullen for (i = 0; i < num_df1; i++) { 3977a8a68f5SJulian Pullen match = B_FALSE; 3987a8a68f5SJulian Pullen for (j = 0; j < num_df2; j++) { 3991fcced4cSJordan Brown if (domain_eq(df1[i].domain, df2[j].domain) && 400928e1f97SJordan Brown strcmp(df1[i].sid, df2[j].sid) == 0) { 4017a8a68f5SJulian Pullen match = B_TRUE; 4027a8a68f5SJulian Pullen break; 4037a8a68f5SJulian Pullen } 4047a8a68f5SJulian Pullen } 4057a8a68f5SJulian Pullen if (!match) 4067a8a68f5SJulian Pullen return (1); 4077a8a68f5SJulian Pullen } 4087a8a68f5SJulian Pullen return (0); 4097a8a68f5SJulian Pullen } 4107a8a68f5SJulian Pullen 4117a8a68f5SJulian Pullen 4127a8a68f5SJulian Pullen 4137a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 4147a8a68f5SJulian Pullen static ad_disc_domainsinforest_t * 4157a8a68f5SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df) 4167a8a68f5SJulian Pullen { 4177a8a68f5SJulian Pullen int i; 4187a8a68f5SJulian Pullen int size; 4197a8a68f5SJulian Pullen ad_disc_domainsinforest_t *new = NULL; 4207a8a68f5SJulian Pullen 4217a8a68f5SJulian Pullen for (i = 0; df[i].domain[0] != '\0'; i++) 4227a8a68f5SJulian Pullen continue; 4237a8a68f5SJulian Pullen 4247a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 4257a8a68f5SJulian Pullen new = malloc(size); 4267a8a68f5SJulian Pullen if (new != NULL) 4277a8a68f5SJulian Pullen memcpy(new, df, size); 4287a8a68f5SJulian Pullen return (new); 4297a8a68f5SJulian Pullen } 4307a8a68f5SJulian Pullen 4317a8a68f5SJulian Pullen 4327a8a68f5SJulian Pullen 4337a8a68f5SJulian Pullen 4347a8a68f5SJulian Pullen 4357a8a68f5SJulian Pullen /* 4367a8a68f5SJulian Pullen * Returns an array of IPv4 address/prefix length 4377a8a68f5SJulian Pullen * The last subnet is NULL 4387a8a68f5SJulian Pullen */ 4397a8a68f5SJulian Pullen static ad_subnet_t * 4407a8a68f5SJulian Pullen find_subnets() 4417a8a68f5SJulian Pullen { 4427a8a68f5SJulian Pullen int sock, n, i; 4437a8a68f5SJulian Pullen struct lifconf lifc; 4447a8a68f5SJulian Pullen struct lifreq lifr, *lifrp; 4457a8a68f5SJulian Pullen struct lifnum lifn; 4467a8a68f5SJulian Pullen uint32_t prefix_len; 4477a8a68f5SJulian Pullen char *s; 4487a8a68f5SJulian Pullen ad_subnet_t *results; 4497a8a68f5SJulian Pullen 4507a8a68f5SJulian Pullen lifrp = &lifr; 4517a8a68f5SJulian Pullen 4527a8a68f5SJulian Pullen if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 4537a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to open IPv4 socket for " 4547a8a68f5SJulian Pullen "listing network interfaces (%s)", strerror(errno)); 4557a8a68f5SJulian Pullen return (NULL); 4567a8a68f5SJulian Pullen } 4577a8a68f5SJulian Pullen 4587a8a68f5SJulian Pullen lifn.lifn_family = AF_INET; 4597a8a68f5SJulian Pullen lifn.lifn_flags = 0; 4607a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4617a8a68f5SJulian Pullen logger(LOG_ERR, 4627a8a68f5SJulian Pullen "Failed to find the number of network interfaces (%s)", 4637a8a68f5SJulian Pullen strerror(errno)); 4647a8a68f5SJulian Pullen close(sock); 4657a8a68f5SJulian Pullen return (NULL); 4667a8a68f5SJulian Pullen } 4677a8a68f5SJulian Pullen 4687a8a68f5SJulian Pullen if (lifn.lifn_count < 1) { 4697a8a68f5SJulian Pullen logger(LOG_ERR, "No IPv4 network interfaces found"); 4707a8a68f5SJulian Pullen close(sock); 4717a8a68f5SJulian Pullen return (NULL); 4727a8a68f5SJulian Pullen } 4737a8a68f5SJulian Pullen 4747a8a68f5SJulian Pullen lifc.lifc_family = AF_INET; 4757a8a68f5SJulian Pullen lifc.lifc_flags = 0; 4767a8a68f5SJulian Pullen lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 4777a8a68f5SJulian Pullen lifc.lifc_buf = malloc(lifc.lifc_len); 4787a8a68f5SJulian Pullen 4797a8a68f5SJulian Pullen if (lifc.lifc_buf == NULL) { 4807a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 4817a8a68f5SJulian Pullen close(sock); 4827a8a68f5SJulian Pullen return (NULL); 4837a8a68f5SJulian Pullen } 4847a8a68f5SJulian Pullen 4857a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 4867a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to list network interfaces (%s)", 4877a8a68f5SJulian Pullen strerror(errno)); 4887a8a68f5SJulian Pullen free(lifc.lifc_buf); 4897a8a68f5SJulian Pullen close(sock); 4907a8a68f5SJulian Pullen return (NULL); 4917a8a68f5SJulian Pullen } 4927a8a68f5SJulian Pullen 4937a8a68f5SJulian Pullen n = lifc.lifc_len / (int)sizeof (struct lifreq); 4947a8a68f5SJulian Pullen 4957a8a68f5SJulian Pullen if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 4967a8a68f5SJulian Pullen free(lifc.lifc_buf); 4977a8a68f5SJulian Pullen close(sock); 4987a8a68f5SJulian Pullen return (NULL); 4997a8a68f5SJulian Pullen } 5007a8a68f5SJulian Pullen 5017a8a68f5SJulian Pullen for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 5027a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 5037a8a68f5SJulian Pullen continue; 5047a8a68f5SJulian Pullen 5057a8a68f5SJulian Pullen if ((lifrp->lifr_flags & IFF_UP) == 0) 5067a8a68f5SJulian Pullen continue; 5077a8a68f5SJulian Pullen 5087a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 5097a8a68f5SJulian Pullen continue; 5107a8a68f5SJulian Pullen 5117a8a68f5SJulian Pullen prefix_len = lifrp->lifr_addrlen; 5127a8a68f5SJulian Pullen 5137a8a68f5SJulian Pullen s = inet_ntoa(((struct sockaddr_in *) 5147a8a68f5SJulian Pullen &lifrp->lifr_addr)->sin_addr); 5157a8a68f5SJulian Pullen 5167a8a68f5SJulian Pullen (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 5177a8a68f5SJulian Pullen "%s/%d", s, prefix_len); 5187a8a68f5SJulian Pullen } 5197a8a68f5SJulian Pullen 5207a8a68f5SJulian Pullen free(lifc.lifc_buf); 5217a8a68f5SJulian Pullen close(sock); 5227a8a68f5SJulian Pullen 5237a8a68f5SJulian Pullen return (results); 5247a8a68f5SJulian Pullen } 5257a8a68f5SJulian Pullen 5267a8a68f5SJulian Pullen static int 5277a8a68f5SJulian Pullen cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 5287a8a68f5SJulian Pullen { 5297a8a68f5SJulian Pullen int num_subnets1; 5307a8a68f5SJulian Pullen int num_subnets2; 5317a8a68f5SJulian Pullen boolean_t matched; 5327a8a68f5SJulian Pullen int i, j; 5337a8a68f5SJulian Pullen 5347a8a68f5SJulian Pullen for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 5357a8a68f5SJulian Pullen continue; 5367a8a68f5SJulian Pullen num_subnets1 = i; 5377a8a68f5SJulian Pullen 5387a8a68f5SJulian Pullen for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 5397a8a68f5SJulian Pullen continue; 5407a8a68f5SJulian Pullen num_subnets2 = i; 5417a8a68f5SJulian Pullen 5427a8a68f5SJulian Pullen if (num_subnets1 != num_subnets2) 5437a8a68f5SJulian Pullen return (1); 5447a8a68f5SJulian Pullen 5457a8a68f5SJulian Pullen for (i = 0; i < num_subnets1; i++) { 5467a8a68f5SJulian Pullen matched = B_FALSE; 5477a8a68f5SJulian Pullen for (j = 0; j < num_subnets2; j++) { 5487a8a68f5SJulian Pullen if (strcmp(subnets1[i].subnet, 5497a8a68f5SJulian Pullen subnets2[j].subnet) == 0) { 5507a8a68f5SJulian Pullen matched = B_TRUE; 5517a8a68f5SJulian Pullen break; 5527a8a68f5SJulian Pullen } 5537a8a68f5SJulian Pullen } 5547a8a68f5SJulian Pullen if (!matched) 5557a8a68f5SJulian Pullen return (1); 5567a8a68f5SJulian Pullen } 5577a8a68f5SJulian Pullen return (0); 5587a8a68f5SJulian Pullen } 5597a8a68f5SJulian Pullen 5607a8a68f5SJulian Pullen 5617a8a68f5SJulian Pullen 5627a8a68f5SJulian Pullen 5637a8a68f5SJulian Pullen /* Convert a DN's DC components into a DNS domainname */ 5647a8a68f5SJulian Pullen char * 5657a8a68f5SJulian Pullen DN_to_DNS(const char *dn_name) 5667a8a68f5SJulian Pullen { 5677a8a68f5SJulian Pullen char dns[DNS_MAX_NAME]; 5687a8a68f5SJulian Pullen char *dns_name; 5697a8a68f5SJulian Pullen int i, j; 5707a8a68f5SJulian Pullen int num = 0; 5717a8a68f5SJulian Pullen 5727a8a68f5SJulian Pullen j = 0; 5737a8a68f5SJulian Pullen i = 0; 5747a8a68f5SJulian Pullen 5757a8a68f5SJulian Pullen if (dn_name == NULL) 5767a8a68f5SJulian Pullen return (NULL); 5777a8a68f5SJulian Pullen /* 5787a8a68f5SJulian Pullen * Find all DC=<value> and form DNS name of the 5797a8a68f5SJulian Pullen * form <value1>.<value2>... 5807a8a68f5SJulian Pullen */ 5817a8a68f5SJulian Pullen while (dn_name[i] != '\0') { 5827a8a68f5SJulian Pullen if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 5837a8a68f5SJulian Pullen i += 3; 5847a8a68f5SJulian Pullen if (dn_name[i] != '\0' && num > 0) 5857a8a68f5SJulian Pullen dns[j++] = '.'; 5867a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 5877a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 5887a8a68f5SJulian Pullen dns[j++] = dn_name[i++]; 5897a8a68f5SJulian Pullen num++; 5907a8a68f5SJulian Pullen } else { 5917a8a68f5SJulian Pullen /* Skip attr=value as it is not DC= */ 5927a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 5937a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 5947a8a68f5SJulian Pullen i++; 5957a8a68f5SJulian Pullen } 5967a8a68f5SJulian Pullen /* Skip over separator ',' or '+' */ 5977a8a68f5SJulian Pullen if (dn_name[i] != '\0') i++; 5987a8a68f5SJulian Pullen } 5997a8a68f5SJulian Pullen dns[j] = '\0'; 6007a8a68f5SJulian Pullen dns_name = malloc(j + 1); 6017a8a68f5SJulian Pullen if (dns_name != NULL) 6027a8a68f5SJulian Pullen (void) strlcpy(dns_name, dns, j + 1); 6037a8a68f5SJulian Pullen return (dns_name); 6047a8a68f5SJulian Pullen } 6057a8a68f5SJulian Pullen 6067a8a68f5SJulian Pullen 6077a8a68f5SJulian Pullen /* Make a list of subnet object DNs from a list of subnets */ 6087a8a68f5SJulian Pullen static char ** 6097a8a68f5SJulian Pullen subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) 6107a8a68f5SJulian Pullen { 6117a8a68f5SJulian Pullen char **results; 6127a8a68f5SJulian Pullen int i, j; 6137a8a68f5SJulian Pullen 6147a8a68f5SJulian Pullen for (i = 0; subnets[i].subnet[0] != '\0'; i++) 6157a8a68f5SJulian Pullen continue; 6167a8a68f5SJulian Pullen 6177a8a68f5SJulian Pullen results = calloc(i + 1, sizeof (char *)); 6187a8a68f5SJulian Pullen if (results == NULL) 6197a8a68f5SJulian Pullen return (NULL); 6207a8a68f5SJulian Pullen 6217a8a68f5SJulian Pullen for (i = 0; subnets[i].subnet[0] != '\0'; i++) { 622*c5866007SKeyur Desai (void) asprintf(&results[i], "CN=%s,CN=Subnets,CN=Sites,%s", 623*c5866007SKeyur Desai subnets[i].subnet, base_dn); 624*c5866007SKeyur Desai if (results[i] == NULL) { 6257a8a68f5SJulian Pullen for (j = 0; j < i; j++) 6267a8a68f5SJulian Pullen free(results[j]); 6277a8a68f5SJulian Pullen free(results); 6287a8a68f5SJulian Pullen return (NULL); 6297a8a68f5SJulian Pullen } 6307a8a68f5SJulian Pullen } 6317a8a68f5SJulian Pullen 6327a8a68f5SJulian Pullen return (results); 6337a8a68f5SJulian Pullen } 6347a8a68f5SJulian Pullen 6357a8a68f5SJulian Pullen 6367a8a68f5SJulian Pullen /* Compare SRC RRs; used with qsort() */ 6377a8a68f5SJulian Pullen static int 6387a8a68f5SJulian Pullen srvcmp(idmap_ad_disc_ds_t *s1, idmap_ad_disc_ds_t *s2) 6397a8a68f5SJulian Pullen { 6407a8a68f5SJulian Pullen if (s1->priority < s2->priority) 6417a8a68f5SJulian Pullen return (1); 6427a8a68f5SJulian Pullen else if (s1->priority > s2->priority) 6437a8a68f5SJulian Pullen return (-1); 6447a8a68f5SJulian Pullen 6457a8a68f5SJulian Pullen if (s1->weight < s2->weight) 6467a8a68f5SJulian Pullen return (1); 6477a8a68f5SJulian Pullen else if (s1->weight > s2->weight) 6487a8a68f5SJulian Pullen return (-1); 6497a8a68f5SJulian Pullen 6507a8a68f5SJulian Pullen return (0); 6517a8a68f5SJulian Pullen } 6527a8a68f5SJulian Pullen 6537a8a68f5SJulian Pullen 6547a8a68f5SJulian Pullen /* 6557a8a68f5SJulian Pullen * Query or search the SRV RRs for a given name. 6567a8a68f5SJulian Pullen * 6577a8a68f5SJulian Pullen * If name == NULL then search (as in res_nsearch(3RESOLV), honoring any 6587a8a68f5SJulian Pullen * search list/option), else query (as in res_nquery(3RESOLV)). 6597a8a68f5SJulian Pullen * 6607a8a68f5SJulian Pullen * The output TTL will be the one of the SRV RR with the lowest TTL. 6617a8a68f5SJulian Pullen */ 6627a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 6637a8a68f5SJulian Pullen srv_query(res_state state, const char *svc_name, const char *dname, 6647a8a68f5SJulian Pullen char **rrname, uint32_t *ttl) 6657a8a68f5SJulian Pullen { 6667a8a68f5SJulian Pullen idmap_ad_disc_ds_t *srv; 667bbf6f00cSJordan Brown idmap_ad_disc_ds_t *srv_res = NULL; 6687a8a68f5SJulian Pullen union { 6697a8a68f5SJulian Pullen HEADER hdr; 6707a8a68f5SJulian Pullen uchar_t buf[NS_MAXMSG]; 6717a8a68f5SJulian Pullen } msg; 6727a8a68f5SJulian Pullen int len, cnt, qdcount, ancount; 6737a8a68f5SJulian Pullen uchar_t *ptr, *eom; 6747a8a68f5SJulian Pullen uchar_t *end; 6757a8a68f5SJulian Pullen uint16_t type; 6767a8a68f5SJulian Pullen /* LINTED E_FUNC_SET_NOT_USED */ 6777a8a68f5SJulian Pullen uint16_t class; 6787a8a68f5SJulian Pullen uint32_t rttl; 6797a8a68f5SJulian Pullen uint16_t size; 6807a8a68f5SJulian Pullen char namebuf[NS_MAXDNAME]; 6817a8a68f5SJulian Pullen 6827a8a68f5SJulian Pullen if (state == NULL) 6837a8a68f5SJulian Pullen return (NULL); 6847a8a68f5SJulian Pullen 6857a8a68f5SJulian Pullen /* Set negative result TTL */ 6867a8a68f5SJulian Pullen *ttl = 5 * 60; 6877a8a68f5SJulian Pullen 6887a8a68f5SJulian Pullen /* 1. query necessary resource records */ 6897a8a68f5SJulian Pullen 6907a8a68f5SJulian Pullen /* Search, querydomain or query */ 6917a8a68f5SJulian Pullen if (rrname != NULL) { 6927a8a68f5SJulian Pullen *rrname = NULL; 6937a8a68f5SJulian Pullen len = res_nsearch(state, svc_name, C_IN, T_SRV, 6947a8a68f5SJulian Pullen msg.buf, sizeof (msg.buf)); 6957a8a68f5SJulian Pullen logger(LOG_DEBUG, "Searching DNS for SRV RRs named '%s'", 6967a8a68f5SJulian Pullen svc_name); 6977a8a68f5SJulian Pullen if (len < 0) { 6987a8a68f5SJulian Pullen logger(LOG_DEBUG, "DNS search for '%s' failed (%s)", 6997a8a68f5SJulian Pullen svc_name, hstrerror(state->res_h_errno)); 7007a8a68f5SJulian Pullen return (NULL); 7017a8a68f5SJulian Pullen } 7027a8a68f5SJulian Pullen } else if (dname != NULL) { 7037a8a68f5SJulian Pullen logger(LOG_DEBUG, 7047a8a68f5SJulian Pullen "Querying DNS for SRV RRs named '%s' for '%s' ", 7057a8a68f5SJulian Pullen svc_name, dname); 7067a8a68f5SJulian Pullen 707e3f2c991SKeyur Desai len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV, 708e3f2c991SKeyur Desai msg.buf, sizeof (msg.buf)); 709e3f2c991SKeyur Desai 7107a8a68f5SJulian Pullen if (len < 0) { 7117a8a68f5SJulian Pullen logger(LOG_DEBUG, 7127a8a68f5SJulian Pullen "DNS query for '%s' for '%s' failed (%s)", 7137a8a68f5SJulian Pullen svc_name, dname, hstrerror(state->res_h_errno)); 7147a8a68f5SJulian Pullen return (NULL); 7157a8a68f5SJulian Pullen } 7167a8a68f5SJulian Pullen } 7177a8a68f5SJulian Pullen 7187a8a68f5SJulian Pullen if (len > sizeof (msg.buf)) { 7197a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query %ib message doesn't fit" 7207a8a68f5SJulian Pullen " into %ib buffer", 7217a8a68f5SJulian Pullen len, sizeof (msg.buf)); 7227a8a68f5SJulian Pullen return (NULL); 7237a8a68f5SJulian Pullen } 7247a8a68f5SJulian Pullen 7257a8a68f5SJulian Pullen /* 2. parse the reply, skip header and question sections */ 7267a8a68f5SJulian Pullen 7277a8a68f5SJulian Pullen ptr = msg.buf + sizeof (msg.hdr); 7287a8a68f5SJulian Pullen eom = msg.buf + len; 7297a8a68f5SJulian Pullen qdcount = ntohs(msg.hdr.qdcount); 7307a8a68f5SJulian Pullen ancount = ntohs(msg.hdr.ancount); 7317a8a68f5SJulian Pullen 7327a8a68f5SJulian Pullen for (cnt = qdcount; cnt > 0; --cnt) { 7337a8a68f5SJulian Pullen if ((len = dn_skipname(ptr, eom)) < 0) { 7347a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 7357a8a68f5SJulian Pullen return (NULL); 7367a8a68f5SJulian Pullen } 7377a8a68f5SJulian Pullen ptr += len + QFIXEDSZ; 7387a8a68f5SJulian Pullen } 7397a8a68f5SJulian Pullen 7407a8a68f5SJulian Pullen /* 3. walk through the answer section */ 7417a8a68f5SJulian Pullen 7427a8a68f5SJulian Pullen srv_res = calloc(ancount + 1, sizeof (idmap_ad_disc_ds_t)); 743bbf6f00cSJordan Brown if (srv_res == NULL) { 744bbf6f00cSJordan Brown logger(LOG_ERR, "Out of memory"); 745bbf6f00cSJordan Brown return (NULL); 746bbf6f00cSJordan Brown } 747bbf6f00cSJordan Brown 7487a8a68f5SJulian Pullen *ttl = (uint32_t)-1; 7497a8a68f5SJulian Pullen 7507a8a68f5SJulian Pullen for (srv = srv_res, cnt = ancount; 7517a8a68f5SJulian Pullen cnt > 0; --cnt, srv++) { 7527a8a68f5SJulian Pullen 7537a8a68f5SJulian Pullen len = dn_expand(msg.buf, eom, ptr, namebuf, 7547a8a68f5SJulian Pullen sizeof (namebuf)); 7557a8a68f5SJulian Pullen if (len < 0) { 7567a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 757bbf6f00cSJordan Brown goto err; 7587a8a68f5SJulian Pullen } 759bbf6f00cSJordan Brown if (rrname != NULL && *rrname == NULL) { 7607a8a68f5SJulian Pullen *rrname = strdup(namebuf); 761bbf6f00cSJordan Brown if (*rrname == NULL) { 762bbf6f00cSJordan Brown logger(LOG_ERR, "Out of memory"); 763bbf6f00cSJordan Brown goto err; 764bbf6f00cSJordan Brown } 765bbf6f00cSJordan Brown } 7667a8a68f5SJulian Pullen ptr += len; 7677a8a68f5SJulian Pullen NS_GET16(type, ptr); 7687a8a68f5SJulian Pullen NS_GET16(class, ptr); 7697a8a68f5SJulian Pullen NS_GET32(rttl, ptr); 7707a8a68f5SJulian Pullen NS_GET16(size, ptr); 7717a8a68f5SJulian Pullen if ((end = ptr + size) > eom) { 7727a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 773bbf6f00cSJordan Brown goto err; 7747a8a68f5SJulian Pullen } 7757a8a68f5SJulian Pullen 7767a8a68f5SJulian Pullen if (type != T_SRV) { 7777a8a68f5SJulian Pullen ptr = end; 7787a8a68f5SJulian Pullen continue; 7797a8a68f5SJulian Pullen } 7807a8a68f5SJulian Pullen 7817a8a68f5SJulian Pullen NS_GET16(srv->priority, ptr); 7827a8a68f5SJulian Pullen NS_GET16(srv->weight, ptr); 7837a8a68f5SJulian Pullen NS_GET16(srv->port, ptr); 7847a8a68f5SJulian Pullen len = dn_expand(msg.buf, eom, ptr, srv->host, 7857a8a68f5SJulian Pullen sizeof (srv->host)); 7867a8a68f5SJulian Pullen if (len < 0) { 7877a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid SRV record"); 788bbf6f00cSJordan Brown goto err; 7897a8a68f5SJulian Pullen } 7907a8a68f5SJulian Pullen 7917a8a68f5SJulian Pullen if (rttl < *ttl) 7927a8a68f5SJulian Pullen *ttl = rttl; 7937a8a68f5SJulian Pullen 7947a8a68f5SJulian Pullen logger(LOG_DEBUG, "Found %s %d IN SRV [%d][%d] %s:%d", 7957a8a68f5SJulian Pullen namebuf, rttl, srv->priority, srv->weight, srv->host, 7967a8a68f5SJulian Pullen srv->port); 7977a8a68f5SJulian Pullen 7987a8a68f5SJulian Pullen /* 3. move ptr to the end of current record */ 7997a8a68f5SJulian Pullen 8007a8a68f5SJulian Pullen ptr = end; 8017a8a68f5SJulian Pullen } 8027a8a68f5SJulian Pullen 8037a8a68f5SJulian Pullen if (ancount > 1) 8047a8a68f5SJulian Pullen qsort(srv_res, ancount, sizeof (*srv_res), 8057a8a68f5SJulian Pullen (int (*)(const void *, const void *))srvcmp); 8067a8a68f5SJulian Pullen 8077a8a68f5SJulian Pullen return (srv_res); 808bbf6f00cSJordan Brown 809bbf6f00cSJordan Brown err: 810bbf6f00cSJordan Brown free(srv_res); 811bbf6f00cSJordan Brown if (rrname != NULL) { 812bbf6f00cSJordan Brown free(*rrname); 813bbf6f00cSJordan Brown *rrname = NULL; 814bbf6f00cSJordan Brown } 815bbf6f00cSJordan Brown return (NULL); 8167a8a68f5SJulian Pullen } 8177a8a68f5SJulian Pullen 8187a8a68f5SJulian Pullen 8197a8a68f5SJulian Pullen /* 8207a8a68f5SJulian Pullen * A utility function to bind to a Directory server 8217a8a68f5SJulian Pullen */ 8227a8a68f5SJulian Pullen 823*c5866007SKeyur Desai static 824*c5866007SKeyur Desai LDAP * 8257a8a68f5SJulian Pullen ldap_lookup_init(idmap_ad_disc_ds_t *ds) 8267a8a68f5SJulian Pullen { 8277a8a68f5SJulian Pullen int i; 8287a8a68f5SJulian Pullen int rc, ldversion; 8297a8a68f5SJulian Pullen int zero = 0; 8307a8a68f5SJulian Pullen int timeoutms = 5 * 1000; 8317a8a68f5SJulian Pullen char *saslmech = "GSSAPI"; 8327a8a68f5SJulian Pullen uint32_t saslflags = LDAP_SASL_INTERACTIVE; 8337a8a68f5SJulian Pullen LDAP *ld = NULL; 8347a8a68f5SJulian Pullen 8357a8a68f5SJulian Pullen for (i = 0; ds[i].host[0] != '\0'; i++) { 8367a8a68f5SJulian Pullen ld = ldap_init(ds[i].host, ds[i].port); 8377a8a68f5SJulian Pullen if (ld == NULL) { 8387a8a68f5SJulian Pullen logger(LOG_DEBUG, "Couldn't connect to " 8397a8a68f5SJulian Pullen "AD DC %s:%d (%s)", 8407a8a68f5SJulian Pullen ds[i].host, ds[i].port, 8417a8a68f5SJulian Pullen strerror(errno)); 8427a8a68f5SJulian Pullen continue; 8437a8a68f5SJulian Pullen } 8447a8a68f5SJulian Pullen 8457a8a68f5SJulian Pullen ldversion = LDAP_VERSION3; 8467a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 8477a8a68f5SJulian Pullen &ldversion); 8487a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 8497a8a68f5SJulian Pullen LDAP_OPT_OFF); 8507a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 8517a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 8527a8a68f5SJulian Pullen /* setup TCP/IP connect timeout */ 8537a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 8547a8a68f5SJulian Pullen &timeoutms); 8557a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_RESTART, 8567a8a68f5SJulian Pullen LDAP_OPT_ON); 8577a8a68f5SJulian Pullen 858bd428526SJulian Pullen rc = adutils_set_thread_functions(ld); 859bd428526SJulian Pullen if (rc != LDAP_SUCCESS) { 860bd428526SJulian Pullen /* Error has already been logged */ 861bd428526SJulian Pullen (void) ldap_unbind(ld); 862bd428526SJulian Pullen ld = NULL; 863bd428526SJulian Pullen continue; 864bd428526SJulian Pullen } 865bd428526SJulian Pullen 8667a8a68f5SJulian Pullen rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 8677a8a68f5SJulian Pullen saslmech, NULL, NULL, saslflags, &saslcallback, 8687a8a68f5SJulian Pullen NULL /* defaults */); 8697a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) 8707a8a68f5SJulian Pullen break; 8717a8a68f5SJulian Pullen 8727a8a68f5SJulian Pullen logger(LOG_INFO, "LDAP SASL bind to %s:%d failed (%s)", 8737a8a68f5SJulian Pullen ds[i].host, ds[i].port, ldap_err2string(rc)); 8747a8a68f5SJulian Pullen (void) ldap_unbind(ld); 8757a8a68f5SJulian Pullen ld = NULL; 8767a8a68f5SJulian Pullen } 8777a8a68f5SJulian Pullen return (ld); 8787a8a68f5SJulian Pullen } 8797a8a68f5SJulian Pullen 8807a8a68f5SJulian Pullen 8817a8a68f5SJulian Pullen 8827a8a68f5SJulian Pullen /* 8837a8a68f5SJulian Pullen * A utility function to get the value of some attribute of one of one 8847a8a68f5SJulian Pullen * or more AD LDAP objects named by the dn_list; first found one wins. 8857a8a68f5SJulian Pullen */ 8867a8a68f5SJulian Pullen static char * 8877a8a68f5SJulian Pullen ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, 8887a8a68f5SJulian Pullen char **dn_list, char *attr) 8897a8a68f5SJulian Pullen { 8907a8a68f5SJulian Pullen int i; 8917a8a68f5SJulian Pullen int rc; 8927a8a68f5SJulian Pullen int scope = LDAP_SCOPE_BASE; 8937a8a68f5SJulian Pullen char *attrs[2]; 8947a8a68f5SJulian Pullen LDAPMessage *results = NULL; 8957a8a68f5SJulian Pullen LDAPMessage *entry; 8967a8a68f5SJulian Pullen char **values = NULL; 8977a8a68f5SJulian Pullen char *val = NULL; 8987a8a68f5SJulian Pullen 8997a8a68f5SJulian Pullen attrs[0] = attr; 9007a8a68f5SJulian Pullen attrs[1] = NULL; 9017a8a68f5SJulian Pullen 9027a8a68f5SJulian Pullen if (*ld == NULL) 9037a8a68f5SJulian Pullen *ld = ldap_lookup_init(domainControllers); 9047a8a68f5SJulian Pullen 9057a8a68f5SJulian Pullen if (*ld == NULL) 9067a8a68f5SJulian Pullen return (NULL); 9077a8a68f5SJulian Pullen 9087a8a68f5SJulian Pullen for (i = 0; dn_list[i] != NULL; i++) { 9097a8a68f5SJulian Pullen rc = ldap_search_s(*ld, dn_list[i], scope, 9107a8a68f5SJulian Pullen "(objectclass=*)", attrs, 0, &results); 9117a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 9127a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 9137a8a68f5SJulian Pullen entry != NULL && values == NULL; 9147a8a68f5SJulian Pullen entry = ldap_next_entry(*ld, entry)) { 9157a8a68f5SJulian Pullen values = ldap_get_values( 9167a8a68f5SJulian Pullen *ld, entry, attr); 9177a8a68f5SJulian Pullen } 9187a8a68f5SJulian Pullen 9197a8a68f5SJulian Pullen if (values != NULL) { 9207a8a68f5SJulian Pullen (void) ldap_msgfree(results); 9217a8a68f5SJulian Pullen val = strdup(values[0]); 9227a8a68f5SJulian Pullen ldap_value_free(values); 9237a8a68f5SJulian Pullen return (val); 9247a8a68f5SJulian Pullen } 9257a8a68f5SJulian Pullen } 9267a8a68f5SJulian Pullen if (results != NULL) { 9277a8a68f5SJulian Pullen (void) ldap_msgfree(results); 9287a8a68f5SJulian Pullen results = NULL; 9297a8a68f5SJulian Pullen } 9307a8a68f5SJulian Pullen } 9317a8a68f5SJulian Pullen 9327a8a68f5SJulian Pullen return (NULL); 9337a8a68f5SJulian Pullen } 9347a8a68f5SJulian Pullen 9357a8a68f5SJulian Pullen 9367a8a68f5SJulian Pullen /* 9377a8a68f5SJulian Pullen * Lookup the trusted domains in the global catalog. 9387a8a68f5SJulian Pullen * 9397a8a68f5SJulian Pullen * Returns: 9407a8a68f5SJulian Pullen * array of trusted domains which is terminated by 9417a8a68f5SJulian Pullen * an empty trusted domain. 9427a8a68f5SJulian Pullen * NULL an error occured 9437a8a68f5SJulian Pullen */ 9447a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 9457a8a68f5SJulian Pullen ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, 9467a8a68f5SJulian Pullen char *base_dn) 9477a8a68f5SJulian Pullen { 9487a8a68f5SJulian Pullen int scope = LDAP_SCOPE_SUBTREE; 9497a8a68f5SJulian Pullen char *attrs[3]; 9507a8a68f5SJulian Pullen int rc; 9517a8a68f5SJulian Pullen LDAPMessage *results = NULL; 9527a8a68f5SJulian Pullen LDAPMessage *entry; 9537a8a68f5SJulian Pullen char *filter; 9547a8a68f5SJulian Pullen char **partner = NULL; 9557a8a68f5SJulian Pullen char **direction = NULL; 9567a8a68f5SJulian Pullen int num = 0; 9577a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 9587a8a68f5SJulian Pullen 9597a8a68f5SJulian Pullen 9607a8a68f5SJulian Pullen if (*ld == NULL) 9617a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalog); 9627a8a68f5SJulian Pullen 9637a8a68f5SJulian Pullen if (*ld == NULL) 9647a8a68f5SJulian Pullen return (NULL); 9657a8a68f5SJulian Pullen 9667a8a68f5SJulian Pullen attrs[0] = "trustPartner"; 9677a8a68f5SJulian Pullen attrs[1] = "trustDirection"; 9687a8a68f5SJulian Pullen attrs[2] = NULL; 9697a8a68f5SJulian Pullen 9707a8a68f5SJulian Pullen /* trustDirection values - inbound = 1 and bidirectional = 3 */ 9717a8a68f5SJulian Pullen filter = "(&(objectclass=trustedDomain)" 9727a8a68f5SJulian Pullen "(|(trustDirection=3)(trustDirection=1)))"; 9737a8a68f5SJulian Pullen 9747a8a68f5SJulian Pullen rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); 9757a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 9767a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 9777a8a68f5SJulian Pullen entry != NULL; entry = ldap_next_entry(*ld, entry)) { 9787a8a68f5SJulian Pullen partner = ldap_get_values(*ld, entry, "trustPartner"); 9797a8a68f5SJulian Pullen direction = ldap_get_values( 9807a8a68f5SJulian Pullen *ld, entry, "trustDirection"); 9817a8a68f5SJulian Pullen 9827a8a68f5SJulian Pullen if (partner != NULL && direction != NULL) { 9837a8a68f5SJulian Pullen num++; 984*c5866007SKeyur Desai void *tmp = realloc(trusted_domains, 9857a8a68f5SJulian Pullen (num + 1) * 9867a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 987*c5866007SKeyur Desai if (tmp == NULL) { 988*c5866007SKeyur Desai free(trusted_domains); 9897a8a68f5SJulian Pullen ldap_value_free(partner); 9907a8a68f5SJulian Pullen ldap_value_free(direction); 9917a8a68f5SJulian Pullen ldap_msgfree(results); 9927a8a68f5SJulian Pullen return (NULL); 9937a8a68f5SJulian Pullen } 994*c5866007SKeyur Desai trusted_domains = tmp; 9957a8a68f5SJulian Pullen /* Last element should be zero */ 9967a8a68f5SJulian Pullen memset(&trusted_domains[num], 0, 9977a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 9987a8a68f5SJulian Pullen strcpy(trusted_domains[num - 1].domain, 9997a8a68f5SJulian Pullen partner[0]); 10007a8a68f5SJulian Pullen trusted_domains[num - 1].direction = 10017a8a68f5SJulian Pullen atoi(direction[0]); 10027a8a68f5SJulian Pullen } 10037a8a68f5SJulian Pullen if (partner != NULL) 10047a8a68f5SJulian Pullen ldap_value_free(partner); 10057a8a68f5SJulian Pullen if (direction != NULL) 10067a8a68f5SJulian Pullen ldap_value_free(direction); 10077a8a68f5SJulian Pullen } 10087a8a68f5SJulian Pullen } else if (rc == LDAP_NO_RESULTS_RETURNED) { 10097a8a68f5SJulian Pullen /* This is not an error - return empty trusted domain */ 10107a8a68f5SJulian Pullen trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 10117a8a68f5SJulian Pullen } 10127a8a68f5SJulian Pullen if (results != NULL) 10137a8a68f5SJulian Pullen ldap_msgfree(results); 10147a8a68f5SJulian Pullen 10157a8a68f5SJulian Pullen return (trusted_domains); 10167a8a68f5SJulian Pullen } 10177a8a68f5SJulian Pullen 10187a8a68f5SJulian Pullen 10197a8a68f5SJulian Pullen /* 10207a8a68f5SJulian Pullen * This functions finds all the domains in a forest. 10217a8a68f5SJulian Pullen */ 10227a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 10237a8a68f5SJulian Pullen ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) 10247a8a68f5SJulian Pullen { 1025928e1f97SJordan Brown static char *attrs[] = { 1026928e1f97SJordan Brown "objectSid", 1027928e1f97SJordan Brown NULL, 1028928e1f97SJordan Brown }; 10297a8a68f5SJulian Pullen int rc; 10307a8a68f5SJulian Pullen LDAPMessage *result = NULL; 10317a8a68f5SJulian Pullen LDAPMessage *entry; 1032928e1f97SJordan Brown int ndomains = 0; 1033928e1f97SJordan Brown int nresults; 10347a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains = NULL; 10357a8a68f5SJulian Pullen 10367a8a68f5SJulian Pullen if (*ld == NULL) 10377a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalogs); 10387a8a68f5SJulian Pullen 10397a8a68f5SJulian Pullen if (*ld == NULL) 10407a8a68f5SJulian Pullen return (NULL); 10417a8a68f5SJulian Pullen 1042928e1f97SJordan Brown logger(LOG_DEBUG, "Looking for domains in forest..."); 10437a8a68f5SJulian Pullen /* Find domains */ 1044928e1f97SJordan Brown rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, 1045928e1f97SJordan Brown "(objectClass=Domain)", attrs, 0, &result); 1046928e1f97SJordan Brown if (rc != LDAP_SUCCESS) 1047928e1f97SJordan Brown goto err; 1048928e1f97SJordan Brown 1049928e1f97SJordan Brown nresults = ldap_count_entries(*ld, result); 1050928e1f97SJordan Brown domains = calloc(nresults + 1, sizeof (*domains)); 1051928e1f97SJordan Brown if (domains == NULL) 1052928e1f97SJordan Brown goto err; 1053928e1f97SJordan Brown 1054928e1f97SJordan Brown for (entry = ldap_first_entry(*ld, result); 1055928e1f97SJordan Brown entry != NULL; 1056928e1f97SJordan Brown entry = ldap_next_entry(*ld, entry)) { 1057928e1f97SJordan Brown struct berval **sid_ber; 1058928e1f97SJordan Brown adutils_sid_t sid; 1059928e1f97SJordan Brown char *sid_str; 1060928e1f97SJordan Brown char *name; 1061bbf6f00cSJordan Brown char *dn; 1062928e1f97SJordan Brown 10637a8a68f5SJulian Pullen sid_ber = ldap_get_values_len(*ld, entry, 10647a8a68f5SJulian Pullen "objectSid"); 1065928e1f97SJordan Brown if (sid_ber == NULL) 1066928e1f97SJordan Brown continue; 10677a8a68f5SJulian Pullen 1068928e1f97SJordan Brown rc = adutils_getsid(sid_ber[0], &sid); 10697a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 1070928e1f97SJordan Brown if (rc < 0) 1071928e1f97SJordan Brown goto err; 10727a8a68f5SJulian Pullen 1073928e1f97SJordan Brown if ((sid_str = adutils_sid2txt(&sid)) == NULL) 1074928e1f97SJordan Brown goto err; 1075928e1f97SJordan Brown 1076928e1f97SJordan Brown strcpy(domains[ndomains].sid, sid_str); 10777a8a68f5SJulian Pullen free(sid_str); 10787a8a68f5SJulian Pullen 1079bbf6f00cSJordan Brown dn = ldap_get_dn(*ld, entry); 1080bbf6f00cSJordan Brown name = DN_to_DNS(dn); 1081bbf6f00cSJordan Brown free(dn); 1082928e1f97SJordan Brown if (name == NULL) 1083928e1f97SJordan Brown goto err; 1084928e1f97SJordan Brown 1085928e1f97SJordan Brown strcpy(domains[ndomains].domain, name); 10867a8a68f5SJulian Pullen free(name); 1087928e1f97SJordan Brown 1088928e1f97SJordan Brown logger(LOG_DEBUG, " found %s", domains[ndomains].domain); 1089928e1f97SJordan Brown 1090928e1f97SJordan Brown ndomains++; 10917a8a68f5SJulian Pullen } 1092928e1f97SJordan Brown 1093928e1f97SJordan Brown if (ndomains == 0) 1094928e1f97SJordan Brown goto err; 1095928e1f97SJordan Brown 1096928e1f97SJordan Brown if (ndomains < nresults) { 1097928e1f97SJordan Brown ad_disc_domainsinforest_t *tmp; 1098928e1f97SJordan Brown tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); 1099928e1f97SJordan Brown if (tmp == NULL) 1100928e1f97SJordan Brown goto err; 1101928e1f97SJordan Brown domains = tmp; 11027a8a68f5SJulian Pullen } 1103928e1f97SJordan Brown 11047a8a68f5SJulian Pullen if (result != NULL) 11057a8a68f5SJulian Pullen ldap_msgfree(result); 11067a8a68f5SJulian Pullen 11077a8a68f5SJulian Pullen return (domains); 1108928e1f97SJordan Brown 1109928e1f97SJordan Brown err: 1110928e1f97SJordan Brown free(domains); 1111928e1f97SJordan Brown if (result != NULL) 1112928e1f97SJordan Brown ldap_msgfree(result); 1113928e1f97SJordan Brown return (NULL); 11147a8a68f5SJulian Pullen } 11157a8a68f5SJulian Pullen 11167a8a68f5SJulian Pullen 11177a8a68f5SJulian Pullen ad_disc_t 11187a8a68f5SJulian Pullen ad_disc_init(void) 11197a8a68f5SJulian Pullen { 11207a8a68f5SJulian Pullen struct ad_disc *ctx; 11217a8a68f5SJulian Pullen ctx = calloc(1, sizeof (struct ad_disc)); 11227a8a68f5SJulian Pullen if (ctx != NULL) 11237a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 11247a8a68f5SJulian Pullen 11257a8a68f5SJulian Pullen ctx->domain_name.type = AD_STRING; 11267a8a68f5SJulian Pullen ctx->domain_controller.type = AD_DIRECTORY; 11277a8a68f5SJulian Pullen ctx->site_name.type = AD_STRING; 11287a8a68f5SJulian Pullen ctx->forest_name.type = AD_STRING; 11297a8a68f5SJulian Pullen ctx->global_catalog.type = AD_DIRECTORY; 11307a8a68f5SJulian Pullen ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 11317a8a68f5SJulian Pullen ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 11327a8a68f5SJulian Pullen /* Site specific versions */ 11337a8a68f5SJulian Pullen ctx->site_domain_controller.type = AD_DIRECTORY; 11347a8a68f5SJulian Pullen ctx->site_global_catalog.type = AD_DIRECTORY; 11357a8a68f5SJulian Pullen return (ctx); 11367a8a68f5SJulian Pullen } 11377a8a68f5SJulian Pullen 11387a8a68f5SJulian Pullen 11397a8a68f5SJulian Pullen void 11407a8a68f5SJulian Pullen ad_disc_fini(ad_disc_t ctx) 11417a8a68f5SJulian Pullen { 11427a8a68f5SJulian Pullen if (ctx == NULL) 11437a8a68f5SJulian Pullen return; 11447a8a68f5SJulian Pullen 11457a8a68f5SJulian Pullen if (ctx->res_ninitted) 11467a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 11477a8a68f5SJulian Pullen 11487a8a68f5SJulian Pullen if (ctx->subnets != NULL) 11497a8a68f5SJulian Pullen free(ctx->subnets); 11507a8a68f5SJulian Pullen 11517a8a68f5SJulian Pullen if (ctx->domain_name.value != NULL) 11527a8a68f5SJulian Pullen free(ctx->domain_name.value); 11537a8a68f5SJulian Pullen 11547a8a68f5SJulian Pullen if (ctx->domain_controller.value != NULL) 11557a8a68f5SJulian Pullen free(ctx->domain_controller.value); 11567a8a68f5SJulian Pullen 11577a8a68f5SJulian Pullen if (ctx->site_name.value != NULL) 11587a8a68f5SJulian Pullen free(ctx->site_name.value); 11597a8a68f5SJulian Pullen 11607a8a68f5SJulian Pullen if (ctx->forest_name.value != NULL) 11617a8a68f5SJulian Pullen free(ctx->forest_name.value); 11627a8a68f5SJulian Pullen 11637a8a68f5SJulian Pullen if (ctx->global_catalog.value != NULL) 11647a8a68f5SJulian Pullen free(ctx->global_catalog.value); 11657a8a68f5SJulian Pullen 11667a8a68f5SJulian Pullen if (ctx->domains_in_forest.value != NULL) 11677a8a68f5SJulian Pullen free(ctx->domains_in_forest.value); 11687a8a68f5SJulian Pullen 11697a8a68f5SJulian Pullen if (ctx->trusted_domains.value != NULL) 11707a8a68f5SJulian Pullen free(ctx->trusted_domains.value); 11717a8a68f5SJulian Pullen 11727a8a68f5SJulian Pullen /* Site specific versions */ 11737a8a68f5SJulian Pullen if (ctx->site_domain_controller.value != NULL) 11747a8a68f5SJulian Pullen free(ctx->site_domain_controller.value); 11757a8a68f5SJulian Pullen 11767a8a68f5SJulian Pullen if (ctx->site_global_catalog.value != NULL) 11777a8a68f5SJulian Pullen free(ctx->site_global_catalog.value); 11787a8a68f5SJulian Pullen 11797a8a68f5SJulian Pullen free(ctx); 11807a8a68f5SJulian Pullen } 11817a8a68f5SJulian Pullen 11827a8a68f5SJulian Pullen void 11837a8a68f5SJulian Pullen ad_disc_refresh(ad_disc_t ctx) 11847a8a68f5SJulian Pullen { 11857a8a68f5SJulian Pullen if (ctx->res_ninitted) 11867a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 11877a8a68f5SJulian Pullen (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 11887a8a68f5SJulian Pullen ctx->res_ninitted = res_ninit(&ctx->res_state) != -1; 11897a8a68f5SJulian Pullen 11907a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_AUTO) 11917a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 11927a8a68f5SJulian Pullen 11937a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_AUTO) 11947a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 11957a8a68f5SJulian Pullen 11967a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_AUTO) 11977a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 11987a8a68f5SJulian Pullen 11997a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_AUTO) 12007a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 12017a8a68f5SJulian Pullen 12027a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_AUTO) 12037a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 12047a8a68f5SJulian Pullen 12057a8a68f5SJulian Pullen if (ctx->domains_in_forest.state == AD_STATE_AUTO) 12067a8a68f5SJulian Pullen ctx->domains_in_forest.state = AD_STATE_INVALID; 12077a8a68f5SJulian Pullen 12087a8a68f5SJulian Pullen if (ctx->trusted_domains.state == AD_STATE_AUTO) 12097a8a68f5SJulian Pullen ctx->trusted_domains.state = AD_STATE_INVALID; 12107a8a68f5SJulian Pullen 12117a8a68f5SJulian Pullen if (ctx->site_domain_controller.state == AD_STATE_AUTO) 12127a8a68f5SJulian Pullen ctx->site_domain_controller.state = AD_STATE_INVALID; 12137a8a68f5SJulian Pullen 12147a8a68f5SJulian Pullen if (ctx->site_global_catalog.state == AD_STATE_AUTO) 12157a8a68f5SJulian Pullen ctx->site_global_catalog.state = AD_STATE_INVALID; 12167a8a68f5SJulian Pullen } 12177a8a68f5SJulian Pullen 12187a8a68f5SJulian Pullen 1219*c5866007SKeyur Desai /* 1220*c5866007SKeyur Desai * Called when the discovery cycle is done. Sets a master TTL 1221*c5866007SKeyur Desai * that will avoid doing new time-based discoveries too soon after 1222*c5866007SKeyur Desai * the last discovery cycle. Most interesting when the discovery 1223*c5866007SKeyur Desai * cycle failed, because then the TTLs on the individual items will 1224*c5866007SKeyur Desai * not be updated and may go stale. 1225*c5866007SKeyur Desai */ 1226*c5866007SKeyur Desai void 1227*c5866007SKeyur Desai ad_disc_done(ad_disc_t ctx) 1228*c5866007SKeyur Desai { 1229*c5866007SKeyur Desai time_t now = time(NULL); 1230*c5866007SKeyur Desai 1231*c5866007SKeyur Desai ctx->expires_not_before = now + MINIMUM_TTL; 1232*c5866007SKeyur Desai ctx->expires_not_after = now + MAXIMUM_TTL; 1233*c5866007SKeyur Desai } 1234*c5866007SKeyur Desai 12357a8a68f5SJulian Pullen 12367a8a68f5SJulian Pullen /* Discover joined Active Directory domainName */ 12377a8a68f5SJulian Pullen static ad_item_t * 12387a8a68f5SJulian Pullen validate_DomainName(ad_disc_t ctx) 12397a8a68f5SJulian Pullen { 12407a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 12417a8a68f5SJulian Pullen char *dname, *srvname; 12427a8a68f5SJulian Pullen uint32_t ttl = 0; 1243928e1f97SJordan Brown int len; 12447a8a68f5SJulian Pullen 12457a8a68f5SJulian Pullen if (is_valid(&ctx->domain_name)) 12467a8a68f5SJulian Pullen return (&ctx->domain_name); 12477a8a68f5SJulian Pullen 12487a8a68f5SJulian Pullen 12497a8a68f5SJulian Pullen /* Try to find our domain by searching for DCs for it */ 12507a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 12517a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, LDAP_SRV_HEAD 12527a8a68f5SJulian Pullen DC_SRV_TAIL, ctx->domain_name.value, &srvname, &ttl); 12537a8a68f5SJulian Pullen 12547a8a68f5SJulian Pullen /* 12557a8a68f5SJulian Pullen * If we can't find DCs by via res_nsearch() then there's no 12567a8a68f5SJulian Pullen * point in trying anything else to discover the AD domain name. 12577a8a68f5SJulian Pullen */ 12587a8a68f5SJulian Pullen if (domain_controller == NULL) 12597a8a68f5SJulian Pullen return (NULL); 12607a8a68f5SJulian Pullen 12617a8a68f5SJulian Pullen free(domain_controller); 12627a8a68f5SJulian Pullen /* 12637a8a68f5SJulian Pullen * We have the FQDN of the SRV RR name, so now we extract the 12647a8a68f5SJulian Pullen * domainname suffix from it. 12657a8a68f5SJulian Pullen */ 12667a8a68f5SJulian Pullen dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 12677a8a68f5SJulian Pullen 1 /* for the dot between RR name and domainname */); 12687a8a68f5SJulian Pullen 12697a8a68f5SJulian Pullen free(srvname); 12707a8a68f5SJulian Pullen 12717a8a68f5SJulian Pullen if (dname == NULL) { 12727a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 12737a8a68f5SJulian Pullen return (NULL); 12747a8a68f5SJulian Pullen } 12757a8a68f5SJulian Pullen 12767a8a68f5SJulian Pullen /* Eat any trailing dot */ 1277928e1f97SJordan Brown len = strlen(dname); 1278928e1f97SJordan Brown if (len > 0 && dname[len - 1] == '.') 1279928e1f97SJordan Brown dname[len - 1] = '\0'; 12807a8a68f5SJulian Pullen 12817a8a68f5SJulian Pullen update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl); 12827a8a68f5SJulian Pullen 12837a8a68f5SJulian Pullen return (&ctx->domain_name); 12847a8a68f5SJulian Pullen } 12857a8a68f5SJulian Pullen 12867a8a68f5SJulian Pullen 12877a8a68f5SJulian Pullen char * 12887a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 12897a8a68f5SJulian Pullen { 12907a8a68f5SJulian Pullen char *domain_name = NULL; 12917a8a68f5SJulian Pullen ad_item_t *domain_name_item; 12927a8a68f5SJulian Pullen 12937a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 12947a8a68f5SJulian Pullen 12957a8a68f5SJulian Pullen if (domain_name_item) { 12967a8a68f5SJulian Pullen domain_name = strdup(domain_name_item->value); 12977a8a68f5SJulian Pullen if (auto_discovered != NULL) 12987a8a68f5SJulian Pullen *auto_discovered = 12997a8a68f5SJulian Pullen (domain_name_item->state == AD_STATE_AUTO); 13007a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 13017a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 13027a8a68f5SJulian Pullen 13037a8a68f5SJulian Pullen return (domain_name); 13047a8a68f5SJulian Pullen } 13057a8a68f5SJulian Pullen 13067a8a68f5SJulian Pullen 13077a8a68f5SJulian Pullen /* Discover domain controllers */ 13087a8a68f5SJulian Pullen static ad_item_t * 13097a8a68f5SJulian Pullen validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 13107a8a68f5SJulian Pullen { 13117a8a68f5SJulian Pullen uint32_t ttl = 0; 13127a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 13137a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 13147a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 13157a8a68f5SJulian Pullen ad_item_t *domain_name_item; 13167a8a68f5SJulian Pullen ad_item_t *site_name_item = NULL; 13177a8a68f5SJulian Pullen 13187a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 13197a8a68f5SJulian Pullen if (is_fixed(&ctx->domain_controller)) 13207a8a68f5SJulian Pullen return (&ctx->domain_controller); 13217a8a68f5SJulian Pullen 13227a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 13237a8a68f5SJulian Pullen if (domain_name_item == NULL) 13247a8a68f5SJulian Pullen return (NULL); 13257a8a68f5SJulian Pullen 13267a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 13277a8a68f5SJulian Pullen validate_global = B_TRUE; 13287a8a68f5SJulian Pullen else { 13297a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 13307a8a68f5SJulian Pullen if (site_name_item != NULL) 13317a8a68f5SJulian Pullen validate_site = B_TRUE; 13327a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 13337a8a68f5SJulian Pullen validate_global = B_TRUE; 13347a8a68f5SJulian Pullen } 13357a8a68f5SJulian Pullen 13367a8a68f5SJulian Pullen if (validate_global) { 13377a8a68f5SJulian Pullen if (!is_valid(&ctx->domain_controller) || 13387a8a68f5SJulian Pullen is_changed(&ctx->domain_controller, PARAM1, 13397a8a68f5SJulian Pullen domain_name_item)) { 13407a8a68f5SJulian Pullen /* 13417a8a68f5SJulian Pullen * Lookup DNS SRV RR named 13427a8a68f5SJulian Pullen * _ldap._tcp.dc._msdcs.<DomainName> 13437a8a68f5SJulian Pullen */ 13447a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 13457a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, 13467a8a68f5SJulian Pullen LDAP_SRV_HEAD DC_SRV_TAIL, 13477a8a68f5SJulian Pullen domain_name_item->value, NULL, &ttl); 13487a8a68f5SJulian Pullen 13497a8a68f5SJulian Pullen if (domain_controller == NULL) 13507a8a68f5SJulian Pullen return (NULL); 13517a8a68f5SJulian Pullen 13527a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 13537a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 13547a8a68f5SJulian Pullen update_version(&ctx->domain_controller, PARAM1, 13557a8a68f5SJulian Pullen domain_name_item); 13567a8a68f5SJulian Pullen } 13577a8a68f5SJulian Pullen return (&ctx->domain_controller); 13587a8a68f5SJulian Pullen } 13597a8a68f5SJulian Pullen 13607a8a68f5SJulian Pullen if (validate_site) { 13617a8a68f5SJulian Pullen if (!is_valid(&ctx->site_domain_controller) || 13627a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM1, 13637a8a68f5SJulian Pullen domain_name_item) || 13647a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM2, 13657a8a68f5SJulian Pullen site_name_item)) { 13667a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 13677a8a68f5SJulian Pullen /* 13687a8a68f5SJulian Pullen * Lookup DNS SRV RR named 13697a8a68f5SJulian Pullen * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 13707a8a68f5SJulian Pullen */ 13717a8a68f5SJulian Pullen (void) snprintf(rr_name, sizeof (rr_name), 13727a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 13737a8a68f5SJulian Pullen site_name_item->value); 13747a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 13757a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, rr_name, 13767a8a68f5SJulian Pullen domain_name_item->value, NULL, &ttl); 13777a8a68f5SJulian Pullen if (domain_controller == NULL) 13787a8a68f5SJulian Pullen return (NULL); 13797a8a68f5SJulian Pullen 13807a8a68f5SJulian Pullen update_item(&ctx->site_domain_controller, 13817a8a68f5SJulian Pullen domain_controller, AD_STATE_AUTO, ttl); 13827a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM1, 13837a8a68f5SJulian Pullen domain_name_item); 13847a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM2, 13857a8a68f5SJulian Pullen site_name_item); 13867a8a68f5SJulian Pullen } 13877a8a68f5SJulian Pullen return (&ctx->site_domain_controller); 13887a8a68f5SJulian Pullen } 13897a8a68f5SJulian Pullen return (NULL); 13907a8a68f5SJulian Pullen } 13917a8a68f5SJulian Pullen 13927a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 13937a8a68f5SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 13947a8a68f5SJulian Pullen boolean_t *auto_discovered) 13957a8a68f5SJulian Pullen { 13967a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 13977a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 13987a8a68f5SJulian Pullen 13997a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, req); 14007a8a68f5SJulian Pullen 14017a8a68f5SJulian Pullen if (domain_controller_item != NULL) { 14027a8a68f5SJulian Pullen domain_controller = ds_dup(domain_controller_item->value); 14037a8a68f5SJulian Pullen if (auto_discovered != NULL) 14047a8a68f5SJulian Pullen *auto_discovered = 14057a8a68f5SJulian Pullen (domain_controller_item->state == AD_STATE_AUTO); 14067a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 14077a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 14087a8a68f5SJulian Pullen 14097a8a68f5SJulian Pullen return (domain_controller); 14107a8a68f5SJulian Pullen } 14117a8a68f5SJulian Pullen 14127a8a68f5SJulian Pullen 14137a8a68f5SJulian Pullen /* Discover site name (for multi-homed systems the first one found wins) */ 14147a8a68f5SJulian Pullen static ad_item_t * 14157a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx) 14167a8a68f5SJulian Pullen { 14177a8a68f5SJulian Pullen LDAP *ld = NULL; 14187a8a68f5SJulian Pullen ad_subnet_t *subnets = NULL; 14197a8a68f5SJulian Pullen char **dn_subnets = NULL; 14207a8a68f5SJulian Pullen char *dn_root[2]; 14217a8a68f5SJulian Pullen char *config_naming_context = NULL; 14227a8a68f5SJulian Pullen char *site_object = NULL; 14237a8a68f5SJulian Pullen char *site_name = NULL; 14247a8a68f5SJulian Pullen char *forest_name; 14257a8a68f5SJulian Pullen int len; 14267a8a68f5SJulian Pullen int i; 14277a8a68f5SJulian Pullen boolean_t update_required = B_FALSE; 14287a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 14297a8a68f5SJulian Pullen 14307a8a68f5SJulian Pullen if (is_fixed(&ctx->site_name)) 14317a8a68f5SJulian Pullen return (&ctx->site_name); 14327a8a68f5SJulian Pullen 14337a8a68f5SJulian Pullen /* Can't rely on site-specific DCs */ 14347a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 14357a8a68f5SJulian Pullen if (domain_controller_item == NULL) 14367a8a68f5SJulian Pullen return (NULL); 14377a8a68f5SJulian Pullen 14387a8a68f5SJulian Pullen if (!is_valid(&ctx->site_name) || 1439*c5866007SKeyur Desai is_changed(&ctx->site_name, PARAM1, domain_controller_item) || 14407a8a68f5SJulian Pullen ctx->subnets == NULL || ctx->subnets_changed) { 14417a8a68f5SJulian Pullen subnets = find_subnets(); 14427a8a68f5SJulian Pullen ctx->subnets_last_check = time(NULL); 14437a8a68f5SJulian Pullen update_required = B_TRUE; 14447a8a68f5SJulian Pullen } else if (ctx->subnets_last_check + 60 < time(NULL)) { 1445*c5866007SKeyur Desai /* NEEDSWORK magic constant 60 above */ 14467a8a68f5SJulian Pullen subnets = find_subnets(); 14477a8a68f5SJulian Pullen ctx->subnets_last_check = time(NULL); 14487a8a68f5SJulian Pullen if (cmpsubnets(ctx->subnets, subnets) != 0) 14497a8a68f5SJulian Pullen update_required = B_TRUE; 14507a8a68f5SJulian Pullen } 14517a8a68f5SJulian Pullen 14527a8a68f5SJulian Pullen if (!update_required) { 14537a8a68f5SJulian Pullen free(subnets); 14547a8a68f5SJulian Pullen return (&ctx->site_name); 14557a8a68f5SJulian Pullen } 14567a8a68f5SJulian Pullen 14577a8a68f5SJulian Pullen if (subnets == NULL) 14587a8a68f5SJulian Pullen return (NULL); 14597a8a68f5SJulian Pullen 14607a8a68f5SJulian Pullen dn_root[0] = ""; 14617a8a68f5SJulian Pullen dn_root[1] = NULL; 14627a8a68f5SJulian Pullen 14637a8a68f5SJulian Pullen config_naming_context = ldap_lookup_entry_attr( 14647a8a68f5SJulian Pullen &ld, ctx->domain_controller.value, 14657a8a68f5SJulian Pullen dn_root, "configurationNamingContext"); 14667a8a68f5SJulian Pullen if (config_naming_context == NULL) 14677a8a68f5SJulian Pullen goto out; 14687a8a68f5SJulian Pullen /* 14697a8a68f5SJulian Pullen * configurationNamingContext also provides the Forest 14707a8a68f5SJulian Pullen * Name. 14717a8a68f5SJulian Pullen */ 14727a8a68f5SJulian Pullen if (!is_fixed(&ctx->forest_name)) { 14737a8a68f5SJulian Pullen /* 14747a8a68f5SJulian Pullen * The configurationNamingContext should be of 14757a8a68f5SJulian Pullen * form: 14767a8a68f5SJulian Pullen * CN=Configuration,<DNforestName> 14777a8a68f5SJulian Pullen * Remove the first part and convert to DNS form 14787a8a68f5SJulian Pullen * (replace ",DC=" with ".") 14797a8a68f5SJulian Pullen */ 14807a8a68f5SJulian Pullen char *str = "CN=Configuration,"; 14817a8a68f5SJulian Pullen int len = strlen(str); 14827a8a68f5SJulian Pullen if (strncasecmp(config_naming_context, str, len) == 0) { 14837a8a68f5SJulian Pullen forest_name = DN_to_DNS(config_naming_context + len); 14847a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 14857a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1486*c5866007SKeyur Desai update_version(&ctx->forest_name, PARAM1, 1487*c5866007SKeyur Desai domain_controller_item); 14887a8a68f5SJulian Pullen } 14897a8a68f5SJulian Pullen } 14907a8a68f5SJulian Pullen 14917a8a68f5SJulian Pullen dn_subnets = subnets_to_DNs(subnets, config_naming_context); 14927a8a68f5SJulian Pullen if (dn_subnets == NULL) 14937a8a68f5SJulian Pullen goto out; 14947a8a68f5SJulian Pullen 14957a8a68f5SJulian Pullen site_object = ldap_lookup_entry_attr( 14967a8a68f5SJulian Pullen &ld, domain_controller_item->value, 14977a8a68f5SJulian Pullen dn_subnets, "siteobject"); 14987a8a68f5SJulian Pullen if (site_object != NULL) { 14997a8a68f5SJulian Pullen /* 15007a8a68f5SJulian Pullen * The site object should be of the form 15017a8a68f5SJulian Pullen * CN=<site>,CN=Sites,CN=Configuration, 15027a8a68f5SJulian Pullen * <DN Domain> 15037a8a68f5SJulian Pullen */ 15047a8a68f5SJulian Pullen if (strncasecmp(site_object, "CN=", 3) == 0) { 15057a8a68f5SJulian Pullen for (len = 0; site_object[len + 3] != ','; len++) 15067a8a68f5SJulian Pullen ; 15077a8a68f5SJulian Pullen site_name = malloc(len + 1); 15087a8a68f5SJulian Pullen (void) strncpy(site_name, &site_object[3], len); 15097a8a68f5SJulian Pullen site_name[len] = '\0'; 15107a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, 15117a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1512*c5866007SKeyur Desai update_version(&ctx->site_name, PARAM1, 1513*c5866007SKeyur Desai domain_controller_item); 15147a8a68f5SJulian Pullen } 15157a8a68f5SJulian Pullen } 15167a8a68f5SJulian Pullen 15177a8a68f5SJulian Pullen if (ctx->subnets != NULL) { 15187a8a68f5SJulian Pullen free(ctx->subnets); 15197a8a68f5SJulian Pullen ctx->subnets = NULL; 15207a8a68f5SJulian Pullen } 15217a8a68f5SJulian Pullen ctx->subnets = subnets; 15227a8a68f5SJulian Pullen subnets = NULL; 15237a8a68f5SJulian Pullen ctx->subnets_changed = B_FALSE; 15247a8a68f5SJulian Pullen 15257a8a68f5SJulian Pullen out: 15267a8a68f5SJulian Pullen if (ld != NULL) 15277a8a68f5SJulian Pullen (void) ldap_unbind(ld); 15287a8a68f5SJulian Pullen 15297a8a68f5SJulian Pullen if (dn_subnets != NULL) { 15307a8a68f5SJulian Pullen for (i = 0; dn_subnets[i] != NULL; i++) 15317a8a68f5SJulian Pullen free(dn_subnets[i]); 15327a8a68f5SJulian Pullen free(dn_subnets); 15337a8a68f5SJulian Pullen } 15347a8a68f5SJulian Pullen if (config_naming_context != NULL) 15357a8a68f5SJulian Pullen free(config_naming_context); 15367a8a68f5SJulian Pullen if (site_object != NULL) 15377a8a68f5SJulian Pullen free(site_object); 15387a8a68f5SJulian Pullen 15397a8a68f5SJulian Pullen free(subnets); 15407a8a68f5SJulian Pullen if (site_name == NULL) 15417a8a68f5SJulian Pullen return (NULL); 15427a8a68f5SJulian Pullen return (&ctx->site_name); 15437a8a68f5SJulian Pullen 15447a8a68f5SJulian Pullen } 15457a8a68f5SJulian Pullen 15467a8a68f5SJulian Pullen 15477a8a68f5SJulian Pullen char * 15487a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 15497a8a68f5SJulian Pullen { 15507a8a68f5SJulian Pullen ad_item_t *site_name_item; 15517a8a68f5SJulian Pullen char *site_name = NULL; 15527a8a68f5SJulian Pullen 15537a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 15547a8a68f5SJulian Pullen if (site_name_item != NULL) { 15557a8a68f5SJulian Pullen site_name = strdup(site_name_item->value); 15567a8a68f5SJulian Pullen if (auto_discovered != NULL) 15577a8a68f5SJulian Pullen *auto_discovered = 15587a8a68f5SJulian Pullen (site_name_item->state == AD_STATE_AUTO); 15597a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 15607a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 15617a8a68f5SJulian Pullen 15627a8a68f5SJulian Pullen return (site_name); 15637a8a68f5SJulian Pullen } 15647a8a68f5SJulian Pullen 15657a8a68f5SJulian Pullen 15667a8a68f5SJulian Pullen 15677a8a68f5SJulian Pullen /* Discover forest name */ 15687a8a68f5SJulian Pullen static ad_item_t * 15697a8a68f5SJulian Pullen validate_ForestName(ad_disc_t ctx) 15707a8a68f5SJulian Pullen { 15717a8a68f5SJulian Pullen LDAP *ld = NULL; 15727a8a68f5SJulian Pullen char *config_naming_context; 15737a8a68f5SJulian Pullen char *forest_name = NULL; 15747a8a68f5SJulian Pullen char *dn_list[2]; 15757a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 15767a8a68f5SJulian Pullen 15777a8a68f5SJulian Pullen if (is_fixed(&ctx->forest_name)) 15787a8a68f5SJulian Pullen return (&ctx->forest_name); 15797a8a68f5SJulian Pullen /* 15807a8a68f5SJulian Pullen * We may not have a site name yet, so we won't rely on 15817a8a68f5SJulian Pullen * site-specific DCs. (But maybe we could replace 15827a8a68f5SJulian Pullen * validate_ForestName() with validate_siteName()?) 15837a8a68f5SJulian Pullen */ 15847a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 15857a8a68f5SJulian Pullen if (domain_controller_item == NULL) 15867a8a68f5SJulian Pullen return (NULL); 15877a8a68f5SJulian Pullen 15887a8a68f5SJulian Pullen if (!is_valid(&ctx->forest_name) || 15897a8a68f5SJulian Pullen is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) { 15907a8a68f5SJulian Pullen 15917a8a68f5SJulian Pullen dn_list[0] = ""; 15927a8a68f5SJulian Pullen dn_list[1] = NULL; 15937a8a68f5SJulian Pullen config_naming_context = ldap_lookup_entry_attr( 15947a8a68f5SJulian Pullen &ld, ctx->domain_controller.value, 15957a8a68f5SJulian Pullen dn_list, "configurationNamingContext"); 15967a8a68f5SJulian Pullen if (config_naming_context != NULL) { 15977a8a68f5SJulian Pullen /* 15987a8a68f5SJulian Pullen * The configurationNamingContext should be of 15997a8a68f5SJulian Pullen * form: 16007a8a68f5SJulian Pullen * CN=Configuration,<DNforestName> 16017a8a68f5SJulian Pullen * Remove the first part and convert to DNS form 16027a8a68f5SJulian Pullen * (replace ",DC=" with ".") 16037a8a68f5SJulian Pullen */ 16047a8a68f5SJulian Pullen char *str = "CN=Configuration,"; 16057a8a68f5SJulian Pullen int len = strlen(str); 16067a8a68f5SJulian Pullen if (strncasecmp(config_naming_context, str, len) == 0) { 16077a8a68f5SJulian Pullen forest_name = DN_to_DNS( 16087a8a68f5SJulian Pullen config_naming_context + len); 16097a8a68f5SJulian Pullen } 16107a8a68f5SJulian Pullen free(config_naming_context); 16117a8a68f5SJulian Pullen } 16127a8a68f5SJulian Pullen if (ld != NULL) 16137a8a68f5SJulian Pullen (void) ldap_unbind(ld); 16147a8a68f5SJulian Pullen 16157a8a68f5SJulian Pullen if (forest_name == NULL) 16167a8a68f5SJulian Pullen return (NULL); 16177a8a68f5SJulian Pullen 16187a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 16197a8a68f5SJulian Pullen update_version(&ctx->forest_name, PARAM1, 16207a8a68f5SJulian Pullen domain_controller_item); 16217a8a68f5SJulian Pullen } 16227a8a68f5SJulian Pullen return (&ctx->forest_name); 16237a8a68f5SJulian Pullen } 16247a8a68f5SJulian Pullen 16257a8a68f5SJulian Pullen 16267a8a68f5SJulian Pullen char * 16277a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 16287a8a68f5SJulian Pullen { 16297a8a68f5SJulian Pullen ad_item_t *forest_name_item; 16307a8a68f5SJulian Pullen char *forest_name = NULL; 16317a8a68f5SJulian Pullen 16327a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 16337a8a68f5SJulian Pullen 16347a8a68f5SJulian Pullen if (forest_name_item != NULL) { 16357a8a68f5SJulian Pullen forest_name = strdup(forest_name_item->value); 16367a8a68f5SJulian Pullen if (auto_discovered != NULL) 16377a8a68f5SJulian Pullen *auto_discovered = 16387a8a68f5SJulian Pullen (forest_name_item->state == AD_STATE_AUTO); 16397a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 16407a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 16417a8a68f5SJulian Pullen 16427a8a68f5SJulian Pullen return (forest_name); 16437a8a68f5SJulian Pullen } 16447a8a68f5SJulian Pullen 16457a8a68f5SJulian Pullen 16467a8a68f5SJulian Pullen /* Discover global catalog servers */ 16477a8a68f5SJulian Pullen static ad_item_t * 16487a8a68f5SJulian Pullen validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 16497a8a68f5SJulian Pullen { 16507a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 16517a8a68f5SJulian Pullen uint32_t ttl = 0; 16527a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 16537a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 16547a8a68f5SJulian Pullen ad_item_t *forest_name_item; 16557a8a68f5SJulian Pullen ad_item_t *site_name_item; 16567a8a68f5SJulian Pullen 16577a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 16587a8a68f5SJulian Pullen if (is_fixed(&ctx->global_catalog)) 16597a8a68f5SJulian Pullen return (&ctx->global_catalog); 16607a8a68f5SJulian Pullen 16617a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 16627a8a68f5SJulian Pullen if (forest_name_item == NULL) 16637a8a68f5SJulian Pullen return (NULL); 16647a8a68f5SJulian Pullen 16657a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 16667a8a68f5SJulian Pullen validate_global = B_TRUE; 16677a8a68f5SJulian Pullen else { 16687a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 16697a8a68f5SJulian Pullen if (site_name_item != NULL) 16707a8a68f5SJulian Pullen validate_site = B_TRUE; 16717a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 16727a8a68f5SJulian Pullen validate_global = B_TRUE; 16737a8a68f5SJulian Pullen } 16747a8a68f5SJulian Pullen 16757a8a68f5SJulian Pullen if (validate_global) { 16767a8a68f5SJulian Pullen if (!is_valid(&ctx->global_catalog) || 16777a8a68f5SJulian Pullen is_changed(&ctx->global_catalog, PARAM1, 16787a8a68f5SJulian Pullen forest_name_item)) { 16797a8a68f5SJulian Pullen /* 16807a8a68f5SJulian Pullen * Lookup DNS SRV RR named 16817a8a68f5SJulian Pullen * _ldap._tcp.gc._msdcs.<ForestName> 16827a8a68f5SJulian Pullen */ 16837a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 16847a8a68f5SJulian Pullen global_catalog = 16857a8a68f5SJulian Pullen srv_query(&ctx->res_state, 16867a8a68f5SJulian Pullen LDAP_SRV_HEAD GC_SRV_TAIL, 16877a8a68f5SJulian Pullen ctx->forest_name.value, NULL, &ttl); 16887a8a68f5SJulian Pullen 16897a8a68f5SJulian Pullen if (global_catalog == NULL) 16907a8a68f5SJulian Pullen return (NULL); 16917a8a68f5SJulian Pullen 16927a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 16937a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 16947a8a68f5SJulian Pullen update_version(&ctx->global_catalog, PARAM1, 16957a8a68f5SJulian Pullen forest_name_item); 16967a8a68f5SJulian Pullen } 16977a8a68f5SJulian Pullen return (&ctx->global_catalog); 16987a8a68f5SJulian Pullen } 16997a8a68f5SJulian Pullen 17007a8a68f5SJulian Pullen if (validate_site) { 17017a8a68f5SJulian Pullen if (!is_valid(&ctx->site_global_catalog) || 17027a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM1, 17037a8a68f5SJulian Pullen forest_name_item) || 17047a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM2, 17057a8a68f5SJulian Pullen site_name_item)) { 17067a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 17077a8a68f5SJulian Pullen 17087a8a68f5SJulian Pullen /* 17097a8a68f5SJulian Pullen * Lookup DNS SRV RR named: 17107a8a68f5SJulian Pullen * _ldap._tcp.<siteName>._sites.gc. 17117a8a68f5SJulian Pullen * _msdcs.<ForestName> 17127a8a68f5SJulian Pullen */ 17137a8a68f5SJulian Pullen (void) snprintf(rr_name, 17147a8a68f5SJulian Pullen sizeof (rr_name), 17157a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 17167a8a68f5SJulian Pullen ctx->site_name.value); 17177a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 17187a8a68f5SJulian Pullen global_catalog = srv_query(&ctx->res_state, rr_name, 17197a8a68f5SJulian Pullen ctx->forest_name.value, NULL, &ttl); 17207a8a68f5SJulian Pullen 17217a8a68f5SJulian Pullen if (global_catalog == NULL) 17227a8a68f5SJulian Pullen return (NULL); 17237a8a68f5SJulian Pullen update_item(&ctx->site_global_catalog, global_catalog, 17247a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 17257a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM1, 17267a8a68f5SJulian Pullen forest_name_item); 17277a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM2, 17287a8a68f5SJulian Pullen site_name_item); 17297a8a68f5SJulian Pullen } 17307a8a68f5SJulian Pullen return (&ctx->site_global_catalog); 17317a8a68f5SJulian Pullen } 17327a8a68f5SJulian Pullen return (NULL); 17337a8a68f5SJulian Pullen } 17347a8a68f5SJulian Pullen 17357a8a68f5SJulian Pullen 17367a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 17377a8a68f5SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 17387a8a68f5SJulian Pullen boolean_t *auto_discovered) 17397a8a68f5SJulian Pullen { 17407a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 17417a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 17427a8a68f5SJulian Pullen 17437a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, req); 17447a8a68f5SJulian Pullen 17457a8a68f5SJulian Pullen if (global_catalog_item != NULL) { 17467a8a68f5SJulian Pullen global_catalog = ds_dup(global_catalog_item->value); 17477a8a68f5SJulian Pullen if (auto_discovered != NULL) 17487a8a68f5SJulian Pullen *auto_discovered = 17497a8a68f5SJulian Pullen (global_catalog_item->state == AD_STATE_AUTO); 17507a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 17517a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 17527a8a68f5SJulian Pullen 17537a8a68f5SJulian Pullen return (global_catalog); 17547a8a68f5SJulian Pullen } 17557a8a68f5SJulian Pullen 17567a8a68f5SJulian Pullen 17577a8a68f5SJulian Pullen static ad_item_t * 17587a8a68f5SJulian Pullen validate_TrustedDomains(ad_disc_t ctx) 17597a8a68f5SJulian Pullen { 17607a8a68f5SJulian Pullen LDAP *ld = NULL; 17617a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 17627a8a68f5SJulian Pullen ad_item_t *forest_name_item; 17637a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains; 17647a8a68f5SJulian Pullen char *dn = NULL; 17657a8a68f5SJulian Pullen char *forest_name_dn; 17667a8a68f5SJulian Pullen int len; 17677a8a68f5SJulian Pullen int num_parts; 17687a8a68f5SJulian Pullen 17697a8a68f5SJulian Pullen if (is_fixed(&ctx->trusted_domains)) 17707a8a68f5SJulian Pullen return (&ctx->trusted_domains); 17717a8a68f5SJulian Pullen 17727a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 17737a8a68f5SJulian Pullen if (global_catalog_item == NULL) 17747a8a68f5SJulian Pullen return (NULL); 17757a8a68f5SJulian Pullen 17767a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 17777a8a68f5SJulian Pullen if (forest_name_item == NULL) 17787a8a68f5SJulian Pullen return (NULL); 17797a8a68f5SJulian Pullen 17807a8a68f5SJulian Pullen if (!is_valid(&ctx->trusted_domains) || 17817a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 17827a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 17837a8a68f5SJulian Pullen 17847a8a68f5SJulian Pullen forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 17857a8a68f5SJulian Pullen &num_parts); 17867a8a68f5SJulian Pullen if (forest_name_dn == NULL) 17877a8a68f5SJulian Pullen return (NULL); 17887a8a68f5SJulian Pullen 17897a8a68f5SJulian Pullen len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 17907a8a68f5SJulian Pullen dn = malloc(len); 17917a8a68f5SJulian Pullen if (dn == NULL) { 17927a8a68f5SJulian Pullen free(forest_name_dn); 17937a8a68f5SJulian Pullen return (NULL); 17947a8a68f5SJulian Pullen } 17957a8a68f5SJulian Pullen (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 17967a8a68f5SJulian Pullen free(forest_name_dn); 17977a8a68f5SJulian Pullen 17987a8a68f5SJulian Pullen trusted_domains = ldap_lookup_trusted_domains( 17997a8a68f5SJulian Pullen &ld, global_catalog_item->value, dn); 18007a8a68f5SJulian Pullen 18017a8a68f5SJulian Pullen if (ld != NULL) 18027a8a68f5SJulian Pullen (void) ldap_unbind(ld); 18037a8a68f5SJulian Pullen free(dn); 18047a8a68f5SJulian Pullen 18057a8a68f5SJulian Pullen if (trusted_domains == NULL) 18067a8a68f5SJulian Pullen return (NULL); 18077a8a68f5SJulian Pullen 18087a8a68f5SJulian Pullen update_item(&ctx->trusted_domains, trusted_domains, 18097a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 18107a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM1, 18117a8a68f5SJulian Pullen global_catalog_item); 18127a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM2, 18137a8a68f5SJulian Pullen forest_name_item); 18147a8a68f5SJulian Pullen } 18157a8a68f5SJulian Pullen 18167a8a68f5SJulian Pullen return (&ctx->trusted_domains); 18177a8a68f5SJulian Pullen } 18187a8a68f5SJulian Pullen 18197a8a68f5SJulian Pullen 18207a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 18217a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 18227a8a68f5SJulian Pullen { 18237a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 18247a8a68f5SJulian Pullen ad_item_t *trusted_domains_item; 18257a8a68f5SJulian Pullen 18267a8a68f5SJulian Pullen trusted_domains_item = validate_TrustedDomains(ctx); 18277a8a68f5SJulian Pullen 18287a8a68f5SJulian Pullen if (trusted_domains_item != NULL) { 18297a8a68f5SJulian Pullen trusted_domains = td_dup(trusted_domains_item->value); 18307a8a68f5SJulian Pullen if (auto_discovered != NULL) 18317a8a68f5SJulian Pullen *auto_discovered = 18327a8a68f5SJulian Pullen (trusted_domains_item->state == AD_STATE_AUTO); 18337a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 18347a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 18357a8a68f5SJulian Pullen 18367a8a68f5SJulian Pullen return (trusted_domains); 18377a8a68f5SJulian Pullen } 18387a8a68f5SJulian Pullen 18397a8a68f5SJulian Pullen 18407a8a68f5SJulian Pullen static ad_item_t * 18417a8a68f5SJulian Pullen validate_DomainsInForest(ad_disc_t ctx) 18427a8a68f5SJulian Pullen { 18437a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 18447a8a68f5SJulian Pullen LDAP *ld = NULL; 18457a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest; 18467a8a68f5SJulian Pullen 18477a8a68f5SJulian Pullen if (is_fixed(&ctx->domains_in_forest)) 18487a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 18497a8a68f5SJulian Pullen 18507a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 18517a8a68f5SJulian Pullen if (global_catalog_item == NULL) 18527a8a68f5SJulian Pullen return (NULL); 18537a8a68f5SJulian Pullen 18547a8a68f5SJulian Pullen if (!is_valid(&ctx->domains_in_forest) || 18557a8a68f5SJulian Pullen is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 18567a8a68f5SJulian Pullen 18577a8a68f5SJulian Pullen domains_in_forest = ldap_lookup_domains_in_forest( 18587a8a68f5SJulian Pullen &ld, global_catalog_item->value); 18597a8a68f5SJulian Pullen 18607a8a68f5SJulian Pullen if (ld != NULL) 18617a8a68f5SJulian Pullen (void) ldap_unbind(ld); 18627a8a68f5SJulian Pullen 18637a8a68f5SJulian Pullen if (domains_in_forest == NULL) 18647a8a68f5SJulian Pullen return (NULL); 18657a8a68f5SJulian Pullen 18667a8a68f5SJulian Pullen update_item(&ctx->domains_in_forest, domains_in_forest, 18677a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 18687a8a68f5SJulian Pullen update_version(&ctx->domains_in_forest, PARAM1, 18697a8a68f5SJulian Pullen global_catalog_item); 18707a8a68f5SJulian Pullen } 18717a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 18727a8a68f5SJulian Pullen } 18737a8a68f5SJulian Pullen 18747a8a68f5SJulian Pullen 18757a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 18767a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 18777a8a68f5SJulian Pullen { 18787a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest = NULL; 18797a8a68f5SJulian Pullen ad_item_t *domains_in_forest_item; 18807a8a68f5SJulian Pullen 18817a8a68f5SJulian Pullen domains_in_forest_item = validate_DomainsInForest(ctx); 18827a8a68f5SJulian Pullen 18837a8a68f5SJulian Pullen if (domains_in_forest_item != NULL) { 18847a8a68f5SJulian Pullen domains_in_forest = df_dup(domains_in_forest_item->value); 18857a8a68f5SJulian Pullen if (auto_discovered != NULL) 18867a8a68f5SJulian Pullen *auto_discovered = 18877a8a68f5SJulian Pullen (domains_in_forest_item->state == AD_STATE_AUTO); 18887a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 18897a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 18907a8a68f5SJulian Pullen 18917a8a68f5SJulian Pullen return (domains_in_forest); 18927a8a68f5SJulian Pullen } 18937a8a68f5SJulian Pullen 18947a8a68f5SJulian Pullen 18957a8a68f5SJulian Pullen 18967a8a68f5SJulian Pullen 18977a8a68f5SJulian Pullen int 18987a8a68f5SJulian Pullen ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 18997a8a68f5SJulian Pullen { 19007a8a68f5SJulian Pullen char *domain_name = NULL; 19017a8a68f5SJulian Pullen if (domainName != NULL) { 19027a8a68f5SJulian Pullen domain_name = strdup(domainName); 19037a8a68f5SJulian Pullen if (domain_name == NULL) 19047a8a68f5SJulian Pullen return (-1); 19057a8a68f5SJulian Pullen update_item(&ctx->domain_name, domain_name, 19067a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19077a8a68f5SJulian Pullen } else if (ctx->domain_name.state == AD_STATE_FIXED) 19087a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 19097a8a68f5SJulian Pullen return (0); 19107a8a68f5SJulian Pullen } 19117a8a68f5SJulian Pullen 19127a8a68f5SJulian Pullen 19137a8a68f5SJulian Pullen int 19147a8a68f5SJulian Pullen ad_disc_set_DomainController(ad_disc_t ctx, 19157a8a68f5SJulian Pullen const idmap_ad_disc_ds_t *domainController) 19167a8a68f5SJulian Pullen { 19177a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 19187a8a68f5SJulian Pullen if (domainController != NULL) { 19197a8a68f5SJulian Pullen domain_controller = ds_dup(domainController); 19207a8a68f5SJulian Pullen if (domain_controller == NULL) 19217a8a68f5SJulian Pullen return (-1); 19227a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 19237a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19247a8a68f5SJulian Pullen } else if (ctx->domain_controller.state == AD_STATE_FIXED) 19257a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 19267a8a68f5SJulian Pullen return (0); 19277a8a68f5SJulian Pullen } 19287a8a68f5SJulian Pullen 19297a8a68f5SJulian Pullen 19307a8a68f5SJulian Pullen int 19317a8a68f5SJulian Pullen ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 19327a8a68f5SJulian Pullen { 19337a8a68f5SJulian Pullen char *site_name = NULL; 19347a8a68f5SJulian Pullen if (siteName != NULL) { 19357a8a68f5SJulian Pullen site_name = strdup(siteName); 19367a8a68f5SJulian Pullen if (site_name == NULL) 19377a8a68f5SJulian Pullen return (-1); 19387a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 19397a8a68f5SJulian Pullen } else if (ctx->site_name.state == AD_STATE_FIXED) 19407a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 19417a8a68f5SJulian Pullen return (0); 19427a8a68f5SJulian Pullen } 19437a8a68f5SJulian Pullen 19447a8a68f5SJulian Pullen int 19457a8a68f5SJulian Pullen ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 19467a8a68f5SJulian Pullen { 19477a8a68f5SJulian Pullen char *forest_name = NULL; 19487a8a68f5SJulian Pullen if (forestName != NULL) { 19497a8a68f5SJulian Pullen forest_name = strdup(forestName); 19507a8a68f5SJulian Pullen if (forest_name == NULL) 19517a8a68f5SJulian Pullen return (-1); 19527a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 19537a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19547a8a68f5SJulian Pullen } else if (ctx->forest_name.state == AD_STATE_FIXED) 19557a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 19567a8a68f5SJulian Pullen return (0); 19577a8a68f5SJulian Pullen } 19587a8a68f5SJulian Pullen 19597a8a68f5SJulian Pullen int 19607a8a68f5SJulian Pullen ad_disc_set_GlobalCatalog(ad_disc_t ctx, 19617a8a68f5SJulian Pullen const idmap_ad_disc_ds_t *globalCatalog) 19627a8a68f5SJulian Pullen { 19637a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 19647a8a68f5SJulian Pullen if (globalCatalog != NULL) { 19657a8a68f5SJulian Pullen global_catalog = ds_dup(globalCatalog); 19667a8a68f5SJulian Pullen if (global_catalog == NULL) 19677a8a68f5SJulian Pullen return (-1); 19687a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 19697a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 19707a8a68f5SJulian Pullen } else if (ctx->global_catalog.state == AD_STATE_FIXED) 19717a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 19727a8a68f5SJulian Pullen return (0); 19737a8a68f5SJulian Pullen } 19747a8a68f5SJulian Pullen 19757a8a68f5SJulian Pullen 19767a8a68f5SJulian Pullen int 19777a8a68f5SJulian Pullen ad_disc_unset(ad_disc_t ctx) 19787a8a68f5SJulian Pullen { 19797a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_FIXED) 19807a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 19817a8a68f5SJulian Pullen 19827a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_FIXED) 19837a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 19847a8a68f5SJulian Pullen 19857a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_FIXED) 19867a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 19877a8a68f5SJulian Pullen 19887a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_FIXED) 19897a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 19907a8a68f5SJulian Pullen 19917a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_FIXED) 19927a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 19937a8a68f5SJulian Pullen 19947a8a68f5SJulian Pullen return (0); 19957a8a68f5SJulian Pullen } 19967a8a68f5SJulian Pullen 19977a8a68f5SJulian Pullen /* 19987a8a68f5SJulian Pullen * ad_disc_get_TTL 19997a8a68f5SJulian Pullen * 20007a8a68f5SJulian Pullen * This routines the time to live for AD 20017a8a68f5SJulian Pullen * auto discovered items. 20027a8a68f5SJulian Pullen * 20037a8a68f5SJulian Pullen * Returns: 20047a8a68f5SJulian Pullen * -1 if there are no TTL items 20057a8a68f5SJulian Pullen * 0 if there are expired items 20067a8a68f5SJulian Pullen * else the number of seconds 20077a8a68f5SJulian Pullen * 20087a8a68f5SJulian Pullen * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 20097a8a68f5SJulian Pullen * is positive -- min() greater than zero. 20107a8a68f5SJulian Pullen */ 20117a8a68f5SJulian Pullen #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 20127a8a68f5SJulian Pullen (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 20137a8a68f5SJulian Pullen int 20147a8a68f5SJulian Pullen ad_disc_get_TTL(ad_disc_t ctx) 20157a8a68f5SJulian Pullen { 2016*c5866007SKeyur Desai time_t expires; 20177a8a68f5SJulian Pullen int ttl; 20187a8a68f5SJulian Pullen 2019*c5866007SKeyur Desai expires = MIN_GT_ZERO(ctx->domain_controller.expires, 2020*c5866007SKeyur Desai ctx->global_catalog.expires); 2021*c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires); 2022*c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires); 20237a8a68f5SJulian Pullen 2024*c5866007SKeyur Desai if (expires == -1) { 20257a8a68f5SJulian Pullen return (-1); 2026*c5866007SKeyur Desai } 2027*c5866007SKeyur Desai 2028*c5866007SKeyur Desai if (ctx->expires_not_before != 0 && 2029*c5866007SKeyur Desai expires < ctx->expires_not_before) { 2030*c5866007SKeyur Desai expires = ctx->expires_not_before; 2031*c5866007SKeyur Desai } 2032*c5866007SKeyur Desai 2033*c5866007SKeyur Desai if (ctx->expires_not_after != 0 && 2034*c5866007SKeyur Desai expires > ctx->expires_not_after) { 2035*c5866007SKeyur Desai expires = ctx->expires_not_after; 2036*c5866007SKeyur Desai } 2037*c5866007SKeyur Desai 2038*c5866007SKeyur Desai ttl = expires - time(NULL); 2039*c5866007SKeyur Desai 2040*c5866007SKeyur Desai if (ttl < 0) { 20417a8a68f5SJulian Pullen return (0); 2042*c5866007SKeyur Desai } 20437a8a68f5SJulian Pullen return (ttl); 20447a8a68f5SJulian Pullen } 20457a8a68f5SJulian Pullen 20467a8a68f5SJulian Pullen boolean_t 20477a8a68f5SJulian Pullen ad_disc_SubnetChanged(ad_disc_t ctx) 20487a8a68f5SJulian Pullen { 20497a8a68f5SJulian Pullen ad_subnet_t *subnets; 20507a8a68f5SJulian Pullen 20517a8a68f5SJulian Pullen if (ctx->subnets_changed || ctx->subnets == NULL) 20527a8a68f5SJulian Pullen return (B_TRUE); 20537a8a68f5SJulian Pullen 20547a8a68f5SJulian Pullen if ((subnets = find_subnets()) != NULL) { 20557a8a68f5SJulian Pullen if (cmpsubnets(subnets, ctx->subnets) != 0) 20567a8a68f5SJulian Pullen ctx->subnets_changed = B_TRUE; 20577a8a68f5SJulian Pullen free(subnets); 20587a8a68f5SJulian Pullen } 20597a8a68f5SJulian Pullen 20607a8a68f5SJulian Pullen return (ctx->subnets_changed); 20617a8a68f5SJulian Pullen } 2062