18671SJulian.Pullen@Sun.COM /* 28671SJulian.Pullen@Sun.COM * CDDL HEADER START 38671SJulian.Pullen@Sun.COM * 48671SJulian.Pullen@Sun.COM * The contents of this file are subject to the terms of the 58671SJulian.Pullen@Sun.COM * Common Development and Distribution License (the "License"). 68671SJulian.Pullen@Sun.COM * You may not use this file except in compliance with the License. 78671SJulian.Pullen@Sun.COM * 88671SJulian.Pullen@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98671SJulian.Pullen@Sun.COM * or http://www.opensolaris.org/os/licensing. 108671SJulian.Pullen@Sun.COM * See the License for the specific language governing permissions 118671SJulian.Pullen@Sun.COM * and limitations under the License. 128671SJulian.Pullen@Sun.COM * 138671SJulian.Pullen@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148671SJulian.Pullen@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158671SJulian.Pullen@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168671SJulian.Pullen@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178671SJulian.Pullen@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188671SJulian.Pullen@Sun.COM * 198671SJulian.Pullen@Sun.COM * CDDL HEADER END 208671SJulian.Pullen@Sun.COM */ 218671SJulian.Pullen@Sun.COM 228671SJulian.Pullen@Sun.COM /* 238671SJulian.Pullen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 248671SJulian.Pullen@Sun.COM * Use is subject to license terms. 258671SJulian.Pullen@Sun.COM */ 268671SJulian.Pullen@Sun.COM 278671SJulian.Pullen@Sun.COM /* 288671SJulian.Pullen@Sun.COM * Active Directory Auto-Discovery. 298671SJulian.Pullen@Sun.COM * 308671SJulian.Pullen@Sun.COM * This [project private] API allows the caller to provide whatever 318671SJulian.Pullen@Sun.COM * details it knows a priori (i.e., provided via configuration so as to 328671SJulian.Pullen@Sun.COM * override auto-discovery) and in any order. Then the caller can ask 338671SJulian.Pullen@Sun.COM * for any of the auto-discoverable parameters in any order. 348671SJulian.Pullen@Sun.COM * 358671SJulian.Pullen@Sun.COM * But there is an actual order in which discovery must be done. Given 368671SJulian.Pullen@Sun.COM * the discovery mechanism implemented here, that order is: 378671SJulian.Pullen@Sun.COM * 388671SJulian.Pullen@Sun.COM * - the domain name joined must be discovered first 398671SJulian.Pullen@Sun.COM * - then the domain controllers 408671SJulian.Pullen@Sun.COM * - then the forest name and site name 418671SJulian.Pullen@Sun.COM * - then the global catalog servers, and site-specific domain 428671SJulian.Pullen@Sun.COM * controllers and global catalog servers. 438671SJulian.Pullen@Sun.COM * 448671SJulian.Pullen@Sun.COM * The API does not require it be called in the same order because there 458671SJulian.Pullen@Sun.COM * may be other discovery mechanisms in the future, and exposing 468671SJulian.Pullen@Sun.COM * ordering requirements of the current mechanism now can create trouble 478671SJulian.Pullen@Sun.COM * down the line. Also, this makes the API easier to use now, which 488671SJulian.Pullen@Sun.COM * means less work to do some day when we make this a public API. 498671SJulian.Pullen@Sun.COM * 508671SJulian.Pullen@Sun.COM * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 518671SJulian.Pullen@Sun.COM * domain controllers. As long as the joined domain appears in the DNS 528671SJulian.Pullen@Sun.COM * resolver's search list then we'll find it. 538671SJulian.Pullen@Sun.COM * 548671SJulian.Pullen@Sun.COM * Domain controller discovery is a matter of formatting the DNS SRV RR 558671SJulian.Pullen@Sun.COM * FQDN for domain controllers and doing a lookup for them. Knowledge 568671SJulian.Pullen@Sun.COM * of the domain name is not fundamentally required, but we separate the 578671SJulian.Pullen@Sun.COM * two processes, which in practice can lead to one more DNS lookup than 588671SJulian.Pullen@Sun.COM * is strictly required. 598671SJulian.Pullen@Sun.COM * 608671SJulian.Pullen@Sun.COM * Forest and site name discovery require an LDAP search of the AD 618671SJulian.Pullen@Sun.COM * "configuration partition" at a domain controller for the joined 628671SJulian.Pullen@Sun.COM * domain. Forest and site name discovery depend on knowing the joined 638671SJulian.Pullen@Sun.COM * domain name and domain controllers for that domain. 648671SJulian.Pullen@Sun.COM * 658671SJulian.Pullen@Sun.COM * Global catalog server discovery requires knowledge of the forest 668671SJulian.Pullen@Sun.COM * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 678671SJulian.Pullen@Sun.COM * domain controller discovery depends on knowing the site name (and, 688671SJulian.Pullen@Sun.COM * therefore, joined domain, ...). Site-specific global catalog server 698671SJulian.Pullen@Sun.COM * discovery depends on knowledge of the forest and site names, which 708671SJulian.Pullen@Sun.COM * depend on... 718671SJulian.Pullen@Sun.COM * 728671SJulian.Pullen@Sun.COM * All the work of discovering particular items is done by functions 738671SJulian.Pullen@Sun.COM * named validate_<item>(). Each such function calls validate_<item>() 748671SJulian.Pullen@Sun.COM * for any items that it depends on. 758671SJulian.Pullen@Sun.COM * 768671SJulian.Pullen@Sun.COM * This API is not thread-safe. 778671SJulian.Pullen@Sun.COM */ 788671SJulian.Pullen@Sun.COM 798671SJulian.Pullen@Sun.COM 808671SJulian.Pullen@Sun.COM #include <stdio.h> 818671SJulian.Pullen@Sun.COM #include <string.h> 828671SJulian.Pullen@Sun.COM #include <strings.h> 838671SJulian.Pullen@Sun.COM #include <unistd.h> 848671SJulian.Pullen@Sun.COM #include <assert.h> 858671SJulian.Pullen@Sun.COM #include <stdlib.h> 868671SJulian.Pullen@Sun.COM #include <net/if.h> 878671SJulian.Pullen@Sun.COM #include <net/if.h> 888671SJulian.Pullen@Sun.COM #include <sys/types.h> 898671SJulian.Pullen@Sun.COM #include <sys/socket.h> 908671SJulian.Pullen@Sun.COM #include <sys/sockio.h> 918671SJulian.Pullen@Sun.COM #include <netinet/in.h> 928671SJulian.Pullen@Sun.COM #include <netinet/in.h> 938671SJulian.Pullen@Sun.COM #include <arpa/inet.h> 948671SJulian.Pullen@Sun.COM #include <arpa/nameser.h> 958671SJulian.Pullen@Sun.COM #include <resolv.h> 968671SJulian.Pullen@Sun.COM #include <netdb.h> 978671SJulian.Pullen@Sun.COM #include <ctype.h> 988671SJulian.Pullen@Sun.COM #include <errno.h> 998671SJulian.Pullen@Sun.COM #include <ldap.h> 1008671SJulian.Pullen@Sun.COM #include <sasl/sasl.h> 1018671SJulian.Pullen@Sun.COM #include <sys/u8_textprep.h> 1028671SJulian.Pullen@Sun.COM #include <syslog.h> 1038671SJulian.Pullen@Sun.COM #include "adutils_impl.h" 1048671SJulian.Pullen@Sun.COM #include "addisc.h" 1058671SJulian.Pullen@Sun.COM 1068671SJulian.Pullen@Sun.COM 1078671SJulian.Pullen@Sun.COM enum ad_item_state { 1088671SJulian.Pullen@Sun.COM AD_STATE_INVALID = 0, /* The value is not valid */ 1098671SJulian.Pullen@Sun.COM AD_STATE_FIXED, /* The value was fixed by caller */ 1108671SJulian.Pullen@Sun.COM AD_STATE_AUTO /* The value is auto discovered */ 1118671SJulian.Pullen@Sun.COM }; 1128671SJulian.Pullen@Sun.COM 1138671SJulian.Pullen@Sun.COM enum ad_data_type { 1148671SJulian.Pullen@Sun.COM AD_STRING = 123, 1158671SJulian.Pullen@Sun.COM AD_DIRECTORY, 1168671SJulian.Pullen@Sun.COM AD_DOMAINS_IN_FOREST, 1178671SJulian.Pullen@Sun.COM AD_TRUSTED_DOMAINS 1188671SJulian.Pullen@Sun.COM }; 1198671SJulian.Pullen@Sun.COM 1208671SJulian.Pullen@Sun.COM 1218671SJulian.Pullen@Sun.COM typedef struct ad_subnet { 1228671SJulian.Pullen@Sun.COM char subnet[24]; 1238671SJulian.Pullen@Sun.COM } ad_subnet_t; 1248671SJulian.Pullen@Sun.COM 1258671SJulian.Pullen@Sun.COM 1268671SJulian.Pullen@Sun.COM typedef struct ad_item { 1278671SJulian.Pullen@Sun.COM enum ad_item_state state; 1288671SJulian.Pullen@Sun.COM enum ad_data_type type; 1298671SJulian.Pullen@Sun.COM void *value; 1308671SJulian.Pullen@Sun.COM time_t ttl; 1318671SJulian.Pullen@Sun.COM unsigned int version; /* Version is only changed */ 1328671SJulian.Pullen@Sun.COM /* if the value changes */ 1338671SJulian.Pullen@Sun.COM #define PARAM1 0 1348671SJulian.Pullen@Sun.COM #define PARAM2 1 1358671SJulian.Pullen@Sun.COM int param_version[2]; 1368671SJulian.Pullen@Sun.COM /* These holds the version of */ 1378671SJulian.Pullen@Sun.COM /* dependents so that a dependent */ 1388671SJulian.Pullen@Sun.COM /* change can be detected */ 1398671SJulian.Pullen@Sun.COM } ad_item_t; 1408671SJulian.Pullen@Sun.COM 1418671SJulian.Pullen@Sun.COM typedef struct ad_disc { 1428671SJulian.Pullen@Sun.COM struct __res_state res_state; 1438671SJulian.Pullen@Sun.COM int res_ninitted; 1448671SJulian.Pullen@Sun.COM ad_subnet_t *subnets; 1458671SJulian.Pullen@Sun.COM boolean_t subnets_changed; 1468671SJulian.Pullen@Sun.COM time_t subnets_last_check; 1478671SJulian.Pullen@Sun.COM ad_item_t domain_name; /* DNS hostname string */ 1488671SJulian.Pullen@Sun.COM ad_item_t domain_controller; /* Directory hostname and */ 1498671SJulian.Pullen@Sun.COM /* port array */ 1508671SJulian.Pullen@Sun.COM ad_item_t site_name; /* String */ 1518671SJulian.Pullen@Sun.COM ad_item_t forest_name; /* DNS forestname string */ 1528671SJulian.Pullen@Sun.COM ad_item_t global_catalog; /* Directory hostname and */ 1538671SJulian.Pullen@Sun.COM /* port array */ 1548671SJulian.Pullen@Sun.COM ad_item_t domains_in_forest; /* DNS domainname and SID */ 1558671SJulian.Pullen@Sun.COM /* array */ 1568671SJulian.Pullen@Sun.COM ad_item_t trusted_domains; /* DNS domainname and trust */ 1578671SJulian.Pullen@Sun.COM /* direction array */ 1588671SJulian.Pullen@Sun.COM /* Site specfic versions */ 1598671SJulian.Pullen@Sun.COM ad_item_t site_domain_controller; /* Directory hostname and */ 1608671SJulian.Pullen@Sun.COM /* port array */ 1618671SJulian.Pullen@Sun.COM ad_item_t site_global_catalog; /* Directory hostname and */ 1628671SJulian.Pullen@Sun.COM /* port array */ 1638671SJulian.Pullen@Sun.COM } ad_disc; 1648671SJulian.Pullen@Sun.COM 1658671SJulian.Pullen@Sun.COM 1668671SJulian.Pullen@Sun.COM #define DNS_MAX_NAME NS_MAXDNAME 1678671SJulian.Pullen@Sun.COM 1688671SJulian.Pullen@Sun.COM 1698671SJulian.Pullen@Sun.COM /* SRV RR names for various queries */ 1708671SJulian.Pullen@Sun.COM #define LDAP_SRV_HEAD "_ldap._tcp." 1718671SJulian.Pullen@Sun.COM #define SITE_SRV_MIDDLE "%s._sites." 1728671SJulian.Pullen@Sun.COM #define GC_SRV_TAIL "gc._msdcs" 1738671SJulian.Pullen@Sun.COM #define DC_SRV_TAIL "dc._msdcs" 1748671SJulian.Pullen@Sun.COM #define ALL_GC_SRV_TAIL "_gc._tcp" 1758671SJulian.Pullen@Sun.COM #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 1768671SJulian.Pullen@Sun.COM 1778671SJulian.Pullen@Sun.COM /* A RR name for all GCs -- last resort this works */ 1788671SJulian.Pullen@Sun.COM #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 1798671SJulian.Pullen@Sun.COM 1808671SJulian.Pullen@Sun.COM 1818671SJulian.Pullen@Sun.COM /* 1828671SJulian.Pullen@Sun.COM * We try res_ninit() whenever we don't have one. res_ninit() fails if 1838671SJulian.Pullen@Sun.COM * idmapd is running before the network is up! 1848671SJulian.Pullen@Sun.COM */ 1858671SJulian.Pullen@Sun.COM #define DO_RES_NINIT(ctx) if (!(ctx)->res_ninitted) \ 1868671SJulian.Pullen@Sun.COM (ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1) 1878671SJulian.Pullen@Sun.COM 1888671SJulian.Pullen@Sun.COM #define is_fixed(item) \ 1898671SJulian.Pullen@Sun.COM ((item)->state == AD_STATE_FIXED) 1908671SJulian.Pullen@Sun.COM 1918671SJulian.Pullen@Sun.COM #define is_changed(item, num, param) \ 1928671SJulian.Pullen@Sun.COM ((item)->param_version[num] != (param)->version) 1938671SJulian.Pullen@Sun.COM 1948671SJulian.Pullen@Sun.COM /*LINTLIBRARY*/ 1958671SJulian.Pullen@Sun.COM 1968671SJulian.Pullen@Sun.COM /* 1978671SJulian.Pullen@Sun.COM * Function definitions 1988671SJulian.Pullen@Sun.COM */ 1998671SJulian.Pullen@Sun.COM static ad_item_t * 2008671SJulian.Pullen@Sun.COM validate_SiteName(ad_disc_t ctx); 2018671SJulian.Pullen@Sun.COM 2028671SJulian.Pullen@Sun.COM 2038671SJulian.Pullen@Sun.COM 2048671SJulian.Pullen@Sun.COM static void 2058671SJulian.Pullen@Sun.COM update_version(ad_item_t *item, int num, ad_item_t *param) 2068671SJulian.Pullen@Sun.COM { 2078671SJulian.Pullen@Sun.COM item->param_version[num] = param->version; 2088671SJulian.Pullen@Sun.COM } 2098671SJulian.Pullen@Sun.COM 2108671SJulian.Pullen@Sun.COM 2118671SJulian.Pullen@Sun.COM 2128671SJulian.Pullen@Sun.COM static boolean_t 2138671SJulian.Pullen@Sun.COM is_valid(ad_item_t *item) 2148671SJulian.Pullen@Sun.COM { 2158671SJulian.Pullen@Sun.COM if (item->value != NULL) { 2168671SJulian.Pullen@Sun.COM if (item->state == AD_STATE_FIXED) 2178671SJulian.Pullen@Sun.COM return (B_TRUE); 2188671SJulian.Pullen@Sun.COM if (item->state == AD_STATE_AUTO && 2198671SJulian.Pullen@Sun.COM (item->ttl == 0 || item->ttl > time(NULL))) 2208671SJulian.Pullen@Sun.COM return (B_TRUE); 2218671SJulian.Pullen@Sun.COM } 2228671SJulian.Pullen@Sun.COM return (B_FALSE); 2238671SJulian.Pullen@Sun.COM } 2248671SJulian.Pullen@Sun.COM 2258671SJulian.Pullen@Sun.COM 2268671SJulian.Pullen@Sun.COM static void 2278671SJulian.Pullen@Sun.COM update_item(ad_item_t *item, void *value, enum ad_item_state state, 2288671SJulian.Pullen@Sun.COM uint32_t ttl) 2298671SJulian.Pullen@Sun.COM { 2308671SJulian.Pullen@Sun.COM if (item->value != NULL && value != NULL) { 2318671SJulian.Pullen@Sun.COM if ((item->type == AD_STRING && 2328671SJulian.Pullen@Sun.COM strcmp(item->value, value) != 0) || 2338671SJulian.Pullen@Sun.COM (item->type == AD_DIRECTORY && 2348671SJulian.Pullen@Sun.COM ad_disc_compare_ds(item->value, value) != 0)|| 2358671SJulian.Pullen@Sun.COM (item->type == AD_DOMAINS_IN_FOREST && 2368671SJulian.Pullen@Sun.COM ad_disc_compare_domainsinforest(item->value, value) != 0) || 2378671SJulian.Pullen@Sun.COM (item->type == AD_TRUSTED_DOMAINS && 2388671SJulian.Pullen@Sun.COM ad_disc_compare_trusteddomains(item->value, value) != 0)) 2398671SJulian.Pullen@Sun.COM item->version++; 2408671SJulian.Pullen@Sun.COM } else if (item->value != value) 2418671SJulian.Pullen@Sun.COM item->version++; 2428671SJulian.Pullen@Sun.COM 2438671SJulian.Pullen@Sun.COM if (item->value != NULL) 2448671SJulian.Pullen@Sun.COM free(item->value); 2458671SJulian.Pullen@Sun.COM 2468671SJulian.Pullen@Sun.COM item->value = value; 2478671SJulian.Pullen@Sun.COM item->state = state; 2488671SJulian.Pullen@Sun.COM 2498671SJulian.Pullen@Sun.COM if (ttl == 0) 2508671SJulian.Pullen@Sun.COM item->ttl = 0; 2518671SJulian.Pullen@Sun.COM else 2528671SJulian.Pullen@Sun.COM item->ttl = time(NULL) + ttl; 2538671SJulian.Pullen@Sun.COM } 2548671SJulian.Pullen@Sun.COM 2558671SJulian.Pullen@Sun.COM 2568671SJulian.Pullen@Sun.COM /* Compare DS lists */ 2578671SJulian.Pullen@Sun.COM int 2588671SJulian.Pullen@Sun.COM ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) 2598671SJulian.Pullen@Sun.COM { 2608671SJulian.Pullen@Sun.COM int i, j; 2618671SJulian.Pullen@Sun.COM int num_ds1; 2628671SJulian.Pullen@Sun.COM int num_ds2; 2638671SJulian.Pullen@Sun.COM boolean_t match; 2648671SJulian.Pullen@Sun.COM 2658671SJulian.Pullen@Sun.COM for (i = 0; ds1[i].host[0] != '\0'; i++) 2668671SJulian.Pullen@Sun.COM continue; 2678671SJulian.Pullen@Sun.COM num_ds1 = i; 2688671SJulian.Pullen@Sun.COM for (j = 0; ds2[j].host[0] != '\0'; j++) 2698671SJulian.Pullen@Sun.COM continue; 2708671SJulian.Pullen@Sun.COM num_ds2 = j; 2718671SJulian.Pullen@Sun.COM if (num_ds1 != num_ds2) 2728671SJulian.Pullen@Sun.COM return (1); 2738671SJulian.Pullen@Sun.COM 2748671SJulian.Pullen@Sun.COM for (i = 0; i < num_ds1; i++) { 2758671SJulian.Pullen@Sun.COM match = B_FALSE; 2768671SJulian.Pullen@Sun.COM for (j = 0; j < num_ds2; j++) { 2779744SJordan.Brown@Sun.COM if (strcmp(ds1[i].host, ds2[j].host) == 0 && 2789744SJordan.Brown@Sun.COM ds1[i].port == ds2[j].port) { 2798671SJulian.Pullen@Sun.COM match = B_TRUE; 2808671SJulian.Pullen@Sun.COM break; 2818671SJulian.Pullen@Sun.COM } 2828671SJulian.Pullen@Sun.COM } 2838671SJulian.Pullen@Sun.COM if (!match) 2848671SJulian.Pullen@Sun.COM return (1); 2858671SJulian.Pullen@Sun.COM } 2868671SJulian.Pullen@Sun.COM return (0); 2878671SJulian.Pullen@Sun.COM } 2888671SJulian.Pullen@Sun.COM 2898671SJulian.Pullen@Sun.COM 2908671SJulian.Pullen@Sun.COM /* Copy a list of DSs */ 2918671SJulian.Pullen@Sun.COM static idmap_ad_disc_ds_t * 2928671SJulian.Pullen@Sun.COM ds_dup(const idmap_ad_disc_ds_t *srv) 2938671SJulian.Pullen@Sun.COM { 2948671SJulian.Pullen@Sun.COM int i; 2958671SJulian.Pullen@Sun.COM int size; 2968671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *new = NULL; 2978671SJulian.Pullen@Sun.COM 2988671SJulian.Pullen@Sun.COM for (i = 0; srv[i].host[0] != '\0'; i++) 2998671SJulian.Pullen@Sun.COM continue; 3008671SJulian.Pullen@Sun.COM 3018671SJulian.Pullen@Sun.COM size = (i + 1) * sizeof (idmap_ad_disc_ds_t); 3028671SJulian.Pullen@Sun.COM new = malloc(size); 3038671SJulian.Pullen@Sun.COM if (new != NULL) 3048671SJulian.Pullen@Sun.COM memcpy(new, srv, size); 3058671SJulian.Pullen@Sun.COM return (new); 3068671SJulian.Pullen@Sun.COM } 3078671SJulian.Pullen@Sun.COM 3088671SJulian.Pullen@Sun.COM 3098671SJulian.Pullen@Sun.COM int 3108671SJulian.Pullen@Sun.COM ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 3118671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t *td2) 3128671SJulian.Pullen@Sun.COM { 3138671SJulian.Pullen@Sun.COM int i, j; 3148671SJulian.Pullen@Sun.COM int num_td1; 3158671SJulian.Pullen@Sun.COM int num_td2; 3168671SJulian.Pullen@Sun.COM boolean_t match; 3178671SJulian.Pullen@Sun.COM 3188671SJulian.Pullen@Sun.COM for (i = 0; td1[i].domain[0] != '\0'; i++) 3198671SJulian.Pullen@Sun.COM continue; 3208671SJulian.Pullen@Sun.COM num_td1 = i; 3218671SJulian.Pullen@Sun.COM 3228671SJulian.Pullen@Sun.COM for (j = 0; td2[j].domain[0] != '\0'; j++) 3238671SJulian.Pullen@Sun.COM continue; 3248671SJulian.Pullen@Sun.COM num_td2 = j; 3258671SJulian.Pullen@Sun.COM 3268671SJulian.Pullen@Sun.COM if (num_td1 != num_td2) 3278671SJulian.Pullen@Sun.COM return (1); 3288671SJulian.Pullen@Sun.COM 3298671SJulian.Pullen@Sun.COM for (i = 0; i < num_td1; i++) { 3308671SJulian.Pullen@Sun.COM match = B_FALSE; 3318671SJulian.Pullen@Sun.COM for (j = 0; j < num_td2; j++) { 332*10122SJordan.Brown@Sun.COM if (domain_eq(td1[i].domain, td2[j].domain)) { 3338671SJulian.Pullen@Sun.COM match = B_TRUE; 3348671SJulian.Pullen@Sun.COM break; 3358671SJulian.Pullen@Sun.COM } 3368671SJulian.Pullen@Sun.COM } 3378671SJulian.Pullen@Sun.COM if (!match) 3388671SJulian.Pullen@Sun.COM return (1); 3398671SJulian.Pullen@Sun.COM } 3408671SJulian.Pullen@Sun.COM return (0); 3418671SJulian.Pullen@Sun.COM } 3428671SJulian.Pullen@Sun.COM 3438671SJulian.Pullen@Sun.COM 3448671SJulian.Pullen@Sun.COM 3458671SJulian.Pullen@Sun.COM /* Copy a list of Trusted Domains */ 3468671SJulian.Pullen@Sun.COM static ad_disc_trusteddomains_t * 3478671SJulian.Pullen@Sun.COM td_dup(const ad_disc_trusteddomains_t *td) 3488671SJulian.Pullen@Sun.COM { 3498671SJulian.Pullen@Sun.COM int i; 3508671SJulian.Pullen@Sun.COM int size; 3518671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t *new = NULL; 3528671SJulian.Pullen@Sun.COM 3538671SJulian.Pullen@Sun.COM for (i = 0; td[i].domain[0] != '\0'; i++) 3548671SJulian.Pullen@Sun.COM continue; 3558671SJulian.Pullen@Sun.COM 3568671SJulian.Pullen@Sun.COM size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 3578671SJulian.Pullen@Sun.COM new = malloc(size); 3588671SJulian.Pullen@Sun.COM if (new != NULL) 3598671SJulian.Pullen@Sun.COM memcpy(new, td, size); 3608671SJulian.Pullen@Sun.COM return (new); 3618671SJulian.Pullen@Sun.COM } 3628671SJulian.Pullen@Sun.COM 3638671SJulian.Pullen@Sun.COM 3648671SJulian.Pullen@Sun.COM 3658671SJulian.Pullen@Sun.COM int 3668671SJulian.Pullen@Sun.COM ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 3678671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t *df2) 3688671SJulian.Pullen@Sun.COM { 3698671SJulian.Pullen@Sun.COM int i, j; 3708671SJulian.Pullen@Sun.COM int num_df1; 3718671SJulian.Pullen@Sun.COM int num_df2; 3728671SJulian.Pullen@Sun.COM boolean_t match; 3738671SJulian.Pullen@Sun.COM 3748671SJulian.Pullen@Sun.COM for (i = 0; df1[i].domain[0] != '\0'; i++) 3758671SJulian.Pullen@Sun.COM continue; 3768671SJulian.Pullen@Sun.COM num_df1 = i; 3778671SJulian.Pullen@Sun.COM 3788671SJulian.Pullen@Sun.COM for (j = 0; df2[j].domain[0] != '\0'; j++) 3798671SJulian.Pullen@Sun.COM continue; 3808671SJulian.Pullen@Sun.COM num_df2 = j; 3818671SJulian.Pullen@Sun.COM 3828671SJulian.Pullen@Sun.COM if (num_df1 != num_df2) 3838671SJulian.Pullen@Sun.COM return (1); 3848671SJulian.Pullen@Sun.COM 3858671SJulian.Pullen@Sun.COM for (i = 0; i < num_df1; i++) { 3868671SJulian.Pullen@Sun.COM match = B_FALSE; 3878671SJulian.Pullen@Sun.COM for (j = 0; j < num_df2; j++) { 388*10122SJordan.Brown@Sun.COM if (domain_eq(df1[i].domain, df2[j].domain) && 3899744SJordan.Brown@Sun.COM strcmp(df1[i].sid, df2[j].sid) == 0) { 3908671SJulian.Pullen@Sun.COM match = B_TRUE; 3918671SJulian.Pullen@Sun.COM break; 3928671SJulian.Pullen@Sun.COM } 3938671SJulian.Pullen@Sun.COM } 3948671SJulian.Pullen@Sun.COM if (!match) 3958671SJulian.Pullen@Sun.COM return (1); 3968671SJulian.Pullen@Sun.COM } 3978671SJulian.Pullen@Sun.COM return (0); 3988671SJulian.Pullen@Sun.COM } 3998671SJulian.Pullen@Sun.COM 4008671SJulian.Pullen@Sun.COM 4018671SJulian.Pullen@Sun.COM 4028671SJulian.Pullen@Sun.COM /* Copy a list of Trusted Domains */ 4038671SJulian.Pullen@Sun.COM static ad_disc_domainsinforest_t * 4048671SJulian.Pullen@Sun.COM df_dup(const ad_disc_domainsinforest_t *df) 4058671SJulian.Pullen@Sun.COM { 4068671SJulian.Pullen@Sun.COM int i; 4078671SJulian.Pullen@Sun.COM int size; 4088671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t *new = NULL; 4098671SJulian.Pullen@Sun.COM 4108671SJulian.Pullen@Sun.COM for (i = 0; df[i].domain[0] != '\0'; i++) 4118671SJulian.Pullen@Sun.COM continue; 4128671SJulian.Pullen@Sun.COM 4138671SJulian.Pullen@Sun.COM size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 4148671SJulian.Pullen@Sun.COM new = malloc(size); 4158671SJulian.Pullen@Sun.COM if (new != NULL) 4168671SJulian.Pullen@Sun.COM memcpy(new, df, size); 4178671SJulian.Pullen@Sun.COM return (new); 4188671SJulian.Pullen@Sun.COM } 4198671SJulian.Pullen@Sun.COM 4208671SJulian.Pullen@Sun.COM 4218671SJulian.Pullen@Sun.COM 4228671SJulian.Pullen@Sun.COM 4238671SJulian.Pullen@Sun.COM 4248671SJulian.Pullen@Sun.COM /* 4258671SJulian.Pullen@Sun.COM * Returns an array of IPv4 address/prefix length 4268671SJulian.Pullen@Sun.COM * The last subnet is NULL 4278671SJulian.Pullen@Sun.COM */ 4288671SJulian.Pullen@Sun.COM static ad_subnet_t * 4298671SJulian.Pullen@Sun.COM find_subnets() 4308671SJulian.Pullen@Sun.COM { 4318671SJulian.Pullen@Sun.COM int sock, n, i; 4328671SJulian.Pullen@Sun.COM struct lifconf lifc; 4338671SJulian.Pullen@Sun.COM struct lifreq lifr, *lifrp; 4348671SJulian.Pullen@Sun.COM struct lifnum lifn; 4358671SJulian.Pullen@Sun.COM uint32_t prefix_len; 4368671SJulian.Pullen@Sun.COM char *s; 4378671SJulian.Pullen@Sun.COM ad_subnet_t *results; 4388671SJulian.Pullen@Sun.COM 4398671SJulian.Pullen@Sun.COM lifrp = &lifr; 4408671SJulian.Pullen@Sun.COM 4418671SJulian.Pullen@Sun.COM if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 4428671SJulian.Pullen@Sun.COM logger(LOG_ERR, "Failed to open IPv4 socket for " 4438671SJulian.Pullen@Sun.COM "listing network interfaces (%s)", strerror(errno)); 4448671SJulian.Pullen@Sun.COM return (NULL); 4458671SJulian.Pullen@Sun.COM } 4468671SJulian.Pullen@Sun.COM 4478671SJulian.Pullen@Sun.COM lifn.lifn_family = AF_INET; 4488671SJulian.Pullen@Sun.COM lifn.lifn_flags = 0; 4498671SJulian.Pullen@Sun.COM if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4508671SJulian.Pullen@Sun.COM logger(LOG_ERR, 4518671SJulian.Pullen@Sun.COM "Failed to find the number of network interfaces (%s)", 4528671SJulian.Pullen@Sun.COM strerror(errno)); 4538671SJulian.Pullen@Sun.COM close(sock); 4548671SJulian.Pullen@Sun.COM return (NULL); 4558671SJulian.Pullen@Sun.COM } 4568671SJulian.Pullen@Sun.COM 4578671SJulian.Pullen@Sun.COM if (lifn.lifn_count < 1) { 4588671SJulian.Pullen@Sun.COM logger(LOG_ERR, "No IPv4 network interfaces found"); 4598671SJulian.Pullen@Sun.COM close(sock); 4608671SJulian.Pullen@Sun.COM return (NULL); 4618671SJulian.Pullen@Sun.COM } 4628671SJulian.Pullen@Sun.COM 4638671SJulian.Pullen@Sun.COM lifc.lifc_family = AF_INET; 4648671SJulian.Pullen@Sun.COM lifc.lifc_flags = 0; 4658671SJulian.Pullen@Sun.COM lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 4668671SJulian.Pullen@Sun.COM lifc.lifc_buf = malloc(lifc.lifc_len); 4678671SJulian.Pullen@Sun.COM 4688671SJulian.Pullen@Sun.COM if (lifc.lifc_buf == NULL) { 4698671SJulian.Pullen@Sun.COM logger(LOG_ERR, "Out of memory"); 4708671SJulian.Pullen@Sun.COM close(sock); 4718671SJulian.Pullen@Sun.COM return (NULL); 4728671SJulian.Pullen@Sun.COM } 4738671SJulian.Pullen@Sun.COM 4748671SJulian.Pullen@Sun.COM if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 4758671SJulian.Pullen@Sun.COM logger(LOG_ERR, "Failed to list network interfaces (%s)", 4768671SJulian.Pullen@Sun.COM strerror(errno)); 4778671SJulian.Pullen@Sun.COM free(lifc.lifc_buf); 4788671SJulian.Pullen@Sun.COM close(sock); 4798671SJulian.Pullen@Sun.COM return (NULL); 4808671SJulian.Pullen@Sun.COM } 4818671SJulian.Pullen@Sun.COM 4828671SJulian.Pullen@Sun.COM n = lifc.lifc_len / (int)sizeof (struct lifreq); 4838671SJulian.Pullen@Sun.COM 4848671SJulian.Pullen@Sun.COM if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 4858671SJulian.Pullen@Sun.COM free(lifc.lifc_buf); 4868671SJulian.Pullen@Sun.COM close(sock); 4878671SJulian.Pullen@Sun.COM return (NULL); 4888671SJulian.Pullen@Sun.COM } 4898671SJulian.Pullen@Sun.COM 4908671SJulian.Pullen@Sun.COM for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 4918671SJulian.Pullen@Sun.COM if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 4928671SJulian.Pullen@Sun.COM continue; 4938671SJulian.Pullen@Sun.COM 4948671SJulian.Pullen@Sun.COM if ((lifrp->lifr_flags & IFF_UP) == 0) 4958671SJulian.Pullen@Sun.COM continue; 4968671SJulian.Pullen@Sun.COM 4978671SJulian.Pullen@Sun.COM if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 4988671SJulian.Pullen@Sun.COM continue; 4998671SJulian.Pullen@Sun.COM 5008671SJulian.Pullen@Sun.COM prefix_len = lifrp->lifr_addrlen; 5018671SJulian.Pullen@Sun.COM 5028671SJulian.Pullen@Sun.COM s = inet_ntoa(((struct sockaddr_in *) 5038671SJulian.Pullen@Sun.COM &lifrp->lifr_addr)->sin_addr); 5048671SJulian.Pullen@Sun.COM 5058671SJulian.Pullen@Sun.COM (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 5068671SJulian.Pullen@Sun.COM "%s/%d", s, prefix_len); 5078671SJulian.Pullen@Sun.COM } 5088671SJulian.Pullen@Sun.COM 5098671SJulian.Pullen@Sun.COM free(lifc.lifc_buf); 5108671SJulian.Pullen@Sun.COM close(sock); 5118671SJulian.Pullen@Sun.COM 5128671SJulian.Pullen@Sun.COM return (results); 5138671SJulian.Pullen@Sun.COM } 5148671SJulian.Pullen@Sun.COM 5158671SJulian.Pullen@Sun.COM static int 5168671SJulian.Pullen@Sun.COM cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 5178671SJulian.Pullen@Sun.COM { 5188671SJulian.Pullen@Sun.COM int num_subnets1; 5198671SJulian.Pullen@Sun.COM int num_subnets2; 5208671SJulian.Pullen@Sun.COM boolean_t matched; 5218671SJulian.Pullen@Sun.COM int i, j; 5228671SJulian.Pullen@Sun.COM 5238671SJulian.Pullen@Sun.COM for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 5248671SJulian.Pullen@Sun.COM continue; 5258671SJulian.Pullen@Sun.COM num_subnets1 = i; 5268671SJulian.Pullen@Sun.COM 5278671SJulian.Pullen@Sun.COM for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 5288671SJulian.Pullen@Sun.COM continue; 5298671SJulian.Pullen@Sun.COM num_subnets2 = i; 5308671SJulian.Pullen@Sun.COM 5318671SJulian.Pullen@Sun.COM if (num_subnets1 != num_subnets2) 5328671SJulian.Pullen@Sun.COM return (1); 5338671SJulian.Pullen@Sun.COM 5348671SJulian.Pullen@Sun.COM for (i = 0; i < num_subnets1; i++) { 5358671SJulian.Pullen@Sun.COM matched = B_FALSE; 5368671SJulian.Pullen@Sun.COM for (j = 0; j < num_subnets2; j++) { 5378671SJulian.Pullen@Sun.COM if (strcmp(subnets1[i].subnet, 5388671SJulian.Pullen@Sun.COM subnets2[j].subnet) == 0) { 5398671SJulian.Pullen@Sun.COM matched = B_TRUE; 5408671SJulian.Pullen@Sun.COM break; 5418671SJulian.Pullen@Sun.COM } 5428671SJulian.Pullen@Sun.COM } 5438671SJulian.Pullen@Sun.COM if (!matched) 5448671SJulian.Pullen@Sun.COM return (1); 5458671SJulian.Pullen@Sun.COM } 5468671SJulian.Pullen@Sun.COM return (0); 5478671SJulian.Pullen@Sun.COM } 5488671SJulian.Pullen@Sun.COM 5498671SJulian.Pullen@Sun.COM 5508671SJulian.Pullen@Sun.COM 5518671SJulian.Pullen@Sun.COM 5528671SJulian.Pullen@Sun.COM /* Convert a DN's DC components into a DNS domainname */ 5538671SJulian.Pullen@Sun.COM char * 5548671SJulian.Pullen@Sun.COM DN_to_DNS(const char *dn_name) 5558671SJulian.Pullen@Sun.COM { 5568671SJulian.Pullen@Sun.COM char dns[DNS_MAX_NAME]; 5578671SJulian.Pullen@Sun.COM char *dns_name; 5588671SJulian.Pullen@Sun.COM int i, j; 5598671SJulian.Pullen@Sun.COM int num = 0; 5608671SJulian.Pullen@Sun.COM 5618671SJulian.Pullen@Sun.COM j = 0; 5628671SJulian.Pullen@Sun.COM i = 0; 5638671SJulian.Pullen@Sun.COM 5648671SJulian.Pullen@Sun.COM if (dn_name == NULL) 5658671SJulian.Pullen@Sun.COM return (NULL); 5668671SJulian.Pullen@Sun.COM /* 5678671SJulian.Pullen@Sun.COM * Find all DC=<value> and form DNS name of the 5688671SJulian.Pullen@Sun.COM * form <value1>.<value2>... 5698671SJulian.Pullen@Sun.COM */ 5708671SJulian.Pullen@Sun.COM while (dn_name[i] != '\0') { 5718671SJulian.Pullen@Sun.COM if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 5728671SJulian.Pullen@Sun.COM i += 3; 5738671SJulian.Pullen@Sun.COM if (dn_name[i] != '\0' && num > 0) 5748671SJulian.Pullen@Sun.COM dns[j++] = '.'; 5758671SJulian.Pullen@Sun.COM while (dn_name[i] != '\0' && 5768671SJulian.Pullen@Sun.COM dn_name[i] != ',' && dn_name[i] != '+') 5778671SJulian.Pullen@Sun.COM dns[j++] = dn_name[i++]; 5788671SJulian.Pullen@Sun.COM num++; 5798671SJulian.Pullen@Sun.COM } else { 5808671SJulian.Pullen@Sun.COM /* Skip attr=value as it is not DC= */ 5818671SJulian.Pullen@Sun.COM while (dn_name[i] != '\0' && 5828671SJulian.Pullen@Sun.COM dn_name[i] != ',' && dn_name[i] != '+') 5838671SJulian.Pullen@Sun.COM i++; 5848671SJulian.Pullen@Sun.COM } 5858671SJulian.Pullen@Sun.COM /* Skip over separator ',' or '+' */ 5868671SJulian.Pullen@Sun.COM if (dn_name[i] != '\0') i++; 5878671SJulian.Pullen@Sun.COM } 5888671SJulian.Pullen@Sun.COM dns[j] = '\0'; 5898671SJulian.Pullen@Sun.COM dns_name = malloc(j + 1); 5908671SJulian.Pullen@Sun.COM if (dns_name != NULL) 5918671SJulian.Pullen@Sun.COM (void) strlcpy(dns_name, dns, j + 1); 5928671SJulian.Pullen@Sun.COM return (dns_name); 5938671SJulian.Pullen@Sun.COM } 5948671SJulian.Pullen@Sun.COM 5958671SJulian.Pullen@Sun.COM 5968671SJulian.Pullen@Sun.COM /* Format the DN of an AD LDAP subnet object for some subnet */ 5978671SJulian.Pullen@Sun.COM static char * 5988671SJulian.Pullen@Sun.COM subnet_to_DN(const char *subnet, const char *baseDN) 5998671SJulian.Pullen@Sun.COM { 6008671SJulian.Pullen@Sun.COM char *result; 6018671SJulian.Pullen@Sun.COM int len; 6028671SJulian.Pullen@Sun.COM 6038671SJulian.Pullen@Sun.COM len = snprintf(NULL, 0, 6048671SJulian.Pullen@Sun.COM "CN=%s,CN=Subnets,CN=Sites,%s", 6058671SJulian.Pullen@Sun.COM subnet, baseDN) + 1; 6068671SJulian.Pullen@Sun.COM 6078671SJulian.Pullen@Sun.COM result = malloc(len); 6088671SJulian.Pullen@Sun.COM if (result != NULL) 6098671SJulian.Pullen@Sun.COM (void) snprintf(result, len, 6108671SJulian.Pullen@Sun.COM "CN=%s,CN=Subnets,CN=Sites,%s", 6118671SJulian.Pullen@Sun.COM subnet, baseDN); 6128671SJulian.Pullen@Sun.COM return (result); 6138671SJulian.Pullen@Sun.COM } 6148671SJulian.Pullen@Sun.COM 6158671SJulian.Pullen@Sun.COM 6168671SJulian.Pullen@Sun.COM /* Make a list of subnet object DNs from a list of subnets */ 6178671SJulian.Pullen@Sun.COM static char ** 6188671SJulian.Pullen@Sun.COM subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) 6198671SJulian.Pullen@Sun.COM { 6208671SJulian.Pullen@Sun.COM char **results; 6218671SJulian.Pullen@Sun.COM int i, j; 6228671SJulian.Pullen@Sun.COM 6238671SJulian.Pullen@Sun.COM for (i = 0; subnets[i].subnet[0] != '\0'; i++) 6248671SJulian.Pullen@Sun.COM continue; 6258671SJulian.Pullen@Sun.COM 6268671SJulian.Pullen@Sun.COM results = calloc(i + 1, sizeof (char *)); 6278671SJulian.Pullen@Sun.COM if (results == NULL) 6288671SJulian.Pullen@Sun.COM return (NULL); 6298671SJulian.Pullen@Sun.COM 6308671SJulian.Pullen@Sun.COM for (i = 0; subnets[i].subnet[0] != '\0'; i++) { 6318671SJulian.Pullen@Sun.COM if ((results[i] = subnet_to_DN(subnets[i].subnet, base_dn)) 6328671SJulian.Pullen@Sun.COM == NULL) { 6338671SJulian.Pullen@Sun.COM for (j = 0; j < i; j++) 6348671SJulian.Pullen@Sun.COM free(results[j]); 6358671SJulian.Pullen@Sun.COM free(results); 6368671SJulian.Pullen@Sun.COM return (NULL); 6378671SJulian.Pullen@Sun.COM } 6388671SJulian.Pullen@Sun.COM } 6398671SJulian.Pullen@Sun.COM 6408671SJulian.Pullen@Sun.COM return (results); 6418671SJulian.Pullen@Sun.COM } 6428671SJulian.Pullen@Sun.COM 6438671SJulian.Pullen@Sun.COM 6448671SJulian.Pullen@Sun.COM /* Compare SRC RRs; used with qsort() */ 6458671SJulian.Pullen@Sun.COM static int 6468671SJulian.Pullen@Sun.COM srvcmp(idmap_ad_disc_ds_t *s1, idmap_ad_disc_ds_t *s2) 6478671SJulian.Pullen@Sun.COM { 6488671SJulian.Pullen@Sun.COM if (s1->priority < s2->priority) 6498671SJulian.Pullen@Sun.COM return (1); 6508671SJulian.Pullen@Sun.COM else if (s1->priority > s2->priority) 6518671SJulian.Pullen@Sun.COM return (-1); 6528671SJulian.Pullen@Sun.COM 6538671SJulian.Pullen@Sun.COM if (s1->weight < s2->weight) 6548671SJulian.Pullen@Sun.COM return (1); 6558671SJulian.Pullen@Sun.COM else if (s1->weight > s2->weight) 6568671SJulian.Pullen@Sun.COM return (-1); 6578671SJulian.Pullen@Sun.COM 6588671SJulian.Pullen@Sun.COM return (0); 6598671SJulian.Pullen@Sun.COM } 6608671SJulian.Pullen@Sun.COM 6618671SJulian.Pullen@Sun.COM 6628671SJulian.Pullen@Sun.COM /* 6638671SJulian.Pullen@Sun.COM * Query or search the SRV RRs for a given name. 6648671SJulian.Pullen@Sun.COM * 6658671SJulian.Pullen@Sun.COM * If name == NULL then search (as in res_nsearch(3RESOLV), honoring any 6668671SJulian.Pullen@Sun.COM * search list/option), else query (as in res_nquery(3RESOLV)). 6678671SJulian.Pullen@Sun.COM * 6688671SJulian.Pullen@Sun.COM * The output TTL will be the one of the SRV RR with the lowest TTL. 6698671SJulian.Pullen@Sun.COM */ 6708671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t * 6718671SJulian.Pullen@Sun.COM srv_query(res_state state, const char *svc_name, const char *dname, 6728671SJulian.Pullen@Sun.COM char **rrname, uint32_t *ttl) 6738671SJulian.Pullen@Sun.COM { 6748671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *srv; 6758671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *srv_res; 6768671SJulian.Pullen@Sun.COM union { 6778671SJulian.Pullen@Sun.COM HEADER hdr; 6788671SJulian.Pullen@Sun.COM uchar_t buf[NS_MAXMSG]; 6798671SJulian.Pullen@Sun.COM } msg; 6808671SJulian.Pullen@Sun.COM int len, cnt, qdcount, ancount; 6818671SJulian.Pullen@Sun.COM uchar_t *ptr, *eom; 6828671SJulian.Pullen@Sun.COM uchar_t *end; 6838671SJulian.Pullen@Sun.COM uint16_t type; 6848671SJulian.Pullen@Sun.COM /* LINTED E_FUNC_SET_NOT_USED */ 6858671SJulian.Pullen@Sun.COM uint16_t class; 6868671SJulian.Pullen@Sun.COM uint32_t rttl; 6878671SJulian.Pullen@Sun.COM uint16_t size; 6888671SJulian.Pullen@Sun.COM char namebuf[NS_MAXDNAME]; 6898671SJulian.Pullen@Sun.COM 6908671SJulian.Pullen@Sun.COM if (state == NULL) 6918671SJulian.Pullen@Sun.COM return (NULL); 6928671SJulian.Pullen@Sun.COM 6938671SJulian.Pullen@Sun.COM /* Set negative result TTL */ 6948671SJulian.Pullen@Sun.COM *ttl = 5 * 60; 6958671SJulian.Pullen@Sun.COM 6968671SJulian.Pullen@Sun.COM /* 1. query necessary resource records */ 6978671SJulian.Pullen@Sun.COM 6988671SJulian.Pullen@Sun.COM /* Search, querydomain or query */ 6998671SJulian.Pullen@Sun.COM if (rrname != NULL) { 7008671SJulian.Pullen@Sun.COM *rrname = NULL; 7018671SJulian.Pullen@Sun.COM len = res_nsearch(state, svc_name, C_IN, T_SRV, 7028671SJulian.Pullen@Sun.COM msg.buf, sizeof (msg.buf)); 7038671SJulian.Pullen@Sun.COM logger(LOG_DEBUG, "Searching DNS for SRV RRs named '%s'", 7048671SJulian.Pullen@Sun.COM svc_name); 7058671SJulian.Pullen@Sun.COM if (len < 0) { 7068671SJulian.Pullen@Sun.COM logger(LOG_DEBUG, "DNS search for '%s' failed (%s)", 7078671SJulian.Pullen@Sun.COM svc_name, hstrerror(state->res_h_errno)); 7088671SJulian.Pullen@Sun.COM return (NULL); 7098671SJulian.Pullen@Sun.COM } 7108671SJulian.Pullen@Sun.COM } else if (dname != NULL) { 7118671SJulian.Pullen@Sun.COM len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV, 7128671SJulian.Pullen@Sun.COM msg.buf, sizeof (msg.buf)); 7138671SJulian.Pullen@Sun.COM logger(LOG_DEBUG, 7148671SJulian.Pullen@Sun.COM "Querying DNS for SRV RRs named '%s' for '%s' ", 7158671SJulian.Pullen@Sun.COM svc_name, dname); 7168671SJulian.Pullen@Sun.COM 7178671SJulian.Pullen@Sun.COM if (len < 0) { 7188671SJulian.Pullen@Sun.COM logger(LOG_DEBUG, 7198671SJulian.Pullen@Sun.COM "DNS query for '%s' for '%s' failed (%s)", 7208671SJulian.Pullen@Sun.COM svc_name, dname, hstrerror(state->res_h_errno)); 7218671SJulian.Pullen@Sun.COM return (NULL); 7228671SJulian.Pullen@Sun.COM } 7238671SJulian.Pullen@Sun.COM } 7248671SJulian.Pullen@Sun.COM 7258671SJulian.Pullen@Sun.COM if (len > sizeof (msg.buf)) { 7268671SJulian.Pullen@Sun.COM logger(LOG_ERR, "DNS query %ib message doesn't fit" 7278671SJulian.Pullen@Sun.COM " into %ib buffer", 7288671SJulian.Pullen@Sun.COM len, sizeof (msg.buf)); 7298671SJulian.Pullen@Sun.COM return (NULL); 7308671SJulian.Pullen@Sun.COM } 7318671SJulian.Pullen@Sun.COM 7328671SJulian.Pullen@Sun.COM /* 2. parse the reply, skip header and question sections */ 7338671SJulian.Pullen@Sun.COM 7348671SJulian.Pullen@Sun.COM ptr = msg.buf + sizeof (msg.hdr); 7358671SJulian.Pullen@Sun.COM eom = msg.buf + len; 7368671SJulian.Pullen@Sun.COM qdcount = ntohs(msg.hdr.qdcount); 7378671SJulian.Pullen@Sun.COM ancount = ntohs(msg.hdr.ancount); 7388671SJulian.Pullen@Sun.COM 7398671SJulian.Pullen@Sun.COM for (cnt = qdcount; cnt > 0; --cnt) { 7408671SJulian.Pullen@Sun.COM if ((len = dn_skipname(ptr, eom)) < 0) { 7418671SJulian.Pullen@Sun.COM logger(LOG_ERR, "DNS query invalid message format"); 7428671SJulian.Pullen@Sun.COM return (NULL); 7438671SJulian.Pullen@Sun.COM } 7448671SJulian.Pullen@Sun.COM ptr += len + QFIXEDSZ; 7458671SJulian.Pullen@Sun.COM } 7468671SJulian.Pullen@Sun.COM 7478671SJulian.Pullen@Sun.COM /* 3. walk through the answer section */ 7488671SJulian.Pullen@Sun.COM 7498671SJulian.Pullen@Sun.COM srv_res = calloc(ancount + 1, sizeof (idmap_ad_disc_ds_t)); 7508671SJulian.Pullen@Sun.COM *ttl = (uint32_t)-1; 7518671SJulian.Pullen@Sun.COM 7528671SJulian.Pullen@Sun.COM for (srv = srv_res, cnt = ancount; 7538671SJulian.Pullen@Sun.COM cnt > 0; --cnt, srv++) { 7548671SJulian.Pullen@Sun.COM 7558671SJulian.Pullen@Sun.COM len = dn_expand(msg.buf, eom, ptr, namebuf, 7568671SJulian.Pullen@Sun.COM sizeof (namebuf)); 7578671SJulian.Pullen@Sun.COM if (len < 0) { 7588671SJulian.Pullen@Sun.COM logger(LOG_ERR, "DNS query invalid message format"); 7598671SJulian.Pullen@Sun.COM return (NULL); 7608671SJulian.Pullen@Sun.COM } 7618671SJulian.Pullen@Sun.COM if (rrname != NULL && *rrname == NULL) 7628671SJulian.Pullen@Sun.COM *rrname = strdup(namebuf); 7638671SJulian.Pullen@Sun.COM ptr += len; 7648671SJulian.Pullen@Sun.COM NS_GET16(type, ptr); 7658671SJulian.Pullen@Sun.COM NS_GET16(class, ptr); 7668671SJulian.Pullen@Sun.COM NS_GET32(rttl, ptr); 7678671SJulian.Pullen@Sun.COM NS_GET16(size, ptr); 7688671SJulian.Pullen@Sun.COM if ((end = ptr + size) > eom) { 7698671SJulian.Pullen@Sun.COM logger(LOG_ERR, "DNS query invalid message format"); 7708671SJulian.Pullen@Sun.COM return (NULL); 7718671SJulian.Pullen@Sun.COM } 7728671SJulian.Pullen@Sun.COM 7738671SJulian.Pullen@Sun.COM if (type != T_SRV) { 7748671SJulian.Pullen@Sun.COM ptr = end; 7758671SJulian.Pullen@Sun.COM continue; 7768671SJulian.Pullen@Sun.COM } 7778671SJulian.Pullen@Sun.COM 7788671SJulian.Pullen@Sun.COM NS_GET16(srv->priority, ptr); 7798671SJulian.Pullen@Sun.COM NS_GET16(srv->weight, ptr); 7808671SJulian.Pullen@Sun.COM NS_GET16(srv->port, ptr); 7818671SJulian.Pullen@Sun.COM len = dn_expand(msg.buf, eom, ptr, srv->host, 7828671SJulian.Pullen@Sun.COM sizeof (srv->host)); 7838671SJulian.Pullen@Sun.COM if (len < 0) { 7848671SJulian.Pullen@Sun.COM logger(LOG_ERR, "DNS query invalid SRV record"); 7858671SJulian.Pullen@Sun.COM return (NULL); 7868671SJulian.Pullen@Sun.COM } 7878671SJulian.Pullen@Sun.COM 7888671SJulian.Pullen@Sun.COM if (rttl < *ttl) 7898671SJulian.Pullen@Sun.COM *ttl = rttl; 7908671SJulian.Pullen@Sun.COM 7918671SJulian.Pullen@Sun.COM logger(LOG_DEBUG, "Found %s %d IN SRV [%d][%d] %s:%d", 7928671SJulian.Pullen@Sun.COM namebuf, rttl, srv->priority, srv->weight, srv->host, 7938671SJulian.Pullen@Sun.COM srv->port); 7948671SJulian.Pullen@Sun.COM 7958671SJulian.Pullen@Sun.COM /* 3. move ptr to the end of current record */ 7968671SJulian.Pullen@Sun.COM 7978671SJulian.Pullen@Sun.COM ptr = end; 7988671SJulian.Pullen@Sun.COM } 7998671SJulian.Pullen@Sun.COM 8008671SJulian.Pullen@Sun.COM if (ancount > 1) 8018671SJulian.Pullen@Sun.COM qsort(srv_res, ancount, sizeof (*srv_res), 8028671SJulian.Pullen@Sun.COM (int (*)(const void *, const void *))srvcmp); 8038671SJulian.Pullen@Sun.COM 8048671SJulian.Pullen@Sun.COM return (srv_res); 8058671SJulian.Pullen@Sun.COM } 8068671SJulian.Pullen@Sun.COM 8078671SJulian.Pullen@Sun.COM 8088671SJulian.Pullen@Sun.COM /* 8098671SJulian.Pullen@Sun.COM * A utility function to bind to a Directory server 8108671SJulian.Pullen@Sun.COM */ 8118671SJulian.Pullen@Sun.COM 8128671SJulian.Pullen@Sun.COM static LDAP* 8138671SJulian.Pullen@Sun.COM ldap_lookup_init(idmap_ad_disc_ds_t *ds) 8148671SJulian.Pullen@Sun.COM { 8158671SJulian.Pullen@Sun.COM int i; 8168671SJulian.Pullen@Sun.COM int rc, ldversion; 8178671SJulian.Pullen@Sun.COM int zero = 0; 8188671SJulian.Pullen@Sun.COM int timeoutms = 5 * 1000; 8198671SJulian.Pullen@Sun.COM char *saslmech = "GSSAPI"; 8208671SJulian.Pullen@Sun.COM uint32_t saslflags = LDAP_SASL_INTERACTIVE; 8218671SJulian.Pullen@Sun.COM LDAP *ld = NULL; 8228671SJulian.Pullen@Sun.COM 8238671SJulian.Pullen@Sun.COM for (i = 0; ds[i].host[0] != '\0'; i++) { 8248671SJulian.Pullen@Sun.COM ld = ldap_init(ds[i].host, ds[i].port); 8258671SJulian.Pullen@Sun.COM if (ld == NULL) { 8268671SJulian.Pullen@Sun.COM logger(LOG_DEBUG, "Couldn't connect to " 8278671SJulian.Pullen@Sun.COM "AD DC %s:%d (%s)", 8288671SJulian.Pullen@Sun.COM ds[i].host, ds[i].port, 8298671SJulian.Pullen@Sun.COM strerror(errno)); 8308671SJulian.Pullen@Sun.COM continue; 8318671SJulian.Pullen@Sun.COM } 8328671SJulian.Pullen@Sun.COM 8338671SJulian.Pullen@Sun.COM ldversion = LDAP_VERSION3; 8348671SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 8358671SJulian.Pullen@Sun.COM &ldversion); 8368671SJulian.Pullen@Sun.COM 8378671SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 8388671SJulian.Pullen@Sun.COM LDAP_OPT_OFF); 8398671SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 8408671SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 8418671SJulian.Pullen@Sun.COM /* setup TCP/IP connect timeout */ 8428671SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 8438671SJulian.Pullen@Sun.COM &timeoutms); 8448671SJulian.Pullen@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_RESTART, 8458671SJulian.Pullen@Sun.COM LDAP_OPT_ON); 8468671SJulian.Pullen@Sun.COM 8478671SJulian.Pullen@Sun.COM rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 8488671SJulian.Pullen@Sun.COM saslmech, NULL, NULL, saslflags, &saslcallback, 8498671SJulian.Pullen@Sun.COM NULL /* defaults */); 8508671SJulian.Pullen@Sun.COM if (rc == LDAP_SUCCESS) 8518671SJulian.Pullen@Sun.COM break; 8528671SJulian.Pullen@Sun.COM 8538671SJulian.Pullen@Sun.COM logger(LOG_INFO, "LDAP SASL bind to %s:%d failed (%s)", 8548671SJulian.Pullen@Sun.COM ds[i].host, ds[i].port, ldap_err2string(rc)); 8558671SJulian.Pullen@Sun.COM (void) ldap_unbind(ld); 8568671SJulian.Pullen@Sun.COM ld = NULL; 8578671SJulian.Pullen@Sun.COM } 8588671SJulian.Pullen@Sun.COM return (ld); 8598671SJulian.Pullen@Sun.COM } 8608671SJulian.Pullen@Sun.COM 8618671SJulian.Pullen@Sun.COM 8628671SJulian.Pullen@Sun.COM 8638671SJulian.Pullen@Sun.COM /* 8648671SJulian.Pullen@Sun.COM * A utility function to get the value of some attribute of one of one 8658671SJulian.Pullen@Sun.COM * or more AD LDAP objects named by the dn_list; first found one wins. 8668671SJulian.Pullen@Sun.COM */ 8678671SJulian.Pullen@Sun.COM static char * 8688671SJulian.Pullen@Sun.COM ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, 8698671SJulian.Pullen@Sun.COM char **dn_list, char *attr) 8708671SJulian.Pullen@Sun.COM { 8718671SJulian.Pullen@Sun.COM int i; 8728671SJulian.Pullen@Sun.COM int rc; 8738671SJulian.Pullen@Sun.COM int scope = LDAP_SCOPE_BASE; 8748671SJulian.Pullen@Sun.COM char *attrs[2]; 8758671SJulian.Pullen@Sun.COM LDAPMessage *results = NULL; 8768671SJulian.Pullen@Sun.COM LDAPMessage *entry; 8778671SJulian.Pullen@Sun.COM char **values = NULL; 8788671SJulian.Pullen@Sun.COM char *val = NULL; 8798671SJulian.Pullen@Sun.COM 8808671SJulian.Pullen@Sun.COM attrs[0] = attr; 8818671SJulian.Pullen@Sun.COM attrs[1] = NULL; 8828671SJulian.Pullen@Sun.COM 8838671SJulian.Pullen@Sun.COM if (*ld == NULL) 8848671SJulian.Pullen@Sun.COM *ld = ldap_lookup_init(domainControllers); 8858671SJulian.Pullen@Sun.COM 8868671SJulian.Pullen@Sun.COM if (*ld == NULL) 8878671SJulian.Pullen@Sun.COM return (NULL); 8888671SJulian.Pullen@Sun.COM 8898671SJulian.Pullen@Sun.COM for (i = 0; dn_list[i] != NULL; i++) { 8908671SJulian.Pullen@Sun.COM rc = ldap_search_s(*ld, dn_list[i], scope, 8918671SJulian.Pullen@Sun.COM "(objectclass=*)", attrs, 0, &results); 8928671SJulian.Pullen@Sun.COM if (rc == LDAP_SUCCESS) { 8938671SJulian.Pullen@Sun.COM for (entry = ldap_first_entry(*ld, results); 8948671SJulian.Pullen@Sun.COM entry != NULL && values == NULL; 8958671SJulian.Pullen@Sun.COM entry = ldap_next_entry(*ld, entry)) { 8968671SJulian.Pullen@Sun.COM values = ldap_get_values( 8978671SJulian.Pullen@Sun.COM *ld, entry, attr); 8988671SJulian.Pullen@Sun.COM } 8998671SJulian.Pullen@Sun.COM 9008671SJulian.Pullen@Sun.COM if (values != NULL) { 9018671SJulian.Pullen@Sun.COM (void) ldap_msgfree(results); 9028671SJulian.Pullen@Sun.COM val = strdup(values[0]); 9038671SJulian.Pullen@Sun.COM ldap_value_free(values); 9048671SJulian.Pullen@Sun.COM return (val); 9058671SJulian.Pullen@Sun.COM } 9068671SJulian.Pullen@Sun.COM } 9078671SJulian.Pullen@Sun.COM if (results != NULL) { 9088671SJulian.Pullen@Sun.COM (void) ldap_msgfree(results); 9098671SJulian.Pullen@Sun.COM results = NULL; 9108671SJulian.Pullen@Sun.COM } 9118671SJulian.Pullen@Sun.COM } 9128671SJulian.Pullen@Sun.COM 9138671SJulian.Pullen@Sun.COM return (NULL); 9148671SJulian.Pullen@Sun.COM } 9158671SJulian.Pullen@Sun.COM 9168671SJulian.Pullen@Sun.COM 9178671SJulian.Pullen@Sun.COM /* 9188671SJulian.Pullen@Sun.COM * Lookup the trusted domains in the global catalog. 9198671SJulian.Pullen@Sun.COM * 9208671SJulian.Pullen@Sun.COM * Returns: 9218671SJulian.Pullen@Sun.COM * array of trusted domains which is terminated by 9228671SJulian.Pullen@Sun.COM * an empty trusted domain. 9238671SJulian.Pullen@Sun.COM * NULL an error occured 9248671SJulian.Pullen@Sun.COM */ 9258671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t * 9268671SJulian.Pullen@Sun.COM ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, 9278671SJulian.Pullen@Sun.COM char *base_dn) 9288671SJulian.Pullen@Sun.COM { 9298671SJulian.Pullen@Sun.COM int scope = LDAP_SCOPE_SUBTREE; 9308671SJulian.Pullen@Sun.COM char *attrs[3]; 9318671SJulian.Pullen@Sun.COM int rc; 9328671SJulian.Pullen@Sun.COM LDAPMessage *results = NULL; 9338671SJulian.Pullen@Sun.COM LDAPMessage *entry; 9348671SJulian.Pullen@Sun.COM char *filter; 9358671SJulian.Pullen@Sun.COM char **partner = NULL; 9368671SJulian.Pullen@Sun.COM char **direction = NULL; 9378671SJulian.Pullen@Sun.COM int num = 0; 9388671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t *trusted_domains = NULL; 9398671SJulian.Pullen@Sun.COM 9408671SJulian.Pullen@Sun.COM 9418671SJulian.Pullen@Sun.COM if (*ld == NULL) 9428671SJulian.Pullen@Sun.COM *ld = ldap_lookup_init(globalCatalog); 9438671SJulian.Pullen@Sun.COM 9448671SJulian.Pullen@Sun.COM if (*ld == NULL) 9458671SJulian.Pullen@Sun.COM return (NULL); 9468671SJulian.Pullen@Sun.COM 9478671SJulian.Pullen@Sun.COM attrs[0] = "trustPartner"; 9488671SJulian.Pullen@Sun.COM attrs[1] = "trustDirection"; 9498671SJulian.Pullen@Sun.COM attrs[2] = NULL; 9508671SJulian.Pullen@Sun.COM 9518671SJulian.Pullen@Sun.COM /* trustDirection values - inbound = 1 and bidirectional = 3 */ 9528671SJulian.Pullen@Sun.COM filter = "(&(objectclass=trustedDomain)" 9538671SJulian.Pullen@Sun.COM "(|(trustDirection=3)(trustDirection=1)))"; 9548671SJulian.Pullen@Sun.COM 9558671SJulian.Pullen@Sun.COM rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); 9568671SJulian.Pullen@Sun.COM if (rc == LDAP_SUCCESS) { 9578671SJulian.Pullen@Sun.COM for (entry = ldap_first_entry(*ld, results); 9588671SJulian.Pullen@Sun.COM entry != NULL; entry = ldap_next_entry(*ld, entry)) { 9598671SJulian.Pullen@Sun.COM partner = ldap_get_values(*ld, entry, "trustPartner"); 9608671SJulian.Pullen@Sun.COM direction = ldap_get_values( 9618671SJulian.Pullen@Sun.COM *ld, entry, "trustDirection"); 9628671SJulian.Pullen@Sun.COM 9638671SJulian.Pullen@Sun.COM if (partner != NULL && direction != NULL) { 9648671SJulian.Pullen@Sun.COM num++; 9658671SJulian.Pullen@Sun.COM trusted_domains = realloc(trusted_domains, 9668671SJulian.Pullen@Sun.COM (num + 1) * 9678671SJulian.Pullen@Sun.COM sizeof (ad_disc_trusteddomains_t)); 9688671SJulian.Pullen@Sun.COM if (trusted_domains == NULL) { 9698671SJulian.Pullen@Sun.COM ldap_value_free(partner); 9708671SJulian.Pullen@Sun.COM ldap_value_free(direction); 9718671SJulian.Pullen@Sun.COM ldap_msgfree(results); 9728671SJulian.Pullen@Sun.COM return (NULL); 9738671SJulian.Pullen@Sun.COM } 9748671SJulian.Pullen@Sun.COM /* Last element should be zero */ 9758671SJulian.Pullen@Sun.COM memset(&trusted_domains[num], 0, 9768671SJulian.Pullen@Sun.COM sizeof (ad_disc_trusteddomains_t)); 9778671SJulian.Pullen@Sun.COM strcpy(trusted_domains[num - 1].domain, 9788671SJulian.Pullen@Sun.COM partner[0]); 9798671SJulian.Pullen@Sun.COM trusted_domains[num - 1].direction = 9808671SJulian.Pullen@Sun.COM atoi(direction[0]); 9818671SJulian.Pullen@Sun.COM } 9828671SJulian.Pullen@Sun.COM if (partner != NULL) 9838671SJulian.Pullen@Sun.COM ldap_value_free(partner); 9848671SJulian.Pullen@Sun.COM if (direction != NULL) 9858671SJulian.Pullen@Sun.COM ldap_value_free(direction); 9868671SJulian.Pullen@Sun.COM } 9878671SJulian.Pullen@Sun.COM } else if (rc == LDAP_NO_RESULTS_RETURNED) { 9888671SJulian.Pullen@Sun.COM /* This is not an error - return empty trusted domain */ 9898671SJulian.Pullen@Sun.COM trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 9908671SJulian.Pullen@Sun.COM } 9918671SJulian.Pullen@Sun.COM if (results != NULL) 9928671SJulian.Pullen@Sun.COM ldap_msgfree(results); 9938671SJulian.Pullen@Sun.COM 9948671SJulian.Pullen@Sun.COM return (trusted_domains); 9958671SJulian.Pullen@Sun.COM } 9968671SJulian.Pullen@Sun.COM 9978671SJulian.Pullen@Sun.COM 9988671SJulian.Pullen@Sun.COM /* 9998671SJulian.Pullen@Sun.COM * This functions finds all the domains in a forest. 10008671SJulian.Pullen@Sun.COM */ 10018671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t * 10028671SJulian.Pullen@Sun.COM ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) 10038671SJulian.Pullen@Sun.COM { 10049744SJordan.Brown@Sun.COM static char *attrs[] = { 10059744SJordan.Brown@Sun.COM "objectSid", 10069744SJordan.Brown@Sun.COM NULL, 10079744SJordan.Brown@Sun.COM }; 10088671SJulian.Pullen@Sun.COM int rc; 10098671SJulian.Pullen@Sun.COM LDAPMessage *result = NULL; 10108671SJulian.Pullen@Sun.COM LDAPMessage *entry; 10119744SJordan.Brown@Sun.COM int ndomains = 0; 10129744SJordan.Brown@Sun.COM int nresults; 10138671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t *domains = NULL; 10148671SJulian.Pullen@Sun.COM 10158671SJulian.Pullen@Sun.COM if (*ld == NULL) 10168671SJulian.Pullen@Sun.COM *ld = ldap_lookup_init(globalCatalogs); 10178671SJulian.Pullen@Sun.COM 10188671SJulian.Pullen@Sun.COM if (*ld == NULL) 10198671SJulian.Pullen@Sun.COM return (NULL); 10208671SJulian.Pullen@Sun.COM 10219744SJordan.Brown@Sun.COM logger(LOG_DEBUG, "Looking for domains in forest..."); 10229744SJordan.Brown@Sun.COM /* Find domains */ 10239744SJordan.Brown@Sun.COM rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, 10249744SJordan.Brown@Sun.COM "(objectClass=Domain)", attrs, 0, &result); 10259744SJordan.Brown@Sun.COM if (rc != LDAP_SUCCESS) 10269744SJordan.Brown@Sun.COM goto err; 10279744SJordan.Brown@Sun.COM 10289744SJordan.Brown@Sun.COM nresults = ldap_count_entries(*ld, result); 10299744SJordan.Brown@Sun.COM domains = calloc(nresults + 1, sizeof (*domains)); 10309744SJordan.Brown@Sun.COM if (domains == NULL) 10319744SJordan.Brown@Sun.COM goto err; 10328671SJulian.Pullen@Sun.COM 10339744SJordan.Brown@Sun.COM for (entry = ldap_first_entry(*ld, result); 10349744SJordan.Brown@Sun.COM entry != NULL; 10359744SJordan.Brown@Sun.COM entry = ldap_next_entry(*ld, entry)) { 10369744SJordan.Brown@Sun.COM struct berval **sid_ber; 10379744SJordan.Brown@Sun.COM adutils_sid_t sid; 10389744SJordan.Brown@Sun.COM char *sid_str; 10399744SJordan.Brown@Sun.COM char *name; 10408671SJulian.Pullen@Sun.COM 10419744SJordan.Brown@Sun.COM sid_ber = ldap_get_values_len(*ld, entry, 10429744SJordan.Brown@Sun.COM "objectSid"); 10439744SJordan.Brown@Sun.COM if (sid_ber == NULL) 10449744SJordan.Brown@Sun.COM continue; 10459744SJordan.Brown@Sun.COM 10469744SJordan.Brown@Sun.COM rc = adutils_getsid(sid_ber[0], &sid); 10479744SJordan.Brown@Sun.COM ldap_value_free_len(sid_ber); 10489744SJordan.Brown@Sun.COM if (rc < 0) 10499744SJordan.Brown@Sun.COM goto err; 10508671SJulian.Pullen@Sun.COM 10519744SJordan.Brown@Sun.COM if ((sid_str = adutils_sid2txt(&sid)) == NULL) 10529744SJordan.Brown@Sun.COM goto err; 10539744SJordan.Brown@Sun.COM 10549744SJordan.Brown@Sun.COM strcpy(domains[ndomains].sid, sid_str); 10559744SJordan.Brown@Sun.COM free(sid_str); 10569744SJordan.Brown@Sun.COM 10579744SJordan.Brown@Sun.COM name = DN_to_DNS(ldap_get_dn(*ld, entry)); 10589744SJordan.Brown@Sun.COM if (name == NULL) 10599744SJordan.Brown@Sun.COM goto err; 10609744SJordan.Brown@Sun.COM 10619744SJordan.Brown@Sun.COM strcpy(domains[ndomains].domain, name); 10629744SJordan.Brown@Sun.COM free(name); 10639744SJordan.Brown@Sun.COM 10649744SJordan.Brown@Sun.COM logger(LOG_DEBUG, " found %s", domains[ndomains].domain); 10659744SJordan.Brown@Sun.COM 10669744SJordan.Brown@Sun.COM ndomains++; 10678671SJulian.Pullen@Sun.COM } 10689744SJordan.Brown@Sun.COM 10699744SJordan.Brown@Sun.COM if (ndomains == 0) 10709744SJordan.Brown@Sun.COM goto err; 10719744SJordan.Brown@Sun.COM 10729744SJordan.Brown@Sun.COM if (ndomains < nresults) { 10739744SJordan.Brown@Sun.COM ad_disc_domainsinforest_t *tmp; 1074*10122SJordan.Brown@Sun.COM tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); 10759744SJordan.Brown@Sun.COM if (tmp == NULL) 10769744SJordan.Brown@Sun.COM goto err; 10779744SJordan.Brown@Sun.COM domains = tmp; 10789744SJordan.Brown@Sun.COM } 10799744SJordan.Brown@Sun.COM 10808671SJulian.Pullen@Sun.COM if (result != NULL) 10818671SJulian.Pullen@Sun.COM ldap_msgfree(result); 10828671SJulian.Pullen@Sun.COM 10838671SJulian.Pullen@Sun.COM return (domains); 10849744SJordan.Brown@Sun.COM 10859744SJordan.Brown@Sun.COM err: 10869744SJordan.Brown@Sun.COM free(domains); 10879744SJordan.Brown@Sun.COM if (result != NULL) 10889744SJordan.Brown@Sun.COM ldap_msgfree(result); 10899744SJordan.Brown@Sun.COM return (NULL); 10908671SJulian.Pullen@Sun.COM } 10918671SJulian.Pullen@Sun.COM 10928671SJulian.Pullen@Sun.COM 10938671SJulian.Pullen@Sun.COM ad_disc_t 10948671SJulian.Pullen@Sun.COM ad_disc_init(void) 10958671SJulian.Pullen@Sun.COM { 10968671SJulian.Pullen@Sun.COM struct ad_disc *ctx; 10978671SJulian.Pullen@Sun.COM ctx = calloc(1, sizeof (struct ad_disc)); 10988671SJulian.Pullen@Sun.COM if (ctx != NULL) 10998671SJulian.Pullen@Sun.COM DO_RES_NINIT(ctx); 11008671SJulian.Pullen@Sun.COM 11018671SJulian.Pullen@Sun.COM ctx->domain_name.type = AD_STRING; 11028671SJulian.Pullen@Sun.COM ctx->domain_controller.type = AD_DIRECTORY; 11038671SJulian.Pullen@Sun.COM ctx->site_name.type = AD_STRING; 11048671SJulian.Pullen@Sun.COM ctx->forest_name.type = AD_STRING; 11058671SJulian.Pullen@Sun.COM ctx->global_catalog.type = AD_DIRECTORY; 11068671SJulian.Pullen@Sun.COM ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 11078671SJulian.Pullen@Sun.COM ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 11088671SJulian.Pullen@Sun.COM /* Site specific versions */ 11098671SJulian.Pullen@Sun.COM ctx->site_domain_controller.type = AD_DIRECTORY; 11108671SJulian.Pullen@Sun.COM ctx->site_global_catalog.type = AD_DIRECTORY; 11118671SJulian.Pullen@Sun.COM return (ctx); 11128671SJulian.Pullen@Sun.COM } 11138671SJulian.Pullen@Sun.COM 11148671SJulian.Pullen@Sun.COM 11158671SJulian.Pullen@Sun.COM void 11168671SJulian.Pullen@Sun.COM ad_disc_fini(ad_disc_t ctx) 11178671SJulian.Pullen@Sun.COM { 11188671SJulian.Pullen@Sun.COM if (ctx == NULL) 11198671SJulian.Pullen@Sun.COM return; 11208671SJulian.Pullen@Sun.COM 11218671SJulian.Pullen@Sun.COM if (ctx->res_ninitted) 11228671SJulian.Pullen@Sun.COM res_ndestroy(&ctx->res_state); 11238671SJulian.Pullen@Sun.COM 11248671SJulian.Pullen@Sun.COM if (ctx->subnets != NULL) 11258671SJulian.Pullen@Sun.COM free(ctx->subnets); 11268671SJulian.Pullen@Sun.COM 11278671SJulian.Pullen@Sun.COM if (ctx->domain_name.value != NULL) 11288671SJulian.Pullen@Sun.COM free(ctx->domain_name.value); 11298671SJulian.Pullen@Sun.COM 11308671SJulian.Pullen@Sun.COM if (ctx->domain_controller.value != NULL) 11318671SJulian.Pullen@Sun.COM free(ctx->domain_controller.value); 11328671SJulian.Pullen@Sun.COM 11338671SJulian.Pullen@Sun.COM if (ctx->site_name.value != NULL) 11348671SJulian.Pullen@Sun.COM free(ctx->site_name.value); 11358671SJulian.Pullen@Sun.COM 11368671SJulian.Pullen@Sun.COM if (ctx->forest_name.value != NULL) 11378671SJulian.Pullen@Sun.COM free(ctx->forest_name.value); 11388671SJulian.Pullen@Sun.COM 11398671SJulian.Pullen@Sun.COM if (ctx->global_catalog.value != NULL) 11408671SJulian.Pullen@Sun.COM free(ctx->global_catalog.value); 11418671SJulian.Pullen@Sun.COM 11428671SJulian.Pullen@Sun.COM if (ctx->domains_in_forest.value != NULL) 11438671SJulian.Pullen@Sun.COM free(ctx->domains_in_forest.value); 11448671SJulian.Pullen@Sun.COM 11458671SJulian.Pullen@Sun.COM if (ctx->trusted_domains.value != NULL) 11468671SJulian.Pullen@Sun.COM free(ctx->trusted_domains.value); 11478671SJulian.Pullen@Sun.COM 11488671SJulian.Pullen@Sun.COM /* Site specific versions */ 11498671SJulian.Pullen@Sun.COM if (ctx->site_domain_controller.value != NULL) 11508671SJulian.Pullen@Sun.COM free(ctx->site_domain_controller.value); 11518671SJulian.Pullen@Sun.COM 11528671SJulian.Pullen@Sun.COM if (ctx->site_global_catalog.value != NULL) 11538671SJulian.Pullen@Sun.COM free(ctx->site_global_catalog.value); 11548671SJulian.Pullen@Sun.COM 11558671SJulian.Pullen@Sun.COM free(ctx); 11568671SJulian.Pullen@Sun.COM } 11578671SJulian.Pullen@Sun.COM 11588671SJulian.Pullen@Sun.COM void 11598671SJulian.Pullen@Sun.COM ad_disc_refresh(ad_disc_t ctx) 11608671SJulian.Pullen@Sun.COM { 11618671SJulian.Pullen@Sun.COM if (ctx->res_ninitted) 11628671SJulian.Pullen@Sun.COM res_ndestroy(&ctx->res_state); 11638671SJulian.Pullen@Sun.COM (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 11648671SJulian.Pullen@Sun.COM ctx->res_ninitted = res_ninit(&ctx->res_state) != -1; 11658671SJulian.Pullen@Sun.COM 11668671SJulian.Pullen@Sun.COM if (ctx->domain_name.state == AD_STATE_AUTO) 11678671SJulian.Pullen@Sun.COM ctx->domain_name.state = AD_STATE_INVALID; 11688671SJulian.Pullen@Sun.COM 11698671SJulian.Pullen@Sun.COM if (ctx->domain_controller.state == AD_STATE_AUTO) 11708671SJulian.Pullen@Sun.COM ctx->domain_controller.state = AD_STATE_INVALID; 11718671SJulian.Pullen@Sun.COM 11728671SJulian.Pullen@Sun.COM if (ctx->site_name.state == AD_STATE_AUTO) 11738671SJulian.Pullen@Sun.COM ctx->site_name.state = AD_STATE_INVALID; 11748671SJulian.Pullen@Sun.COM 11758671SJulian.Pullen@Sun.COM if (ctx->forest_name.state == AD_STATE_AUTO) 11768671SJulian.Pullen@Sun.COM ctx->forest_name.state = AD_STATE_INVALID; 11778671SJulian.Pullen@Sun.COM 11788671SJulian.Pullen@Sun.COM if (ctx->global_catalog.state == AD_STATE_AUTO) 11798671SJulian.Pullen@Sun.COM ctx->global_catalog.state = AD_STATE_INVALID; 11808671SJulian.Pullen@Sun.COM 11818671SJulian.Pullen@Sun.COM if (ctx->domains_in_forest.state == AD_STATE_AUTO) 11828671SJulian.Pullen@Sun.COM ctx->domains_in_forest.state = AD_STATE_INVALID; 11838671SJulian.Pullen@Sun.COM 11848671SJulian.Pullen@Sun.COM if (ctx->trusted_domains.state == AD_STATE_AUTO) 11858671SJulian.Pullen@Sun.COM ctx->trusted_domains.state = AD_STATE_INVALID; 11868671SJulian.Pullen@Sun.COM 11878671SJulian.Pullen@Sun.COM if (ctx->site_domain_controller.state == AD_STATE_AUTO) 11888671SJulian.Pullen@Sun.COM ctx->site_domain_controller.state = AD_STATE_INVALID; 11898671SJulian.Pullen@Sun.COM 11908671SJulian.Pullen@Sun.COM if (ctx->site_global_catalog.state == AD_STATE_AUTO) 11918671SJulian.Pullen@Sun.COM ctx->site_global_catalog.state = AD_STATE_INVALID; 11928671SJulian.Pullen@Sun.COM } 11938671SJulian.Pullen@Sun.COM 11948671SJulian.Pullen@Sun.COM 11958671SJulian.Pullen@Sun.COM 11968671SJulian.Pullen@Sun.COM /* Discover joined Active Directory domainName */ 11978671SJulian.Pullen@Sun.COM static ad_item_t * 11988671SJulian.Pullen@Sun.COM validate_DomainName(ad_disc_t ctx) 11998671SJulian.Pullen@Sun.COM { 12008671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *domain_controller = NULL; 12018671SJulian.Pullen@Sun.COM char *dname, *srvname; 12028671SJulian.Pullen@Sun.COM uint32_t ttl = 0; 12039744SJordan.Brown@Sun.COM int len; 12048671SJulian.Pullen@Sun.COM 12058671SJulian.Pullen@Sun.COM if (is_valid(&ctx->domain_name)) 12068671SJulian.Pullen@Sun.COM return (&ctx->domain_name); 12078671SJulian.Pullen@Sun.COM 12088671SJulian.Pullen@Sun.COM 12098671SJulian.Pullen@Sun.COM /* Try to find our domain by searching for DCs for it */ 12108671SJulian.Pullen@Sun.COM DO_RES_NINIT(ctx); 12118671SJulian.Pullen@Sun.COM domain_controller = srv_query(&ctx->res_state, LDAP_SRV_HEAD 12128671SJulian.Pullen@Sun.COM DC_SRV_TAIL, ctx->domain_name.value, &srvname, &ttl); 12138671SJulian.Pullen@Sun.COM 12148671SJulian.Pullen@Sun.COM /* 12158671SJulian.Pullen@Sun.COM * If we can't find DCs by via res_nsearch() then there's no 12168671SJulian.Pullen@Sun.COM * point in trying anything else to discover the AD domain name. 12178671SJulian.Pullen@Sun.COM */ 12188671SJulian.Pullen@Sun.COM if (domain_controller == NULL) 12198671SJulian.Pullen@Sun.COM return (NULL); 12208671SJulian.Pullen@Sun.COM 12218671SJulian.Pullen@Sun.COM free(domain_controller); 12228671SJulian.Pullen@Sun.COM /* 12238671SJulian.Pullen@Sun.COM * We have the FQDN of the SRV RR name, so now we extract the 12248671SJulian.Pullen@Sun.COM * domainname suffix from it. 12258671SJulian.Pullen@Sun.COM */ 12268671SJulian.Pullen@Sun.COM dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 12278671SJulian.Pullen@Sun.COM 1 /* for the dot between RR name and domainname */); 12288671SJulian.Pullen@Sun.COM 12298671SJulian.Pullen@Sun.COM free(srvname); 12308671SJulian.Pullen@Sun.COM 12318671SJulian.Pullen@Sun.COM if (dname == NULL) { 12328671SJulian.Pullen@Sun.COM logger(LOG_ERR, "Out of memory"); 12338671SJulian.Pullen@Sun.COM return (NULL); 12348671SJulian.Pullen@Sun.COM } 12358671SJulian.Pullen@Sun.COM 12368671SJulian.Pullen@Sun.COM /* Eat any trailing dot */ 12379744SJordan.Brown@Sun.COM len = strlen(dname); 1238*10122SJordan.Brown@Sun.COM if (len > 0 && dname[len - 1] == '.') 1239*10122SJordan.Brown@Sun.COM dname[len - 1] = '\0'; 12408671SJulian.Pullen@Sun.COM 12418671SJulian.Pullen@Sun.COM update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl); 12428671SJulian.Pullen@Sun.COM 12438671SJulian.Pullen@Sun.COM return (&ctx->domain_name); 12448671SJulian.Pullen@Sun.COM } 12458671SJulian.Pullen@Sun.COM 12468671SJulian.Pullen@Sun.COM 12478671SJulian.Pullen@Sun.COM char * 12488671SJulian.Pullen@Sun.COM ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 12498671SJulian.Pullen@Sun.COM { 12508671SJulian.Pullen@Sun.COM char *domain_name = NULL; 12518671SJulian.Pullen@Sun.COM ad_item_t *domain_name_item; 12528671SJulian.Pullen@Sun.COM 12538671SJulian.Pullen@Sun.COM domain_name_item = validate_DomainName(ctx); 12548671SJulian.Pullen@Sun.COM 12558671SJulian.Pullen@Sun.COM if (domain_name_item) { 12568671SJulian.Pullen@Sun.COM domain_name = strdup(domain_name_item->value); 12578671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 12588671SJulian.Pullen@Sun.COM *auto_discovered = 12598671SJulian.Pullen@Sun.COM (domain_name_item->state == AD_STATE_AUTO); 12608671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 12618671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 12628671SJulian.Pullen@Sun.COM 12638671SJulian.Pullen@Sun.COM return (domain_name); 12648671SJulian.Pullen@Sun.COM } 12658671SJulian.Pullen@Sun.COM 12668671SJulian.Pullen@Sun.COM 12678671SJulian.Pullen@Sun.COM /* Discover domain controllers */ 12688671SJulian.Pullen@Sun.COM static ad_item_t * 12698671SJulian.Pullen@Sun.COM validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 12708671SJulian.Pullen@Sun.COM { 12718671SJulian.Pullen@Sun.COM uint32_t ttl = 0; 12728671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *domain_controller = NULL; 12738671SJulian.Pullen@Sun.COM boolean_t validate_global = B_FALSE; 12748671SJulian.Pullen@Sun.COM boolean_t validate_site = B_FALSE; 12758671SJulian.Pullen@Sun.COM ad_item_t *domain_name_item; 12768671SJulian.Pullen@Sun.COM ad_item_t *site_name_item = NULL; 12778671SJulian.Pullen@Sun.COM 12788671SJulian.Pullen@Sun.COM /* If the values is fixed there will not be a site specific version */ 12798671SJulian.Pullen@Sun.COM if (is_fixed(&ctx->domain_controller)) 12808671SJulian.Pullen@Sun.COM return (&ctx->domain_controller); 12818671SJulian.Pullen@Sun.COM 12828671SJulian.Pullen@Sun.COM domain_name_item = validate_DomainName(ctx); 12838671SJulian.Pullen@Sun.COM if (domain_name_item == NULL) 12848671SJulian.Pullen@Sun.COM return (NULL); 12858671SJulian.Pullen@Sun.COM 12868671SJulian.Pullen@Sun.COM if (req == AD_DISC_GLOBAL) 12878671SJulian.Pullen@Sun.COM validate_global = B_TRUE; 12888671SJulian.Pullen@Sun.COM else { 12898671SJulian.Pullen@Sun.COM site_name_item = validate_SiteName(ctx); 12908671SJulian.Pullen@Sun.COM if (site_name_item != NULL) 12918671SJulian.Pullen@Sun.COM validate_site = B_TRUE; 12928671SJulian.Pullen@Sun.COM else if (req == AD_DISC_PREFER_SITE) 12938671SJulian.Pullen@Sun.COM validate_global = B_TRUE; 12948671SJulian.Pullen@Sun.COM } 12958671SJulian.Pullen@Sun.COM 12968671SJulian.Pullen@Sun.COM if (validate_global) { 12978671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->domain_controller) || 12988671SJulian.Pullen@Sun.COM is_changed(&ctx->domain_controller, PARAM1, 12998671SJulian.Pullen@Sun.COM domain_name_item)) { 13008671SJulian.Pullen@Sun.COM /* 13018671SJulian.Pullen@Sun.COM * Lookup DNS SRV RR named 13028671SJulian.Pullen@Sun.COM * _ldap._tcp.dc._msdcs.<DomainName> 13038671SJulian.Pullen@Sun.COM */ 13048671SJulian.Pullen@Sun.COM DO_RES_NINIT(ctx); 13058671SJulian.Pullen@Sun.COM domain_controller = srv_query(&ctx->res_state, 13068671SJulian.Pullen@Sun.COM LDAP_SRV_HEAD DC_SRV_TAIL, 13078671SJulian.Pullen@Sun.COM domain_name_item->value, NULL, &ttl); 13088671SJulian.Pullen@Sun.COM 13098671SJulian.Pullen@Sun.COM if (domain_controller == NULL) 13108671SJulian.Pullen@Sun.COM return (NULL); 13118671SJulian.Pullen@Sun.COM 13128671SJulian.Pullen@Sun.COM update_item(&ctx->domain_controller, domain_controller, 13138671SJulian.Pullen@Sun.COM AD_STATE_AUTO, ttl); 13148671SJulian.Pullen@Sun.COM update_version(&ctx->domain_controller, PARAM1, 13158671SJulian.Pullen@Sun.COM domain_name_item); 13168671SJulian.Pullen@Sun.COM } 13178671SJulian.Pullen@Sun.COM return (&ctx->domain_controller); 13188671SJulian.Pullen@Sun.COM } 13198671SJulian.Pullen@Sun.COM 13208671SJulian.Pullen@Sun.COM if (validate_site) { 13218671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->site_domain_controller) || 13228671SJulian.Pullen@Sun.COM is_changed(&ctx->site_domain_controller, PARAM1, 13238671SJulian.Pullen@Sun.COM domain_name_item) || 13248671SJulian.Pullen@Sun.COM is_changed(&ctx->site_domain_controller, PARAM2, 13258671SJulian.Pullen@Sun.COM site_name_item)) { 13268671SJulian.Pullen@Sun.COM char rr_name[DNS_MAX_NAME]; 13278671SJulian.Pullen@Sun.COM /* 13288671SJulian.Pullen@Sun.COM * Lookup DNS SRV RR named 13298671SJulian.Pullen@Sun.COM * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 13308671SJulian.Pullen@Sun.COM */ 13318671SJulian.Pullen@Sun.COM (void) snprintf(rr_name, sizeof (rr_name), 13328671SJulian.Pullen@Sun.COM LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 13338671SJulian.Pullen@Sun.COM site_name_item->value); 13348671SJulian.Pullen@Sun.COM DO_RES_NINIT(ctx); 13358671SJulian.Pullen@Sun.COM domain_controller = srv_query(&ctx->res_state, rr_name, 13368671SJulian.Pullen@Sun.COM domain_name_item->value, NULL, &ttl); 13378671SJulian.Pullen@Sun.COM if (domain_controller == NULL) 13388671SJulian.Pullen@Sun.COM return (NULL); 13398671SJulian.Pullen@Sun.COM 13408671SJulian.Pullen@Sun.COM update_item(&ctx->site_domain_controller, 13418671SJulian.Pullen@Sun.COM domain_controller, AD_STATE_AUTO, ttl); 13428671SJulian.Pullen@Sun.COM update_version(&ctx->site_domain_controller, PARAM1, 13438671SJulian.Pullen@Sun.COM domain_name_item); 13448671SJulian.Pullen@Sun.COM update_version(&ctx->site_domain_controller, PARAM2, 13458671SJulian.Pullen@Sun.COM site_name_item); 13468671SJulian.Pullen@Sun.COM } 13478671SJulian.Pullen@Sun.COM return (&ctx->site_domain_controller); 13488671SJulian.Pullen@Sun.COM } 13498671SJulian.Pullen@Sun.COM return (NULL); 13508671SJulian.Pullen@Sun.COM } 13518671SJulian.Pullen@Sun.COM 13528671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t * 13538671SJulian.Pullen@Sun.COM ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 13548671SJulian.Pullen@Sun.COM boolean_t *auto_discovered) 13558671SJulian.Pullen@Sun.COM { 13568671SJulian.Pullen@Sun.COM ad_item_t *domain_controller_item; 13578671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *domain_controller = NULL; 13588671SJulian.Pullen@Sun.COM 13598671SJulian.Pullen@Sun.COM domain_controller_item = validate_DomainController(ctx, req); 13608671SJulian.Pullen@Sun.COM 13618671SJulian.Pullen@Sun.COM if (domain_controller_item != NULL) { 13628671SJulian.Pullen@Sun.COM domain_controller = ds_dup(domain_controller_item->value); 13638671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 13648671SJulian.Pullen@Sun.COM *auto_discovered = 13658671SJulian.Pullen@Sun.COM (domain_controller_item->state == AD_STATE_AUTO); 13668671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 13678671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 13688671SJulian.Pullen@Sun.COM 13698671SJulian.Pullen@Sun.COM return (domain_controller); 13708671SJulian.Pullen@Sun.COM } 13718671SJulian.Pullen@Sun.COM 13728671SJulian.Pullen@Sun.COM 13738671SJulian.Pullen@Sun.COM /* Discover site name (for multi-homed systems the first one found wins) */ 13748671SJulian.Pullen@Sun.COM static ad_item_t * 13758671SJulian.Pullen@Sun.COM validate_SiteName(ad_disc_t ctx) 13768671SJulian.Pullen@Sun.COM { 13778671SJulian.Pullen@Sun.COM LDAP *ld = NULL; 13788671SJulian.Pullen@Sun.COM ad_subnet_t *subnets = NULL; 13798671SJulian.Pullen@Sun.COM char **dn_subnets = NULL; 13808671SJulian.Pullen@Sun.COM char *dn_root[2]; 13818671SJulian.Pullen@Sun.COM char *config_naming_context = NULL; 13828671SJulian.Pullen@Sun.COM char *site_object = NULL; 13838671SJulian.Pullen@Sun.COM char *site_name = NULL; 13848671SJulian.Pullen@Sun.COM char *forest_name; 13858671SJulian.Pullen@Sun.COM int len; 13868671SJulian.Pullen@Sun.COM int i; 13878671SJulian.Pullen@Sun.COM boolean_t update_required = B_FALSE; 13888671SJulian.Pullen@Sun.COM ad_item_t *domain_controller_item; 13898671SJulian.Pullen@Sun.COM 13908671SJulian.Pullen@Sun.COM if (is_fixed(&ctx->site_name)) 13918671SJulian.Pullen@Sun.COM return (&ctx->site_name); 13928671SJulian.Pullen@Sun.COM 13938671SJulian.Pullen@Sun.COM /* Can't rely on site-specific DCs */ 13948671SJulian.Pullen@Sun.COM domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 13958671SJulian.Pullen@Sun.COM if (domain_controller_item == NULL) 13968671SJulian.Pullen@Sun.COM return (NULL); 13978671SJulian.Pullen@Sun.COM 13988671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->site_name) || 13998671SJulian.Pullen@Sun.COM is_changed(&ctx->site_name, PARAM1, &ctx->domain_controller) || 14008671SJulian.Pullen@Sun.COM ctx->subnets == NULL || ctx->subnets_changed) { 14018671SJulian.Pullen@Sun.COM subnets = find_subnets(); 14028671SJulian.Pullen@Sun.COM ctx->subnets_last_check = time(NULL); 14038671SJulian.Pullen@Sun.COM update_required = B_TRUE; 14048671SJulian.Pullen@Sun.COM } else if (ctx->subnets_last_check + 60 < time(NULL)) { 14058671SJulian.Pullen@Sun.COM subnets = find_subnets(); 14068671SJulian.Pullen@Sun.COM ctx->subnets_last_check = time(NULL); 14078671SJulian.Pullen@Sun.COM if (cmpsubnets(ctx->subnets, subnets) != 0) 14088671SJulian.Pullen@Sun.COM update_required = B_TRUE; 14098671SJulian.Pullen@Sun.COM } 14108671SJulian.Pullen@Sun.COM 14118671SJulian.Pullen@Sun.COM if (!update_required) { 14128671SJulian.Pullen@Sun.COM free(subnets); 14138671SJulian.Pullen@Sun.COM return (&ctx->site_name); 14148671SJulian.Pullen@Sun.COM } 14158671SJulian.Pullen@Sun.COM 14168671SJulian.Pullen@Sun.COM if (subnets == NULL) 14178671SJulian.Pullen@Sun.COM return (NULL); 14188671SJulian.Pullen@Sun.COM 14198671SJulian.Pullen@Sun.COM dn_root[0] = ""; 14208671SJulian.Pullen@Sun.COM dn_root[1] = NULL; 14218671SJulian.Pullen@Sun.COM 14228671SJulian.Pullen@Sun.COM config_naming_context = ldap_lookup_entry_attr( 14238671SJulian.Pullen@Sun.COM &ld, ctx->domain_controller.value, 14248671SJulian.Pullen@Sun.COM dn_root, "configurationNamingContext"); 14258671SJulian.Pullen@Sun.COM if (config_naming_context == NULL) 14268671SJulian.Pullen@Sun.COM goto out; 14278671SJulian.Pullen@Sun.COM /* 14288671SJulian.Pullen@Sun.COM * configurationNamingContext also provides the Forest 14298671SJulian.Pullen@Sun.COM * Name. 14308671SJulian.Pullen@Sun.COM */ 14318671SJulian.Pullen@Sun.COM if (!is_fixed(&ctx->forest_name)) { 14328671SJulian.Pullen@Sun.COM /* 14338671SJulian.Pullen@Sun.COM * The configurationNamingContext should be of 14348671SJulian.Pullen@Sun.COM * form: 14358671SJulian.Pullen@Sun.COM * CN=Configuration,<DNforestName> 14368671SJulian.Pullen@Sun.COM * Remove the first part and convert to DNS form 14378671SJulian.Pullen@Sun.COM * (replace ",DC=" with ".") 14388671SJulian.Pullen@Sun.COM */ 14398671SJulian.Pullen@Sun.COM char *str = "CN=Configuration,"; 14408671SJulian.Pullen@Sun.COM int len = strlen(str); 14418671SJulian.Pullen@Sun.COM if (strncasecmp(config_naming_context, str, len) == 0) { 14428671SJulian.Pullen@Sun.COM forest_name = DN_to_DNS(config_naming_context + len); 14438671SJulian.Pullen@Sun.COM update_item(&ctx->forest_name, forest_name, 14448671SJulian.Pullen@Sun.COM AD_STATE_AUTO, 0); 14458671SJulian.Pullen@Sun.COM } 14468671SJulian.Pullen@Sun.COM } 14478671SJulian.Pullen@Sun.COM 14488671SJulian.Pullen@Sun.COM dn_subnets = subnets_to_DNs(subnets, config_naming_context); 14498671SJulian.Pullen@Sun.COM if (dn_subnets == NULL) 14508671SJulian.Pullen@Sun.COM goto out; 14518671SJulian.Pullen@Sun.COM 14528671SJulian.Pullen@Sun.COM site_object = ldap_lookup_entry_attr( 14538671SJulian.Pullen@Sun.COM &ld, domain_controller_item->value, 14548671SJulian.Pullen@Sun.COM dn_subnets, "siteobject"); 14558671SJulian.Pullen@Sun.COM if (site_object != NULL) { 14568671SJulian.Pullen@Sun.COM /* 14578671SJulian.Pullen@Sun.COM * The site object should be of the form 14588671SJulian.Pullen@Sun.COM * CN=<site>,CN=Sites,CN=Configuration, 14598671SJulian.Pullen@Sun.COM * <DN Domain> 14608671SJulian.Pullen@Sun.COM */ 14618671SJulian.Pullen@Sun.COM if (strncasecmp(site_object, "CN=", 3) == 0) { 14628671SJulian.Pullen@Sun.COM for (len = 0; site_object[len + 3] != ','; len++) 14638671SJulian.Pullen@Sun.COM ; 14648671SJulian.Pullen@Sun.COM site_name = malloc(len + 1); 14658671SJulian.Pullen@Sun.COM (void) strncpy(site_name, &site_object[3], len); 14668671SJulian.Pullen@Sun.COM site_name[len] = '\0'; 14678671SJulian.Pullen@Sun.COM update_item(&ctx->site_name, site_name, 14688671SJulian.Pullen@Sun.COM AD_STATE_AUTO, 0); 14698671SJulian.Pullen@Sun.COM } 14708671SJulian.Pullen@Sun.COM } 14718671SJulian.Pullen@Sun.COM 14728671SJulian.Pullen@Sun.COM if (ctx->subnets != NULL) { 14738671SJulian.Pullen@Sun.COM free(ctx->subnets); 14748671SJulian.Pullen@Sun.COM ctx->subnets = NULL; 14758671SJulian.Pullen@Sun.COM } 14768671SJulian.Pullen@Sun.COM ctx->subnets = subnets; 14778671SJulian.Pullen@Sun.COM subnets = NULL; 14788671SJulian.Pullen@Sun.COM ctx->subnets_changed = B_FALSE; 14798671SJulian.Pullen@Sun.COM 14808671SJulian.Pullen@Sun.COM out: 14818671SJulian.Pullen@Sun.COM if (ld != NULL) 14828671SJulian.Pullen@Sun.COM (void) ldap_unbind(ld); 14838671SJulian.Pullen@Sun.COM 14848671SJulian.Pullen@Sun.COM if (dn_subnets != NULL) { 14858671SJulian.Pullen@Sun.COM for (i = 0; dn_subnets[i] != NULL; i++) 14868671SJulian.Pullen@Sun.COM free(dn_subnets[i]); 14878671SJulian.Pullen@Sun.COM free(dn_subnets); 14888671SJulian.Pullen@Sun.COM } 14898671SJulian.Pullen@Sun.COM if (config_naming_context != NULL) 14908671SJulian.Pullen@Sun.COM free(config_naming_context); 14918671SJulian.Pullen@Sun.COM if (site_object != NULL) 14928671SJulian.Pullen@Sun.COM free(site_object); 14938671SJulian.Pullen@Sun.COM 14948671SJulian.Pullen@Sun.COM free(subnets); 14958671SJulian.Pullen@Sun.COM if (site_name == NULL) 14968671SJulian.Pullen@Sun.COM return (NULL); 14978671SJulian.Pullen@Sun.COM return (&ctx->site_name); 14988671SJulian.Pullen@Sun.COM 14998671SJulian.Pullen@Sun.COM } 15008671SJulian.Pullen@Sun.COM 15018671SJulian.Pullen@Sun.COM 15028671SJulian.Pullen@Sun.COM char * 15038671SJulian.Pullen@Sun.COM ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 15048671SJulian.Pullen@Sun.COM { 15058671SJulian.Pullen@Sun.COM ad_item_t *site_name_item; 15068671SJulian.Pullen@Sun.COM char *site_name = NULL; 15078671SJulian.Pullen@Sun.COM 15088671SJulian.Pullen@Sun.COM site_name_item = validate_SiteName(ctx); 15098671SJulian.Pullen@Sun.COM if (site_name_item != NULL) { 15108671SJulian.Pullen@Sun.COM site_name = strdup(site_name_item->value); 15118671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 15128671SJulian.Pullen@Sun.COM *auto_discovered = 15138671SJulian.Pullen@Sun.COM (site_name_item->state == AD_STATE_AUTO); 15148671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 15158671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 15168671SJulian.Pullen@Sun.COM 15178671SJulian.Pullen@Sun.COM return (site_name); 15188671SJulian.Pullen@Sun.COM } 15198671SJulian.Pullen@Sun.COM 15208671SJulian.Pullen@Sun.COM 15218671SJulian.Pullen@Sun.COM 15228671SJulian.Pullen@Sun.COM /* Discover forest name */ 15238671SJulian.Pullen@Sun.COM static ad_item_t * 15248671SJulian.Pullen@Sun.COM validate_ForestName(ad_disc_t ctx) 15258671SJulian.Pullen@Sun.COM { 15268671SJulian.Pullen@Sun.COM LDAP *ld = NULL; 15278671SJulian.Pullen@Sun.COM char *config_naming_context; 15288671SJulian.Pullen@Sun.COM char *forest_name = NULL; 15298671SJulian.Pullen@Sun.COM char *dn_list[2]; 15308671SJulian.Pullen@Sun.COM ad_item_t *domain_controller_item; 15318671SJulian.Pullen@Sun.COM 15328671SJulian.Pullen@Sun.COM if (is_fixed(&ctx->forest_name)) 15338671SJulian.Pullen@Sun.COM return (&ctx->forest_name); 15348671SJulian.Pullen@Sun.COM /* 15358671SJulian.Pullen@Sun.COM * We may not have a site name yet, so we won't rely on 15368671SJulian.Pullen@Sun.COM * site-specific DCs. (But maybe we could replace 15378671SJulian.Pullen@Sun.COM * validate_ForestName() with validate_siteName()?) 15388671SJulian.Pullen@Sun.COM */ 15398671SJulian.Pullen@Sun.COM domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 15408671SJulian.Pullen@Sun.COM if (domain_controller_item == NULL) 15418671SJulian.Pullen@Sun.COM return (NULL); 15428671SJulian.Pullen@Sun.COM 15438671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->forest_name) || 15448671SJulian.Pullen@Sun.COM is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) { 15458671SJulian.Pullen@Sun.COM 15468671SJulian.Pullen@Sun.COM dn_list[0] = ""; 15478671SJulian.Pullen@Sun.COM dn_list[1] = NULL; 15488671SJulian.Pullen@Sun.COM config_naming_context = ldap_lookup_entry_attr( 15498671SJulian.Pullen@Sun.COM &ld, ctx->domain_controller.value, 15508671SJulian.Pullen@Sun.COM dn_list, "configurationNamingContext"); 15518671SJulian.Pullen@Sun.COM if (config_naming_context != NULL) { 15528671SJulian.Pullen@Sun.COM /* 15538671SJulian.Pullen@Sun.COM * The configurationNamingContext should be of 15548671SJulian.Pullen@Sun.COM * form: 15558671SJulian.Pullen@Sun.COM * CN=Configuration,<DNforestName> 15568671SJulian.Pullen@Sun.COM * Remove the first part and convert to DNS form 15578671SJulian.Pullen@Sun.COM * (replace ",DC=" with ".") 15588671SJulian.Pullen@Sun.COM */ 15598671SJulian.Pullen@Sun.COM char *str = "CN=Configuration,"; 15608671SJulian.Pullen@Sun.COM int len = strlen(str); 15618671SJulian.Pullen@Sun.COM if (strncasecmp(config_naming_context, str, len) == 0) { 15628671SJulian.Pullen@Sun.COM forest_name = DN_to_DNS( 15638671SJulian.Pullen@Sun.COM config_naming_context + len); 15648671SJulian.Pullen@Sun.COM } 15658671SJulian.Pullen@Sun.COM free(config_naming_context); 15668671SJulian.Pullen@Sun.COM } 15678671SJulian.Pullen@Sun.COM if (ld != NULL) 15688671SJulian.Pullen@Sun.COM (void) ldap_unbind(ld); 15698671SJulian.Pullen@Sun.COM 15708671SJulian.Pullen@Sun.COM if (forest_name == NULL) 15718671SJulian.Pullen@Sun.COM return (NULL); 15728671SJulian.Pullen@Sun.COM 15738671SJulian.Pullen@Sun.COM update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 15748671SJulian.Pullen@Sun.COM update_version(&ctx->forest_name, PARAM1, 15758671SJulian.Pullen@Sun.COM domain_controller_item); 15768671SJulian.Pullen@Sun.COM } 15778671SJulian.Pullen@Sun.COM return (&ctx->forest_name); 15788671SJulian.Pullen@Sun.COM } 15798671SJulian.Pullen@Sun.COM 15808671SJulian.Pullen@Sun.COM 15818671SJulian.Pullen@Sun.COM char * 15828671SJulian.Pullen@Sun.COM ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 15838671SJulian.Pullen@Sun.COM { 15848671SJulian.Pullen@Sun.COM ad_item_t *forest_name_item; 15858671SJulian.Pullen@Sun.COM char *forest_name = NULL; 15868671SJulian.Pullen@Sun.COM 15878671SJulian.Pullen@Sun.COM forest_name_item = validate_ForestName(ctx); 15888671SJulian.Pullen@Sun.COM 15898671SJulian.Pullen@Sun.COM if (forest_name_item != NULL) { 15908671SJulian.Pullen@Sun.COM forest_name = strdup(forest_name_item->value); 15918671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 15928671SJulian.Pullen@Sun.COM *auto_discovered = 15938671SJulian.Pullen@Sun.COM (forest_name_item->state == AD_STATE_AUTO); 15948671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 15958671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 15968671SJulian.Pullen@Sun.COM 15978671SJulian.Pullen@Sun.COM return (forest_name); 15988671SJulian.Pullen@Sun.COM } 15998671SJulian.Pullen@Sun.COM 16008671SJulian.Pullen@Sun.COM 16018671SJulian.Pullen@Sun.COM /* Discover global catalog servers */ 16028671SJulian.Pullen@Sun.COM static ad_item_t * 16038671SJulian.Pullen@Sun.COM validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 16048671SJulian.Pullen@Sun.COM { 16058671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *global_catalog = NULL; 16068671SJulian.Pullen@Sun.COM uint32_t ttl = 0; 16078671SJulian.Pullen@Sun.COM boolean_t validate_global = B_FALSE; 16088671SJulian.Pullen@Sun.COM boolean_t validate_site = B_FALSE; 16098671SJulian.Pullen@Sun.COM ad_item_t *forest_name_item; 16108671SJulian.Pullen@Sun.COM ad_item_t *site_name_item; 16118671SJulian.Pullen@Sun.COM 16128671SJulian.Pullen@Sun.COM /* If the values is fixed there will not be a site specific version */ 16138671SJulian.Pullen@Sun.COM if (is_fixed(&ctx->global_catalog)) 16148671SJulian.Pullen@Sun.COM return (&ctx->global_catalog); 16158671SJulian.Pullen@Sun.COM 16168671SJulian.Pullen@Sun.COM forest_name_item = validate_ForestName(ctx); 16178671SJulian.Pullen@Sun.COM if (forest_name_item == NULL) 16188671SJulian.Pullen@Sun.COM return (NULL); 16198671SJulian.Pullen@Sun.COM 16208671SJulian.Pullen@Sun.COM if (req == AD_DISC_GLOBAL) 16218671SJulian.Pullen@Sun.COM validate_global = B_TRUE; 16228671SJulian.Pullen@Sun.COM else { 16238671SJulian.Pullen@Sun.COM site_name_item = validate_SiteName(ctx); 16248671SJulian.Pullen@Sun.COM if (site_name_item != NULL) 16258671SJulian.Pullen@Sun.COM validate_site = B_TRUE; 16268671SJulian.Pullen@Sun.COM else if (req == AD_DISC_PREFER_SITE) 16278671SJulian.Pullen@Sun.COM validate_global = B_TRUE; 16288671SJulian.Pullen@Sun.COM } 16298671SJulian.Pullen@Sun.COM 16308671SJulian.Pullen@Sun.COM if (validate_global) { 16318671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->global_catalog) || 16328671SJulian.Pullen@Sun.COM is_changed(&ctx->global_catalog, PARAM1, 16338671SJulian.Pullen@Sun.COM forest_name_item)) { 16348671SJulian.Pullen@Sun.COM /* 16358671SJulian.Pullen@Sun.COM * Lookup DNS SRV RR named 16368671SJulian.Pullen@Sun.COM * _ldap._tcp.gc._msdcs.<ForestName> 16378671SJulian.Pullen@Sun.COM */ 16388671SJulian.Pullen@Sun.COM DO_RES_NINIT(ctx); 16398671SJulian.Pullen@Sun.COM global_catalog = 16408671SJulian.Pullen@Sun.COM srv_query(&ctx->res_state, 16418671SJulian.Pullen@Sun.COM LDAP_SRV_HEAD GC_SRV_TAIL, 16428671SJulian.Pullen@Sun.COM ctx->forest_name.value, NULL, &ttl); 16438671SJulian.Pullen@Sun.COM 16448671SJulian.Pullen@Sun.COM if (global_catalog == NULL) 16458671SJulian.Pullen@Sun.COM return (NULL); 16468671SJulian.Pullen@Sun.COM 16478671SJulian.Pullen@Sun.COM update_item(&ctx->global_catalog, global_catalog, 16488671SJulian.Pullen@Sun.COM AD_STATE_AUTO, ttl); 16498671SJulian.Pullen@Sun.COM update_version(&ctx->global_catalog, PARAM1, 16508671SJulian.Pullen@Sun.COM forest_name_item); 16518671SJulian.Pullen@Sun.COM } 16528671SJulian.Pullen@Sun.COM return (&ctx->global_catalog); 16538671SJulian.Pullen@Sun.COM } 16548671SJulian.Pullen@Sun.COM 16558671SJulian.Pullen@Sun.COM if (validate_site) { 16568671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->site_global_catalog) || 16578671SJulian.Pullen@Sun.COM is_changed(&ctx->site_global_catalog, PARAM1, 16588671SJulian.Pullen@Sun.COM forest_name_item) || 16598671SJulian.Pullen@Sun.COM is_changed(&ctx->site_global_catalog, PARAM2, 16608671SJulian.Pullen@Sun.COM site_name_item)) { 16618671SJulian.Pullen@Sun.COM char rr_name[DNS_MAX_NAME]; 16628671SJulian.Pullen@Sun.COM 16638671SJulian.Pullen@Sun.COM /* 16648671SJulian.Pullen@Sun.COM * Lookup DNS SRV RR named: 16658671SJulian.Pullen@Sun.COM * _ldap._tcp.<siteName>._sites.gc. 16668671SJulian.Pullen@Sun.COM * _msdcs.<ForestName> 16678671SJulian.Pullen@Sun.COM */ 16688671SJulian.Pullen@Sun.COM (void) snprintf(rr_name, 16698671SJulian.Pullen@Sun.COM sizeof (rr_name), 16708671SJulian.Pullen@Sun.COM LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 16718671SJulian.Pullen@Sun.COM ctx->site_name.value); 16728671SJulian.Pullen@Sun.COM DO_RES_NINIT(ctx); 16738671SJulian.Pullen@Sun.COM global_catalog = srv_query(&ctx->res_state, rr_name, 16748671SJulian.Pullen@Sun.COM ctx->forest_name.value, NULL, &ttl); 16758671SJulian.Pullen@Sun.COM 16768671SJulian.Pullen@Sun.COM if (global_catalog == NULL) 16778671SJulian.Pullen@Sun.COM return (NULL); 16788671SJulian.Pullen@Sun.COM update_item(&ctx->site_global_catalog, global_catalog, 16798671SJulian.Pullen@Sun.COM AD_STATE_AUTO, ttl); 16808671SJulian.Pullen@Sun.COM update_version(&ctx->site_global_catalog, PARAM1, 16818671SJulian.Pullen@Sun.COM forest_name_item); 16828671SJulian.Pullen@Sun.COM update_version(&ctx->site_global_catalog, PARAM2, 16838671SJulian.Pullen@Sun.COM site_name_item); 16848671SJulian.Pullen@Sun.COM } 16858671SJulian.Pullen@Sun.COM return (&ctx->site_global_catalog); 16868671SJulian.Pullen@Sun.COM } 16878671SJulian.Pullen@Sun.COM return (NULL); 16888671SJulian.Pullen@Sun.COM } 16898671SJulian.Pullen@Sun.COM 16908671SJulian.Pullen@Sun.COM 16918671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t * 16928671SJulian.Pullen@Sun.COM ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 16938671SJulian.Pullen@Sun.COM boolean_t *auto_discovered) 16948671SJulian.Pullen@Sun.COM { 16958671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *global_catalog = NULL; 16968671SJulian.Pullen@Sun.COM ad_item_t *global_catalog_item; 16978671SJulian.Pullen@Sun.COM 16988671SJulian.Pullen@Sun.COM global_catalog_item = validate_GlobalCatalog(ctx, req); 16998671SJulian.Pullen@Sun.COM 17008671SJulian.Pullen@Sun.COM if (global_catalog_item != NULL) { 17018671SJulian.Pullen@Sun.COM global_catalog = ds_dup(global_catalog_item->value); 17028671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 17038671SJulian.Pullen@Sun.COM *auto_discovered = 17048671SJulian.Pullen@Sun.COM (global_catalog_item->state == AD_STATE_AUTO); 17058671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 17068671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 17078671SJulian.Pullen@Sun.COM 17088671SJulian.Pullen@Sun.COM return (global_catalog); 17098671SJulian.Pullen@Sun.COM } 17108671SJulian.Pullen@Sun.COM 17118671SJulian.Pullen@Sun.COM 17128671SJulian.Pullen@Sun.COM static ad_item_t * 17138671SJulian.Pullen@Sun.COM validate_TrustedDomains(ad_disc_t ctx) 17148671SJulian.Pullen@Sun.COM { 17158671SJulian.Pullen@Sun.COM LDAP *ld = NULL; 17168671SJulian.Pullen@Sun.COM ad_item_t *global_catalog_item; 17178671SJulian.Pullen@Sun.COM ad_item_t *forest_name_item; 17188671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t *trusted_domains; 17198671SJulian.Pullen@Sun.COM char *dn = NULL; 17208671SJulian.Pullen@Sun.COM char *forest_name_dn; 17218671SJulian.Pullen@Sun.COM int len; 17228671SJulian.Pullen@Sun.COM int num_parts; 17238671SJulian.Pullen@Sun.COM 17248671SJulian.Pullen@Sun.COM if (is_fixed(&ctx->trusted_domains)) 17258671SJulian.Pullen@Sun.COM return (&ctx->trusted_domains); 17268671SJulian.Pullen@Sun.COM 17278671SJulian.Pullen@Sun.COM global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 17288671SJulian.Pullen@Sun.COM if (global_catalog_item == NULL) 17298671SJulian.Pullen@Sun.COM return (NULL); 17308671SJulian.Pullen@Sun.COM 17318671SJulian.Pullen@Sun.COM forest_name_item = validate_ForestName(ctx); 17328671SJulian.Pullen@Sun.COM if (forest_name_item == NULL) 17338671SJulian.Pullen@Sun.COM return (NULL); 17348671SJulian.Pullen@Sun.COM 17358671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->trusted_domains) || 17368671SJulian.Pullen@Sun.COM is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 17378671SJulian.Pullen@Sun.COM is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 17388671SJulian.Pullen@Sun.COM 17398671SJulian.Pullen@Sun.COM forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 17408671SJulian.Pullen@Sun.COM &num_parts); 17418671SJulian.Pullen@Sun.COM if (forest_name_dn == NULL) 17428671SJulian.Pullen@Sun.COM return (NULL); 17438671SJulian.Pullen@Sun.COM 17448671SJulian.Pullen@Sun.COM len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 17458671SJulian.Pullen@Sun.COM dn = malloc(len); 17468671SJulian.Pullen@Sun.COM if (dn == NULL) { 17478671SJulian.Pullen@Sun.COM free(forest_name_dn); 17488671SJulian.Pullen@Sun.COM return (NULL); 17498671SJulian.Pullen@Sun.COM } 17508671SJulian.Pullen@Sun.COM (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 17518671SJulian.Pullen@Sun.COM free(forest_name_dn); 17528671SJulian.Pullen@Sun.COM 17538671SJulian.Pullen@Sun.COM trusted_domains = ldap_lookup_trusted_domains( 17548671SJulian.Pullen@Sun.COM &ld, global_catalog_item->value, dn); 17558671SJulian.Pullen@Sun.COM 17568671SJulian.Pullen@Sun.COM if (ld != NULL) 17578671SJulian.Pullen@Sun.COM (void) ldap_unbind(ld); 17588671SJulian.Pullen@Sun.COM free(dn); 17598671SJulian.Pullen@Sun.COM 17608671SJulian.Pullen@Sun.COM if (trusted_domains == NULL) 17618671SJulian.Pullen@Sun.COM return (NULL); 17628671SJulian.Pullen@Sun.COM 17638671SJulian.Pullen@Sun.COM update_item(&ctx->trusted_domains, trusted_domains, 17648671SJulian.Pullen@Sun.COM AD_STATE_AUTO, 0); 17658671SJulian.Pullen@Sun.COM update_version(&ctx->trusted_domains, PARAM1, 17668671SJulian.Pullen@Sun.COM global_catalog_item); 17678671SJulian.Pullen@Sun.COM update_version(&ctx->trusted_domains, PARAM2, 17688671SJulian.Pullen@Sun.COM forest_name_item); 17698671SJulian.Pullen@Sun.COM } 17708671SJulian.Pullen@Sun.COM 17718671SJulian.Pullen@Sun.COM return (&ctx->trusted_domains); 17728671SJulian.Pullen@Sun.COM } 17738671SJulian.Pullen@Sun.COM 17748671SJulian.Pullen@Sun.COM 17758671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t * 17768671SJulian.Pullen@Sun.COM ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 17778671SJulian.Pullen@Sun.COM { 17788671SJulian.Pullen@Sun.COM ad_disc_trusteddomains_t *trusted_domains = NULL; 17798671SJulian.Pullen@Sun.COM ad_item_t *trusted_domains_item; 17808671SJulian.Pullen@Sun.COM 17818671SJulian.Pullen@Sun.COM trusted_domains_item = validate_TrustedDomains(ctx); 17828671SJulian.Pullen@Sun.COM 17838671SJulian.Pullen@Sun.COM if (trusted_domains_item != NULL) { 17848671SJulian.Pullen@Sun.COM trusted_domains = td_dup(trusted_domains_item->value); 17858671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 17868671SJulian.Pullen@Sun.COM *auto_discovered = 17878671SJulian.Pullen@Sun.COM (trusted_domains_item->state == AD_STATE_AUTO); 17888671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 17898671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 17908671SJulian.Pullen@Sun.COM 17918671SJulian.Pullen@Sun.COM return (trusted_domains); 17928671SJulian.Pullen@Sun.COM } 17938671SJulian.Pullen@Sun.COM 17948671SJulian.Pullen@Sun.COM 17958671SJulian.Pullen@Sun.COM static ad_item_t * 17968671SJulian.Pullen@Sun.COM validate_DomainsInForest(ad_disc_t ctx) 17978671SJulian.Pullen@Sun.COM { 17988671SJulian.Pullen@Sun.COM ad_item_t *global_catalog_item; 17998671SJulian.Pullen@Sun.COM LDAP *ld = NULL; 18008671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t *domains_in_forest; 18018671SJulian.Pullen@Sun.COM 18028671SJulian.Pullen@Sun.COM if (is_fixed(&ctx->domains_in_forest)) 18038671SJulian.Pullen@Sun.COM return (&ctx->domains_in_forest); 18048671SJulian.Pullen@Sun.COM 18058671SJulian.Pullen@Sun.COM global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 18068671SJulian.Pullen@Sun.COM if (global_catalog_item == NULL) 18078671SJulian.Pullen@Sun.COM return (NULL); 18088671SJulian.Pullen@Sun.COM 18098671SJulian.Pullen@Sun.COM if (!is_valid(&ctx->domains_in_forest) || 18108671SJulian.Pullen@Sun.COM is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 18118671SJulian.Pullen@Sun.COM 18128671SJulian.Pullen@Sun.COM domains_in_forest = ldap_lookup_domains_in_forest( 18138671SJulian.Pullen@Sun.COM &ld, global_catalog_item->value); 18148671SJulian.Pullen@Sun.COM 18158671SJulian.Pullen@Sun.COM if (ld != NULL) 18168671SJulian.Pullen@Sun.COM (void) ldap_unbind(ld); 18178671SJulian.Pullen@Sun.COM 18188671SJulian.Pullen@Sun.COM if (domains_in_forest == NULL) 18198671SJulian.Pullen@Sun.COM return (NULL); 18208671SJulian.Pullen@Sun.COM 18218671SJulian.Pullen@Sun.COM update_item(&ctx->domains_in_forest, domains_in_forest, 18228671SJulian.Pullen@Sun.COM AD_STATE_AUTO, 0); 18238671SJulian.Pullen@Sun.COM update_version(&ctx->domains_in_forest, PARAM1, 18248671SJulian.Pullen@Sun.COM global_catalog_item); 18258671SJulian.Pullen@Sun.COM } 18268671SJulian.Pullen@Sun.COM return (&ctx->domains_in_forest); 18278671SJulian.Pullen@Sun.COM } 18288671SJulian.Pullen@Sun.COM 18298671SJulian.Pullen@Sun.COM 18308671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t * 18318671SJulian.Pullen@Sun.COM ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 18328671SJulian.Pullen@Sun.COM { 18338671SJulian.Pullen@Sun.COM ad_disc_domainsinforest_t *domains_in_forest = NULL; 18348671SJulian.Pullen@Sun.COM ad_item_t *domains_in_forest_item; 18358671SJulian.Pullen@Sun.COM 18368671SJulian.Pullen@Sun.COM domains_in_forest_item = validate_DomainsInForest(ctx); 18378671SJulian.Pullen@Sun.COM 18388671SJulian.Pullen@Sun.COM if (domains_in_forest_item != NULL) { 18398671SJulian.Pullen@Sun.COM domains_in_forest = df_dup(domains_in_forest_item->value); 18408671SJulian.Pullen@Sun.COM if (auto_discovered != NULL) 18418671SJulian.Pullen@Sun.COM *auto_discovered = 18428671SJulian.Pullen@Sun.COM (domains_in_forest_item->state == AD_STATE_AUTO); 18438671SJulian.Pullen@Sun.COM } else if (auto_discovered != NULL) 18448671SJulian.Pullen@Sun.COM *auto_discovered = B_FALSE; 18458671SJulian.Pullen@Sun.COM 18468671SJulian.Pullen@Sun.COM return (domains_in_forest); 18478671SJulian.Pullen@Sun.COM } 18488671SJulian.Pullen@Sun.COM 18498671SJulian.Pullen@Sun.COM 18508671SJulian.Pullen@Sun.COM 18518671SJulian.Pullen@Sun.COM 18528671SJulian.Pullen@Sun.COM int 18538671SJulian.Pullen@Sun.COM ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 18548671SJulian.Pullen@Sun.COM { 18558671SJulian.Pullen@Sun.COM char *domain_name = NULL; 18568671SJulian.Pullen@Sun.COM if (domainName != NULL) { 18578671SJulian.Pullen@Sun.COM domain_name = strdup(domainName); 18588671SJulian.Pullen@Sun.COM if (domain_name == NULL) 18598671SJulian.Pullen@Sun.COM return (-1); 18608671SJulian.Pullen@Sun.COM update_item(&ctx->domain_name, domain_name, 18618671SJulian.Pullen@Sun.COM AD_STATE_FIXED, 0); 18628671SJulian.Pullen@Sun.COM } else if (ctx->domain_name.state == AD_STATE_FIXED) 18638671SJulian.Pullen@Sun.COM ctx->domain_name.state = AD_STATE_INVALID; 18648671SJulian.Pullen@Sun.COM return (0); 18658671SJulian.Pullen@Sun.COM } 18668671SJulian.Pullen@Sun.COM 18678671SJulian.Pullen@Sun.COM 18688671SJulian.Pullen@Sun.COM int 18698671SJulian.Pullen@Sun.COM ad_disc_set_DomainController(ad_disc_t ctx, 18708671SJulian.Pullen@Sun.COM const idmap_ad_disc_ds_t *domainController) 18718671SJulian.Pullen@Sun.COM { 18728671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *domain_controller = NULL; 18738671SJulian.Pullen@Sun.COM if (domainController != NULL) { 18748671SJulian.Pullen@Sun.COM domain_controller = ds_dup(domainController); 18758671SJulian.Pullen@Sun.COM if (domain_controller == NULL) 18768671SJulian.Pullen@Sun.COM return (-1); 18778671SJulian.Pullen@Sun.COM update_item(&ctx->domain_controller, domain_controller, 18788671SJulian.Pullen@Sun.COM AD_STATE_FIXED, 0); 18798671SJulian.Pullen@Sun.COM } else if (ctx->domain_controller.state == AD_STATE_FIXED) 18808671SJulian.Pullen@Sun.COM ctx->domain_controller.state = AD_STATE_INVALID; 18818671SJulian.Pullen@Sun.COM return (0); 18828671SJulian.Pullen@Sun.COM } 18838671SJulian.Pullen@Sun.COM 18848671SJulian.Pullen@Sun.COM 18858671SJulian.Pullen@Sun.COM int 18868671SJulian.Pullen@Sun.COM ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 18878671SJulian.Pullen@Sun.COM { 18888671SJulian.Pullen@Sun.COM char *site_name = NULL; 18898671SJulian.Pullen@Sun.COM if (siteName != NULL) { 18908671SJulian.Pullen@Sun.COM site_name = strdup(siteName); 18918671SJulian.Pullen@Sun.COM if (site_name == NULL) 18928671SJulian.Pullen@Sun.COM return (-1); 18938671SJulian.Pullen@Sun.COM update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 18948671SJulian.Pullen@Sun.COM } else if (ctx->site_name.state == AD_STATE_FIXED) 18958671SJulian.Pullen@Sun.COM ctx->site_name.state = AD_STATE_INVALID; 18968671SJulian.Pullen@Sun.COM return (0); 18978671SJulian.Pullen@Sun.COM } 18988671SJulian.Pullen@Sun.COM 18998671SJulian.Pullen@Sun.COM int 19008671SJulian.Pullen@Sun.COM ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 19018671SJulian.Pullen@Sun.COM { 19028671SJulian.Pullen@Sun.COM char *forest_name = NULL; 19038671SJulian.Pullen@Sun.COM if (forestName != NULL) { 19048671SJulian.Pullen@Sun.COM forest_name = strdup(forestName); 19058671SJulian.Pullen@Sun.COM if (forest_name == NULL) 19068671SJulian.Pullen@Sun.COM return (-1); 19078671SJulian.Pullen@Sun.COM update_item(&ctx->forest_name, forest_name, 19088671SJulian.Pullen@Sun.COM AD_STATE_FIXED, 0); 19098671SJulian.Pullen@Sun.COM } else if (ctx->forest_name.state == AD_STATE_FIXED) 19108671SJulian.Pullen@Sun.COM ctx->forest_name.state = AD_STATE_INVALID; 19118671SJulian.Pullen@Sun.COM return (0); 19128671SJulian.Pullen@Sun.COM } 19138671SJulian.Pullen@Sun.COM 19148671SJulian.Pullen@Sun.COM int 19158671SJulian.Pullen@Sun.COM ad_disc_set_GlobalCatalog(ad_disc_t ctx, 19168671SJulian.Pullen@Sun.COM const idmap_ad_disc_ds_t *globalCatalog) 19178671SJulian.Pullen@Sun.COM { 19188671SJulian.Pullen@Sun.COM idmap_ad_disc_ds_t *global_catalog = NULL; 19198671SJulian.Pullen@Sun.COM if (globalCatalog != NULL) { 19208671SJulian.Pullen@Sun.COM global_catalog = ds_dup(globalCatalog); 19218671SJulian.Pullen@Sun.COM if (global_catalog == NULL) 19228671SJulian.Pullen@Sun.COM return (-1); 19238671SJulian.Pullen@Sun.COM update_item(&ctx->global_catalog, global_catalog, 19248671SJulian.Pullen@Sun.COM AD_STATE_FIXED, 0); 19258671SJulian.Pullen@Sun.COM } else if (ctx->global_catalog.state == AD_STATE_FIXED) 19268671SJulian.Pullen@Sun.COM ctx->global_catalog.state = AD_STATE_INVALID; 19278671SJulian.Pullen@Sun.COM return (0); 19288671SJulian.Pullen@Sun.COM } 19298671SJulian.Pullen@Sun.COM 19308671SJulian.Pullen@Sun.COM 19318671SJulian.Pullen@Sun.COM int 19328671SJulian.Pullen@Sun.COM ad_disc_unset(ad_disc_t ctx) 19338671SJulian.Pullen@Sun.COM { 19348671SJulian.Pullen@Sun.COM if (ctx->domain_name.state == AD_STATE_FIXED) 19358671SJulian.Pullen@Sun.COM ctx->domain_name.state = AD_STATE_INVALID; 19368671SJulian.Pullen@Sun.COM 19378671SJulian.Pullen@Sun.COM if (ctx->domain_controller.state == AD_STATE_FIXED) 19388671SJulian.Pullen@Sun.COM ctx->domain_controller.state = AD_STATE_INVALID; 19398671SJulian.Pullen@Sun.COM 19408671SJulian.Pullen@Sun.COM if (ctx->site_name.state == AD_STATE_FIXED) 19418671SJulian.Pullen@Sun.COM ctx->site_name.state = AD_STATE_INVALID; 19428671SJulian.Pullen@Sun.COM 19438671SJulian.Pullen@Sun.COM if (ctx->forest_name.state == AD_STATE_FIXED) 19448671SJulian.Pullen@Sun.COM ctx->forest_name.state = AD_STATE_INVALID; 19458671SJulian.Pullen@Sun.COM 19468671SJulian.Pullen@Sun.COM if (ctx->global_catalog.state == AD_STATE_FIXED) 19478671SJulian.Pullen@Sun.COM ctx->global_catalog.state = AD_STATE_INVALID; 19488671SJulian.Pullen@Sun.COM 19498671SJulian.Pullen@Sun.COM return (0); 19508671SJulian.Pullen@Sun.COM } 19518671SJulian.Pullen@Sun.COM 19528671SJulian.Pullen@Sun.COM /* 19538671SJulian.Pullen@Sun.COM * ad_disc_get_TTL 19548671SJulian.Pullen@Sun.COM * 19558671SJulian.Pullen@Sun.COM * This routines the time to live for AD 19568671SJulian.Pullen@Sun.COM * auto discovered items. 19578671SJulian.Pullen@Sun.COM * 19588671SJulian.Pullen@Sun.COM * Returns: 19598671SJulian.Pullen@Sun.COM * -1 if there are no TTL items 19608671SJulian.Pullen@Sun.COM * 0 if there are expired items 19618671SJulian.Pullen@Sun.COM * else the number of seconds 19628671SJulian.Pullen@Sun.COM * 19638671SJulian.Pullen@Sun.COM * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 19648671SJulian.Pullen@Sun.COM * is positive -- min() greater than zero. 19658671SJulian.Pullen@Sun.COM */ 19668671SJulian.Pullen@Sun.COM #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 19678671SJulian.Pullen@Sun.COM (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 19688671SJulian.Pullen@Sun.COM int 19698671SJulian.Pullen@Sun.COM ad_disc_get_TTL(ad_disc_t ctx) 19708671SJulian.Pullen@Sun.COM { 19718671SJulian.Pullen@Sun.COM int ttl; 19728671SJulian.Pullen@Sun.COM 19738671SJulian.Pullen@Sun.COM ttl = MIN_GT_ZERO(ctx->domain_controller.ttl, ctx->global_catalog.ttl); 19748671SJulian.Pullen@Sun.COM ttl = MIN_GT_ZERO(ttl, ctx->site_domain_controller.ttl); 19758671SJulian.Pullen@Sun.COM ttl = MIN_GT_ZERO(ttl, ctx->site_global_catalog.ttl); 19768671SJulian.Pullen@Sun.COM 19778671SJulian.Pullen@Sun.COM if (ttl == -1) 19788671SJulian.Pullen@Sun.COM return (-1); 19798671SJulian.Pullen@Sun.COM ttl -= time(NULL); 19808671SJulian.Pullen@Sun.COM if (ttl < 0) 19818671SJulian.Pullen@Sun.COM return (0); 19828671SJulian.Pullen@Sun.COM return (ttl); 19838671SJulian.Pullen@Sun.COM } 19848671SJulian.Pullen@Sun.COM 19858671SJulian.Pullen@Sun.COM boolean_t 19868671SJulian.Pullen@Sun.COM ad_disc_SubnetChanged(ad_disc_t ctx) 19878671SJulian.Pullen@Sun.COM { 19888671SJulian.Pullen@Sun.COM ad_subnet_t *subnets; 19898671SJulian.Pullen@Sun.COM 19908671SJulian.Pullen@Sun.COM if (ctx->subnets_changed || ctx->subnets == NULL) 19918671SJulian.Pullen@Sun.COM return (B_TRUE); 19928671SJulian.Pullen@Sun.COM 19938671SJulian.Pullen@Sun.COM if ((subnets = find_subnets()) != NULL) { 19948671SJulian.Pullen@Sun.COM if (cmpsubnets(subnets, ctx->subnets) != 0) 19958671SJulian.Pullen@Sun.COM ctx->subnets_changed = B_TRUE; 19968671SJulian.Pullen@Sun.COM free(subnets); 19978671SJulian.Pullen@Sun.COM } 19988671SJulian.Pullen@Sun.COM 19998671SJulian.Pullen@Sun.COM return (ctx->subnets_changed); 20008671SJulian.Pullen@Sun.COM } 2001