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