17a8a68f5SJulian Pullen /* 27a8a68f5SJulian Pullen * CDDL HEADER START 37a8a68f5SJulian Pullen * 47a8a68f5SJulian Pullen * The contents of this file are subject to the terms of the 57a8a68f5SJulian Pullen * Common Development and Distribution License (the "License"). 67a8a68f5SJulian Pullen * You may not use this file except in compliance with the License. 77a8a68f5SJulian Pullen * 87a8a68f5SJulian Pullen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97a8a68f5SJulian Pullen * or http://www.opensolaris.org/os/licensing. 107a8a68f5SJulian Pullen * See the License for the specific language governing permissions 117a8a68f5SJulian Pullen * and limitations under the License. 127a8a68f5SJulian Pullen * 137a8a68f5SJulian Pullen * When distributing Covered Code, include this CDDL HEADER in each 147a8a68f5SJulian Pullen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157a8a68f5SJulian Pullen * If applicable, add the following below this CDDL HEADER, with the 167a8a68f5SJulian Pullen * fields enclosed by brackets "[]" replaced with your own identifying 177a8a68f5SJulian Pullen * information: Portions Copyright [yyyy] [name of copyright owner] 187a8a68f5SJulian Pullen * 197a8a68f5SJulian Pullen * CDDL HEADER END 207a8a68f5SJulian Pullen */ 217a8a68f5SJulian Pullen 227a8a68f5SJulian Pullen /* 23*148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 247a8a68f5SJulian Pullen */ 257a8a68f5SJulian Pullen 267a8a68f5SJulian Pullen /* 277a8a68f5SJulian Pullen * Active Directory Auto-Discovery. 287a8a68f5SJulian Pullen * 297a8a68f5SJulian Pullen * This [project private] API allows the caller to provide whatever 307a8a68f5SJulian Pullen * details it knows a priori (i.e., provided via configuration so as to 317a8a68f5SJulian Pullen * override auto-discovery) and in any order. Then the caller can ask 327a8a68f5SJulian Pullen * for any of the auto-discoverable parameters in any order. 337a8a68f5SJulian Pullen * 347a8a68f5SJulian Pullen * But there is an actual order in which discovery must be done. Given 357a8a68f5SJulian Pullen * the discovery mechanism implemented here, that order is: 367a8a68f5SJulian Pullen * 377a8a68f5SJulian Pullen * - the domain name joined must be discovered first 387a8a68f5SJulian Pullen * - then the domain controllers 397a8a68f5SJulian Pullen * - then the forest name and site name 407a8a68f5SJulian Pullen * - then the global catalog servers, and site-specific domain 417a8a68f5SJulian Pullen * controllers and global catalog servers. 427a8a68f5SJulian Pullen * 437a8a68f5SJulian Pullen * The API does not require it be called in the same order because there 447a8a68f5SJulian Pullen * may be other discovery mechanisms in the future, and exposing 457a8a68f5SJulian Pullen * ordering requirements of the current mechanism now can create trouble 467a8a68f5SJulian Pullen * down the line. Also, this makes the API easier to use now, which 477a8a68f5SJulian Pullen * means less work to do some day when we make this a public API. 487a8a68f5SJulian Pullen * 497a8a68f5SJulian Pullen * Domain discovery is done by res_nsearch() of the DNS SRV RR name for 507a8a68f5SJulian Pullen * domain controllers. As long as the joined domain appears in the DNS 517a8a68f5SJulian Pullen * resolver's search list then we'll find it. 527a8a68f5SJulian Pullen * 537a8a68f5SJulian Pullen * Domain controller discovery is a matter of formatting the DNS SRV RR 547a8a68f5SJulian Pullen * FQDN for domain controllers and doing a lookup for them. Knowledge 557a8a68f5SJulian Pullen * of the domain name is not fundamentally required, but we separate the 567a8a68f5SJulian Pullen * two processes, which in practice can lead to one more DNS lookup than 577a8a68f5SJulian Pullen * is strictly required. 587a8a68f5SJulian Pullen * 597a8a68f5SJulian Pullen * Forest and site name discovery require an LDAP search of the AD 607a8a68f5SJulian Pullen * "configuration partition" at a domain controller for the joined 617a8a68f5SJulian Pullen * domain. Forest and site name discovery depend on knowing the joined 627a8a68f5SJulian Pullen * domain name and domain controllers for that domain. 637a8a68f5SJulian Pullen * 647a8a68f5SJulian Pullen * Global catalog server discovery requires knowledge of the forest 657a8a68f5SJulian Pullen * name in order to format the DNS SRV RR FQDN to lookup. Site-specific 667a8a68f5SJulian Pullen * domain controller discovery depends on knowing the site name (and, 677a8a68f5SJulian Pullen * therefore, joined domain, ...). Site-specific global catalog server 687a8a68f5SJulian Pullen * discovery depends on knowledge of the forest and site names, which 697a8a68f5SJulian Pullen * depend on... 707a8a68f5SJulian Pullen * 717a8a68f5SJulian Pullen * All the work of discovering particular items is done by functions 727a8a68f5SJulian Pullen * named validate_<item>(). Each such function calls validate_<item>() 737a8a68f5SJulian Pullen * for any items that it depends on. 747a8a68f5SJulian Pullen * 757a8a68f5SJulian Pullen * This API is not thread-safe. 767a8a68f5SJulian Pullen */ 777a8a68f5SJulian Pullen 787a8a68f5SJulian Pullen 797a8a68f5SJulian Pullen #include <stdio.h> 807a8a68f5SJulian Pullen #include <string.h> 817a8a68f5SJulian Pullen #include <strings.h> 827a8a68f5SJulian Pullen #include <unistd.h> 837a8a68f5SJulian Pullen #include <assert.h> 847a8a68f5SJulian Pullen #include <stdlib.h> 857a8a68f5SJulian Pullen #include <net/if.h> 867a8a68f5SJulian Pullen #include <net/if.h> 877a8a68f5SJulian Pullen #include <sys/types.h> 887a8a68f5SJulian Pullen #include <sys/socket.h> 897a8a68f5SJulian Pullen #include <sys/sockio.h> 907a8a68f5SJulian Pullen #include <netinet/in.h> 917a8a68f5SJulian Pullen #include <netinet/in.h> 927a8a68f5SJulian Pullen #include <arpa/inet.h> 937a8a68f5SJulian Pullen #include <arpa/nameser.h> 947a8a68f5SJulian Pullen #include <resolv.h> 957a8a68f5SJulian Pullen #include <netdb.h> 967a8a68f5SJulian Pullen #include <ctype.h> 977a8a68f5SJulian Pullen #include <errno.h> 987a8a68f5SJulian Pullen #include <ldap.h> 997a8a68f5SJulian Pullen #include <sasl/sasl.h> 1007a8a68f5SJulian Pullen #include <sys/u8_textprep.h> 1017a8a68f5SJulian Pullen #include <syslog.h> 1027a8a68f5SJulian Pullen #include "adutils_impl.h" 1037a8a68f5SJulian Pullen #include "addisc.h" 1047a8a68f5SJulian Pullen 105c5866007SKeyur Desai /* 106c5866007SKeyur Desai * These set some sanity policies for discovery. After a discovery 107c5866007SKeyur Desai * cycle, we will consider the results (successful or unsuccessful) 108c5866007SKeyur Desai * to be valid for at least MINIMUM_TTL seconds, and for at most 109c5866007SKeyur Desai * MAXIMUM_TTL seconds. Note that the caller is free to request 110c5866007SKeyur Desai * discovery cycles sooner than MINIMUM_TTL if it has reason to believe 111c5866007SKeyur Desai * that the situation has changed. 112c5866007SKeyur Desai */ 113c5866007SKeyur Desai #define MINIMUM_TTL (5 * 60) 114c5866007SKeyur Desai #define MAXIMUM_TTL (20 * 60) 1157a8a68f5SJulian Pullen 1167a8a68f5SJulian Pullen enum ad_item_state { 1177a8a68f5SJulian Pullen AD_STATE_INVALID = 0, /* The value is not valid */ 1187a8a68f5SJulian Pullen AD_STATE_FIXED, /* The value was fixed by caller */ 1197a8a68f5SJulian Pullen AD_STATE_AUTO /* The value is auto discovered */ 1207a8a68f5SJulian Pullen }; 1217a8a68f5SJulian Pullen 1227a8a68f5SJulian Pullen enum ad_data_type { 1237a8a68f5SJulian Pullen AD_STRING = 123, 1247a8a68f5SJulian Pullen AD_DIRECTORY, 1257a8a68f5SJulian Pullen AD_DOMAINS_IN_FOREST, 1267a8a68f5SJulian Pullen AD_TRUSTED_DOMAINS 1277a8a68f5SJulian Pullen }; 1287a8a68f5SJulian Pullen 1297a8a68f5SJulian Pullen 1307a8a68f5SJulian Pullen typedef struct ad_subnet { 1317a8a68f5SJulian Pullen char subnet[24]; 1327a8a68f5SJulian Pullen } ad_subnet_t; 1337a8a68f5SJulian Pullen 1347a8a68f5SJulian Pullen 1357a8a68f5SJulian Pullen typedef struct ad_item { 1367a8a68f5SJulian Pullen enum ad_item_state state; 1377a8a68f5SJulian Pullen enum ad_data_type type; 1387a8a68f5SJulian Pullen void *value; 139c5866007SKeyur Desai time_t expires; 1407a8a68f5SJulian Pullen unsigned int version; /* Version is only changed */ 1417a8a68f5SJulian Pullen /* if the value changes */ 1427a8a68f5SJulian Pullen #define PARAM1 0 1437a8a68f5SJulian Pullen #define PARAM2 1 1447a8a68f5SJulian Pullen int param_version[2]; 1457a8a68f5SJulian Pullen /* These holds the version of */ 1467a8a68f5SJulian Pullen /* dependents so that a dependent */ 1477a8a68f5SJulian Pullen /* change can be detected */ 1487a8a68f5SJulian Pullen } ad_item_t; 1497a8a68f5SJulian Pullen 1507a8a68f5SJulian Pullen typedef struct ad_disc { 1517a8a68f5SJulian Pullen struct __res_state res_state; 1527a8a68f5SJulian Pullen int res_ninitted; 1537a8a68f5SJulian Pullen ad_subnet_t *subnets; 1547a8a68f5SJulian Pullen boolean_t subnets_changed; 1557a8a68f5SJulian Pullen time_t subnets_last_check; 156c5866007SKeyur Desai time_t expires_not_before; 157c5866007SKeyur Desai time_t expires_not_after; 1587a8a68f5SJulian Pullen ad_item_t domain_name; /* DNS hostname string */ 1597a8a68f5SJulian Pullen ad_item_t domain_controller; /* Directory hostname and */ 1607a8a68f5SJulian Pullen /* port array */ 1617a8a68f5SJulian Pullen ad_item_t site_name; /* String */ 1627a8a68f5SJulian Pullen ad_item_t forest_name; /* DNS forestname string */ 1637a8a68f5SJulian Pullen ad_item_t global_catalog; /* Directory hostname and */ 1647a8a68f5SJulian Pullen /* port array */ 1657a8a68f5SJulian Pullen ad_item_t domains_in_forest; /* DNS domainname and SID */ 1667a8a68f5SJulian Pullen /* array */ 1677a8a68f5SJulian Pullen ad_item_t trusted_domains; /* DNS domainname and trust */ 1687a8a68f5SJulian Pullen /* direction array */ 1697a8a68f5SJulian Pullen /* Site specfic versions */ 1707a8a68f5SJulian Pullen ad_item_t site_domain_controller; /* Directory hostname and */ 1717a8a68f5SJulian Pullen /* port array */ 1727a8a68f5SJulian Pullen ad_item_t site_global_catalog; /* Directory hostname and */ 1737a8a68f5SJulian Pullen /* port array */ 174*148c5f43SAlan Wright int debug[AD_DEBUG_MAX+1]; /* Debug levels */ 1757a8a68f5SJulian Pullen } ad_disc; 1767a8a68f5SJulian Pullen 1777a8a68f5SJulian Pullen 1787a8a68f5SJulian Pullen #define DNS_MAX_NAME NS_MAXDNAME 1797a8a68f5SJulian Pullen 1807a8a68f5SJulian Pullen 1817a8a68f5SJulian Pullen /* SRV RR names for various queries */ 1827a8a68f5SJulian Pullen #define LDAP_SRV_HEAD "_ldap._tcp." 1837a8a68f5SJulian Pullen #define SITE_SRV_MIDDLE "%s._sites." 1847a8a68f5SJulian Pullen #define GC_SRV_TAIL "gc._msdcs" 1857a8a68f5SJulian Pullen #define DC_SRV_TAIL "dc._msdcs" 1867a8a68f5SJulian Pullen #define ALL_GC_SRV_TAIL "_gc._tcp" 1877a8a68f5SJulian Pullen #define PDC_SRV "_ldap._tcp.pdc._msdcs.%s" 1887a8a68f5SJulian Pullen 1897a8a68f5SJulian Pullen /* A RR name for all GCs -- last resort this works */ 1907a8a68f5SJulian Pullen #define GC_ALL_A_NAME_FSTR "gc._msdcs.%s." 1917a8a68f5SJulian Pullen 1927a8a68f5SJulian Pullen 1937a8a68f5SJulian Pullen /* 1947a8a68f5SJulian Pullen * We try res_ninit() whenever we don't have one. res_ninit() fails if 1957a8a68f5SJulian Pullen * idmapd is running before the network is up! 1967a8a68f5SJulian Pullen */ 1977a8a68f5SJulian Pullen #define DO_RES_NINIT(ctx) if (!(ctx)->res_ninitted) \ 1987a8a68f5SJulian Pullen (ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1) 1997a8a68f5SJulian Pullen 2007a8a68f5SJulian Pullen #define is_fixed(item) \ 2017a8a68f5SJulian Pullen ((item)->state == AD_STATE_FIXED) 2027a8a68f5SJulian Pullen 2037a8a68f5SJulian Pullen #define is_changed(item, num, param) \ 2047a8a68f5SJulian Pullen ((item)->param_version[num] != (param)->version) 2057a8a68f5SJulian Pullen 2067a8a68f5SJulian Pullen /* 2077a8a68f5SJulian Pullen * Function definitions 2087a8a68f5SJulian Pullen */ 2097a8a68f5SJulian Pullen static ad_item_t * 2107a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx); 2117a8a68f5SJulian Pullen 2127a8a68f5SJulian Pullen 2137a8a68f5SJulian Pullen 2147a8a68f5SJulian Pullen static void 2157a8a68f5SJulian Pullen update_version(ad_item_t *item, int num, ad_item_t *param) 2167a8a68f5SJulian Pullen { 2177a8a68f5SJulian Pullen item->param_version[num] = param->version; 2187a8a68f5SJulian Pullen } 2197a8a68f5SJulian Pullen 2207a8a68f5SJulian Pullen 2217a8a68f5SJulian Pullen 2227a8a68f5SJulian Pullen static boolean_t 2237a8a68f5SJulian Pullen is_valid(ad_item_t *item) 2247a8a68f5SJulian Pullen { 2257a8a68f5SJulian Pullen if (item->value != NULL) { 2267a8a68f5SJulian Pullen if (item->state == AD_STATE_FIXED) 2277a8a68f5SJulian Pullen return (B_TRUE); 2287a8a68f5SJulian Pullen if (item->state == AD_STATE_AUTO && 229c5866007SKeyur Desai (item->expires == 0 || item->expires > time(NULL))) 2307a8a68f5SJulian Pullen return (B_TRUE); 2317a8a68f5SJulian Pullen } 2327a8a68f5SJulian Pullen return (B_FALSE); 2337a8a68f5SJulian Pullen } 2347a8a68f5SJulian Pullen 2357a8a68f5SJulian Pullen 2367a8a68f5SJulian Pullen static void 2377a8a68f5SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state, 2387a8a68f5SJulian Pullen uint32_t ttl) 2397a8a68f5SJulian Pullen { 2407a8a68f5SJulian Pullen if (item->value != NULL && value != NULL) { 2417a8a68f5SJulian Pullen if ((item->type == AD_STRING && 2427a8a68f5SJulian Pullen strcmp(item->value, value) != 0) || 2437a8a68f5SJulian Pullen (item->type == AD_DIRECTORY && 2447a8a68f5SJulian Pullen ad_disc_compare_ds(item->value, value) != 0)|| 2457a8a68f5SJulian Pullen (item->type == AD_DOMAINS_IN_FOREST && 2467a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(item->value, value) != 0) || 2477a8a68f5SJulian Pullen (item->type == AD_TRUSTED_DOMAINS && 2487a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(item->value, value) != 0)) 2497a8a68f5SJulian Pullen item->version++; 2507a8a68f5SJulian Pullen } else if (item->value != value) 2517a8a68f5SJulian Pullen item->version++; 2527a8a68f5SJulian Pullen 2537a8a68f5SJulian Pullen if (item->value != NULL) 2547a8a68f5SJulian Pullen free(item->value); 2557a8a68f5SJulian Pullen 2567a8a68f5SJulian Pullen item->value = value; 2577a8a68f5SJulian Pullen item->state = state; 2587a8a68f5SJulian Pullen 2597a8a68f5SJulian Pullen if (ttl == 0) 260c5866007SKeyur Desai item->expires = 0; 2617a8a68f5SJulian Pullen else 262c5866007SKeyur Desai item->expires = time(NULL) + ttl; 2637a8a68f5SJulian Pullen } 2647a8a68f5SJulian Pullen 2657a8a68f5SJulian Pullen 2667a8a68f5SJulian Pullen /* Compare DS lists */ 2677a8a68f5SJulian Pullen int 2687a8a68f5SJulian Pullen ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2) 2697a8a68f5SJulian Pullen { 2707a8a68f5SJulian Pullen int i, j; 2717a8a68f5SJulian Pullen int num_ds1; 2727a8a68f5SJulian Pullen int num_ds2; 2737a8a68f5SJulian Pullen boolean_t match; 2747a8a68f5SJulian Pullen 2757a8a68f5SJulian Pullen for (i = 0; ds1[i].host[0] != '\0'; i++) 2767a8a68f5SJulian Pullen continue; 2777a8a68f5SJulian Pullen num_ds1 = i; 2787a8a68f5SJulian Pullen for (j = 0; ds2[j].host[0] != '\0'; j++) 2797a8a68f5SJulian Pullen continue; 2807a8a68f5SJulian Pullen num_ds2 = j; 2817a8a68f5SJulian Pullen if (num_ds1 != num_ds2) 2827a8a68f5SJulian Pullen return (1); 2837a8a68f5SJulian Pullen 2847a8a68f5SJulian Pullen for (i = 0; i < num_ds1; i++) { 2857a8a68f5SJulian Pullen match = B_FALSE; 2867a8a68f5SJulian Pullen for (j = 0; j < num_ds2; j++) { 287928e1f97SJordan Brown if (strcmp(ds1[i].host, ds2[j].host) == 0 && 288928e1f97SJordan Brown ds1[i].port == ds2[j].port) { 2897a8a68f5SJulian Pullen match = B_TRUE; 2907a8a68f5SJulian Pullen break; 2917a8a68f5SJulian Pullen } 2927a8a68f5SJulian Pullen } 2937a8a68f5SJulian Pullen if (!match) 2947a8a68f5SJulian Pullen return (1); 2957a8a68f5SJulian Pullen } 2967a8a68f5SJulian Pullen return (0); 2977a8a68f5SJulian Pullen } 2987a8a68f5SJulian Pullen 2997a8a68f5SJulian Pullen 3007a8a68f5SJulian Pullen /* Copy a list of DSs */ 3017a8a68f5SJulian Pullen static idmap_ad_disc_ds_t * 3027a8a68f5SJulian Pullen ds_dup(const idmap_ad_disc_ds_t *srv) 3037a8a68f5SJulian Pullen { 3047a8a68f5SJulian Pullen int i; 3057a8a68f5SJulian Pullen int size; 3067a8a68f5SJulian Pullen idmap_ad_disc_ds_t *new = NULL; 3077a8a68f5SJulian Pullen 3087a8a68f5SJulian Pullen for (i = 0; srv[i].host[0] != '\0'; i++) 3097a8a68f5SJulian Pullen continue; 3107a8a68f5SJulian Pullen 3117a8a68f5SJulian Pullen size = (i + 1) * sizeof (idmap_ad_disc_ds_t); 3127a8a68f5SJulian Pullen new = malloc(size); 3137a8a68f5SJulian Pullen if (new != NULL) 314*148c5f43SAlan Wright (void) memcpy(new, srv, size); 3157a8a68f5SJulian Pullen return (new); 3167a8a68f5SJulian Pullen } 3177a8a68f5SJulian Pullen 3187a8a68f5SJulian Pullen 3197a8a68f5SJulian Pullen int 3207a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1, 3217a8a68f5SJulian Pullen ad_disc_trusteddomains_t *td2) 3227a8a68f5SJulian Pullen { 3237a8a68f5SJulian Pullen int i, j; 3247a8a68f5SJulian Pullen int num_td1; 3257a8a68f5SJulian Pullen int num_td2; 3267a8a68f5SJulian Pullen boolean_t match; 3277a8a68f5SJulian Pullen 3287a8a68f5SJulian Pullen for (i = 0; td1[i].domain[0] != '\0'; i++) 3297a8a68f5SJulian Pullen continue; 3307a8a68f5SJulian Pullen num_td1 = i; 3317a8a68f5SJulian Pullen 3327a8a68f5SJulian Pullen for (j = 0; td2[j].domain[0] != '\0'; j++) 3337a8a68f5SJulian Pullen continue; 3347a8a68f5SJulian Pullen num_td2 = j; 3357a8a68f5SJulian Pullen 3367a8a68f5SJulian Pullen if (num_td1 != num_td2) 3377a8a68f5SJulian Pullen return (1); 3387a8a68f5SJulian Pullen 3397a8a68f5SJulian Pullen for (i = 0; i < num_td1; i++) { 3407a8a68f5SJulian Pullen match = B_FALSE; 3417a8a68f5SJulian Pullen for (j = 0; j < num_td2; j++) { 3421fcced4cSJordan Brown if (domain_eq(td1[i].domain, td2[j].domain)) { 3437a8a68f5SJulian Pullen match = B_TRUE; 3447a8a68f5SJulian Pullen break; 3457a8a68f5SJulian Pullen } 3467a8a68f5SJulian Pullen } 3477a8a68f5SJulian Pullen if (!match) 3487a8a68f5SJulian Pullen return (1); 3497a8a68f5SJulian Pullen } 3507a8a68f5SJulian Pullen return (0); 3517a8a68f5SJulian Pullen } 3527a8a68f5SJulian Pullen 3537a8a68f5SJulian Pullen 3547a8a68f5SJulian Pullen 3557a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 3567a8a68f5SJulian Pullen static ad_disc_trusteddomains_t * 3577a8a68f5SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td) 3587a8a68f5SJulian Pullen { 3597a8a68f5SJulian Pullen int i; 3607a8a68f5SJulian Pullen int size; 3617a8a68f5SJulian Pullen ad_disc_trusteddomains_t *new = NULL; 3627a8a68f5SJulian Pullen 3637a8a68f5SJulian Pullen for (i = 0; td[i].domain[0] != '\0'; i++) 3647a8a68f5SJulian Pullen continue; 3657a8a68f5SJulian Pullen 3667a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_trusteddomains_t); 3677a8a68f5SJulian Pullen new = malloc(size); 3687a8a68f5SJulian Pullen if (new != NULL) 369*148c5f43SAlan Wright (void) memcpy(new, td, size); 3707a8a68f5SJulian Pullen return (new); 3717a8a68f5SJulian Pullen } 3727a8a68f5SJulian Pullen 3737a8a68f5SJulian Pullen 3747a8a68f5SJulian Pullen 3757a8a68f5SJulian Pullen int 3767a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1, 3777a8a68f5SJulian Pullen ad_disc_domainsinforest_t *df2) 3787a8a68f5SJulian Pullen { 3797a8a68f5SJulian Pullen int i, j; 3807a8a68f5SJulian Pullen int num_df1; 3817a8a68f5SJulian Pullen int num_df2; 3827a8a68f5SJulian Pullen boolean_t match; 3837a8a68f5SJulian Pullen 3847a8a68f5SJulian Pullen for (i = 0; df1[i].domain[0] != '\0'; i++) 3857a8a68f5SJulian Pullen continue; 3867a8a68f5SJulian Pullen num_df1 = i; 3877a8a68f5SJulian Pullen 3887a8a68f5SJulian Pullen for (j = 0; df2[j].domain[0] != '\0'; j++) 3897a8a68f5SJulian Pullen continue; 3907a8a68f5SJulian Pullen num_df2 = j; 3917a8a68f5SJulian Pullen 3927a8a68f5SJulian Pullen if (num_df1 != num_df2) 3937a8a68f5SJulian Pullen return (1); 3947a8a68f5SJulian Pullen 3957a8a68f5SJulian Pullen for (i = 0; i < num_df1; i++) { 3967a8a68f5SJulian Pullen match = B_FALSE; 3977a8a68f5SJulian Pullen for (j = 0; j < num_df2; j++) { 3981fcced4cSJordan Brown if (domain_eq(df1[i].domain, df2[j].domain) && 399928e1f97SJordan Brown strcmp(df1[i].sid, df2[j].sid) == 0) { 4007a8a68f5SJulian Pullen match = B_TRUE; 4017a8a68f5SJulian Pullen break; 4027a8a68f5SJulian Pullen } 4037a8a68f5SJulian Pullen } 4047a8a68f5SJulian Pullen if (!match) 4057a8a68f5SJulian Pullen return (1); 4067a8a68f5SJulian Pullen } 4077a8a68f5SJulian Pullen return (0); 4087a8a68f5SJulian Pullen } 4097a8a68f5SJulian Pullen 4107a8a68f5SJulian Pullen 4117a8a68f5SJulian Pullen 4127a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */ 4137a8a68f5SJulian Pullen static ad_disc_domainsinforest_t * 4147a8a68f5SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df) 4157a8a68f5SJulian Pullen { 4167a8a68f5SJulian Pullen int i; 4177a8a68f5SJulian Pullen int size; 4187a8a68f5SJulian Pullen ad_disc_domainsinforest_t *new = NULL; 4197a8a68f5SJulian Pullen 4207a8a68f5SJulian Pullen for (i = 0; df[i].domain[0] != '\0'; i++) 4217a8a68f5SJulian Pullen continue; 4227a8a68f5SJulian Pullen 4237a8a68f5SJulian Pullen size = (i + 1) * sizeof (ad_disc_domainsinforest_t); 4247a8a68f5SJulian Pullen new = malloc(size); 4257a8a68f5SJulian Pullen if (new != NULL) 426*148c5f43SAlan Wright (void) memcpy(new, df, size); 4277a8a68f5SJulian Pullen return (new); 4287a8a68f5SJulian Pullen } 4297a8a68f5SJulian Pullen 4307a8a68f5SJulian Pullen 4317a8a68f5SJulian Pullen 4327a8a68f5SJulian Pullen 4337a8a68f5SJulian Pullen 4347a8a68f5SJulian Pullen /* 4357a8a68f5SJulian Pullen * Returns an array of IPv4 address/prefix length 4367a8a68f5SJulian Pullen * The last subnet is NULL 4377a8a68f5SJulian Pullen */ 4387a8a68f5SJulian Pullen static ad_subnet_t * 4397a8a68f5SJulian Pullen find_subnets() 4407a8a68f5SJulian Pullen { 4417a8a68f5SJulian Pullen int sock, n, i; 4427a8a68f5SJulian Pullen struct lifconf lifc; 4437a8a68f5SJulian Pullen struct lifreq lifr, *lifrp; 4447a8a68f5SJulian Pullen struct lifnum lifn; 4457a8a68f5SJulian Pullen uint32_t prefix_len; 4467a8a68f5SJulian Pullen char *s; 4477a8a68f5SJulian Pullen ad_subnet_t *results; 4487a8a68f5SJulian Pullen 4497a8a68f5SJulian Pullen lifrp = &lifr; 4507a8a68f5SJulian Pullen 4517a8a68f5SJulian Pullen if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 4527a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to open IPv4 socket for " 4537a8a68f5SJulian Pullen "listing network interfaces (%s)", strerror(errno)); 4547a8a68f5SJulian Pullen return (NULL); 4557a8a68f5SJulian Pullen } 4567a8a68f5SJulian Pullen 4577a8a68f5SJulian Pullen lifn.lifn_family = AF_INET; 4587a8a68f5SJulian Pullen lifn.lifn_flags = 0; 4597a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) { 4607a8a68f5SJulian Pullen logger(LOG_ERR, 4617a8a68f5SJulian Pullen "Failed to find the number of network interfaces (%s)", 4627a8a68f5SJulian Pullen strerror(errno)); 463*148c5f43SAlan Wright (void) close(sock); 4647a8a68f5SJulian Pullen return (NULL); 4657a8a68f5SJulian Pullen } 4667a8a68f5SJulian Pullen 4677a8a68f5SJulian Pullen if (lifn.lifn_count < 1) { 4687a8a68f5SJulian Pullen logger(LOG_ERR, "No IPv4 network interfaces found"); 469*148c5f43SAlan Wright (void) close(sock); 4707a8a68f5SJulian Pullen return (NULL); 4717a8a68f5SJulian Pullen } 4727a8a68f5SJulian Pullen 4737a8a68f5SJulian Pullen lifc.lifc_family = AF_INET; 4747a8a68f5SJulian Pullen lifc.lifc_flags = 0; 4757a8a68f5SJulian Pullen lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 4767a8a68f5SJulian Pullen lifc.lifc_buf = malloc(lifc.lifc_len); 4777a8a68f5SJulian Pullen 4787a8a68f5SJulian Pullen if (lifc.lifc_buf == NULL) { 4797a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 480*148c5f43SAlan Wright (void) close(sock); 4817a8a68f5SJulian Pullen return (NULL); 4827a8a68f5SJulian Pullen } 4837a8a68f5SJulian Pullen 4847a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) { 4857a8a68f5SJulian Pullen logger(LOG_ERR, "Failed to list network interfaces (%s)", 4867a8a68f5SJulian Pullen strerror(errno)); 4877a8a68f5SJulian Pullen free(lifc.lifc_buf); 488*148c5f43SAlan Wright (void) close(sock); 4897a8a68f5SJulian Pullen return (NULL); 4907a8a68f5SJulian Pullen } 4917a8a68f5SJulian Pullen 4927a8a68f5SJulian Pullen n = lifc.lifc_len / (int)sizeof (struct lifreq); 4937a8a68f5SJulian Pullen 4947a8a68f5SJulian Pullen if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) { 4957a8a68f5SJulian Pullen free(lifc.lifc_buf); 496*148c5f43SAlan Wright (void) close(sock); 4977a8a68f5SJulian Pullen return (NULL); 4987a8a68f5SJulian Pullen } 4997a8a68f5SJulian Pullen 5007a8a68f5SJulian Pullen for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) { 5017a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0) 5027a8a68f5SJulian Pullen continue; 5037a8a68f5SJulian Pullen 5047a8a68f5SJulian Pullen if ((lifrp->lifr_flags & IFF_UP) == 0) 5057a8a68f5SJulian Pullen continue; 5067a8a68f5SJulian Pullen 5077a8a68f5SJulian Pullen if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0) 5087a8a68f5SJulian Pullen continue; 5097a8a68f5SJulian Pullen 5107a8a68f5SJulian Pullen prefix_len = lifrp->lifr_addrlen; 5117a8a68f5SJulian Pullen 5127a8a68f5SJulian Pullen s = inet_ntoa(((struct sockaddr_in *) 5137a8a68f5SJulian Pullen &lifrp->lifr_addr)->sin_addr); 5147a8a68f5SJulian Pullen 5157a8a68f5SJulian Pullen (void) snprintf(results[i].subnet, sizeof (ad_subnet_t), 5167a8a68f5SJulian Pullen "%s/%d", s, prefix_len); 5177a8a68f5SJulian Pullen } 5187a8a68f5SJulian Pullen 5197a8a68f5SJulian Pullen free(lifc.lifc_buf); 520*148c5f43SAlan Wright (void) close(sock); 5217a8a68f5SJulian Pullen 5227a8a68f5SJulian Pullen return (results); 5237a8a68f5SJulian Pullen } 5247a8a68f5SJulian Pullen 5257a8a68f5SJulian Pullen static int 5267a8a68f5SJulian Pullen cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2) 5277a8a68f5SJulian Pullen { 5287a8a68f5SJulian Pullen int num_subnets1; 5297a8a68f5SJulian Pullen int num_subnets2; 5307a8a68f5SJulian Pullen boolean_t matched; 5317a8a68f5SJulian Pullen int i, j; 5327a8a68f5SJulian Pullen 5337a8a68f5SJulian Pullen for (i = 0; subnets1[i].subnet[0] != '\0'; i++) 5347a8a68f5SJulian Pullen continue; 5357a8a68f5SJulian Pullen num_subnets1 = i; 5367a8a68f5SJulian Pullen 5377a8a68f5SJulian Pullen for (i = 0; subnets2[i].subnet[0] != '\0'; i++) 5387a8a68f5SJulian Pullen continue; 5397a8a68f5SJulian Pullen num_subnets2 = i; 5407a8a68f5SJulian Pullen 5417a8a68f5SJulian Pullen if (num_subnets1 != num_subnets2) 5427a8a68f5SJulian Pullen return (1); 5437a8a68f5SJulian Pullen 5447a8a68f5SJulian Pullen for (i = 0; i < num_subnets1; i++) { 5457a8a68f5SJulian Pullen matched = B_FALSE; 5467a8a68f5SJulian Pullen for (j = 0; j < num_subnets2; j++) { 5477a8a68f5SJulian Pullen if (strcmp(subnets1[i].subnet, 5487a8a68f5SJulian Pullen subnets2[j].subnet) == 0) { 5497a8a68f5SJulian Pullen matched = B_TRUE; 5507a8a68f5SJulian Pullen break; 5517a8a68f5SJulian Pullen } 5527a8a68f5SJulian Pullen } 5537a8a68f5SJulian Pullen if (!matched) 5547a8a68f5SJulian Pullen return (1); 5557a8a68f5SJulian Pullen } 5567a8a68f5SJulian Pullen return (0); 5577a8a68f5SJulian Pullen } 5587a8a68f5SJulian Pullen 5597a8a68f5SJulian Pullen 5607a8a68f5SJulian Pullen 5617a8a68f5SJulian Pullen 5627a8a68f5SJulian Pullen /* Convert a DN's DC components into a DNS domainname */ 5637a8a68f5SJulian Pullen char * 5647a8a68f5SJulian Pullen DN_to_DNS(const char *dn_name) 5657a8a68f5SJulian Pullen { 5667a8a68f5SJulian Pullen char dns[DNS_MAX_NAME]; 5677a8a68f5SJulian Pullen char *dns_name; 5687a8a68f5SJulian Pullen int i, j; 5697a8a68f5SJulian Pullen int num = 0; 5707a8a68f5SJulian Pullen 5717a8a68f5SJulian Pullen j = 0; 5727a8a68f5SJulian Pullen i = 0; 5737a8a68f5SJulian Pullen 5747a8a68f5SJulian Pullen if (dn_name == NULL) 5757a8a68f5SJulian Pullen return (NULL); 5767a8a68f5SJulian Pullen /* 5777a8a68f5SJulian Pullen * Find all DC=<value> and form DNS name of the 5787a8a68f5SJulian Pullen * form <value1>.<value2>... 5797a8a68f5SJulian Pullen */ 5807a8a68f5SJulian Pullen while (dn_name[i] != '\0') { 5817a8a68f5SJulian Pullen if (strncasecmp(&dn_name[i], "DC=", 3) == 0) { 5827a8a68f5SJulian Pullen i += 3; 5837a8a68f5SJulian Pullen if (dn_name[i] != '\0' && num > 0) 5847a8a68f5SJulian Pullen dns[j++] = '.'; 5857a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 5867a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 5877a8a68f5SJulian Pullen dns[j++] = dn_name[i++]; 5887a8a68f5SJulian Pullen num++; 5897a8a68f5SJulian Pullen } else { 5907a8a68f5SJulian Pullen /* Skip attr=value as it is not DC= */ 5917a8a68f5SJulian Pullen while (dn_name[i] != '\0' && 5927a8a68f5SJulian Pullen dn_name[i] != ',' && dn_name[i] != '+') 5937a8a68f5SJulian Pullen i++; 5947a8a68f5SJulian Pullen } 5957a8a68f5SJulian Pullen /* Skip over separator ',' or '+' */ 5967a8a68f5SJulian Pullen if (dn_name[i] != '\0') i++; 5977a8a68f5SJulian Pullen } 5987a8a68f5SJulian Pullen dns[j] = '\0'; 5997a8a68f5SJulian Pullen dns_name = malloc(j + 1); 6007a8a68f5SJulian Pullen if (dns_name != NULL) 6017a8a68f5SJulian Pullen (void) strlcpy(dns_name, dns, j + 1); 6027a8a68f5SJulian Pullen return (dns_name); 6037a8a68f5SJulian Pullen } 6047a8a68f5SJulian Pullen 6057a8a68f5SJulian Pullen 6067a8a68f5SJulian Pullen /* Make a list of subnet object DNs from a list of subnets */ 6077a8a68f5SJulian Pullen static char ** 6087a8a68f5SJulian Pullen subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn) 6097a8a68f5SJulian Pullen { 6107a8a68f5SJulian Pullen char **results; 6117a8a68f5SJulian Pullen int i, j; 6127a8a68f5SJulian Pullen 6137a8a68f5SJulian Pullen for (i = 0; subnets[i].subnet[0] != '\0'; i++) 6147a8a68f5SJulian Pullen continue; 6157a8a68f5SJulian Pullen 6167a8a68f5SJulian Pullen results = calloc(i + 1, sizeof (char *)); 6177a8a68f5SJulian Pullen if (results == NULL) 6187a8a68f5SJulian Pullen return (NULL); 6197a8a68f5SJulian Pullen 6207a8a68f5SJulian Pullen for (i = 0; subnets[i].subnet[0] != '\0'; i++) { 621c5866007SKeyur Desai (void) asprintf(&results[i], "CN=%s,CN=Subnets,CN=Sites,%s", 622c5866007SKeyur Desai subnets[i].subnet, base_dn); 623c5866007SKeyur Desai if (results[i] == NULL) { 6247a8a68f5SJulian Pullen for (j = 0; j < i; j++) 6257a8a68f5SJulian Pullen free(results[j]); 6267a8a68f5SJulian Pullen free(results); 6277a8a68f5SJulian Pullen return (NULL); 6287a8a68f5SJulian Pullen } 6297a8a68f5SJulian Pullen } 6307a8a68f5SJulian Pullen 6317a8a68f5SJulian Pullen return (results); 6327a8a68f5SJulian Pullen } 6337a8a68f5SJulian Pullen 6347a8a68f5SJulian Pullen 6357a8a68f5SJulian Pullen /* Compare SRC RRs; used with qsort() */ 6367a8a68f5SJulian Pullen static int 6377a8a68f5SJulian Pullen srvcmp(idmap_ad_disc_ds_t *s1, idmap_ad_disc_ds_t *s2) 6387a8a68f5SJulian Pullen { 6397a8a68f5SJulian Pullen if (s1->priority < s2->priority) 6407a8a68f5SJulian Pullen return (1); 6417a8a68f5SJulian Pullen else if (s1->priority > s2->priority) 6427a8a68f5SJulian Pullen return (-1); 6437a8a68f5SJulian Pullen 6447a8a68f5SJulian Pullen if (s1->weight < s2->weight) 6457a8a68f5SJulian Pullen return (1); 6467a8a68f5SJulian Pullen else if (s1->weight > s2->weight) 6477a8a68f5SJulian Pullen return (-1); 6487a8a68f5SJulian Pullen 6497a8a68f5SJulian Pullen return (0); 6507a8a68f5SJulian Pullen } 6517a8a68f5SJulian Pullen 6527a8a68f5SJulian Pullen 6537a8a68f5SJulian Pullen /* 6547a8a68f5SJulian Pullen * Query or search the SRV RRs for a given name. 6557a8a68f5SJulian Pullen * 6567a8a68f5SJulian Pullen * If name == NULL then search (as in res_nsearch(3RESOLV), honoring any 6577a8a68f5SJulian Pullen * search list/option), else query (as in res_nquery(3RESOLV)). 6587a8a68f5SJulian Pullen * 6597a8a68f5SJulian Pullen * The output TTL will be the one of the SRV RR with the lowest TTL. 6607a8a68f5SJulian Pullen */ 6617a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 6627a8a68f5SJulian Pullen srv_query(res_state state, const char *svc_name, const char *dname, 6637a8a68f5SJulian Pullen char **rrname, uint32_t *ttl) 6647a8a68f5SJulian Pullen { 6657a8a68f5SJulian Pullen idmap_ad_disc_ds_t *srv; 666bbf6f00cSJordan Brown idmap_ad_disc_ds_t *srv_res = NULL; 6677a8a68f5SJulian Pullen union { 6687a8a68f5SJulian Pullen HEADER hdr; 6697a8a68f5SJulian Pullen uchar_t buf[NS_MAXMSG]; 6707a8a68f5SJulian Pullen } msg; 6717a8a68f5SJulian Pullen int len, cnt, qdcount, ancount; 6727a8a68f5SJulian Pullen uchar_t *ptr, *eom; 6737a8a68f5SJulian Pullen uchar_t *end; 6747a8a68f5SJulian Pullen uint16_t type; 6757a8a68f5SJulian Pullen /* LINTED E_FUNC_SET_NOT_USED */ 6767a8a68f5SJulian Pullen uint16_t class; 6777a8a68f5SJulian Pullen uint32_t rttl; 6787a8a68f5SJulian Pullen uint16_t size; 6797a8a68f5SJulian Pullen char namebuf[NS_MAXDNAME]; 6807a8a68f5SJulian Pullen 6817a8a68f5SJulian Pullen if (state == NULL) 6827a8a68f5SJulian Pullen return (NULL); 6837a8a68f5SJulian Pullen 6847a8a68f5SJulian Pullen /* Set negative result TTL */ 6857a8a68f5SJulian Pullen *ttl = 5 * 60; 6867a8a68f5SJulian Pullen 6877a8a68f5SJulian Pullen /* 1. query necessary resource records */ 6887a8a68f5SJulian Pullen 6897a8a68f5SJulian Pullen /* Search, querydomain or query */ 6907a8a68f5SJulian Pullen if (rrname != NULL) { 6917a8a68f5SJulian Pullen *rrname = NULL; 692*148c5f43SAlan Wright if (DBG(DNS, 1)) { 693*148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for SRV RRs '%s.*'", 694*148c5f43SAlan Wright svc_name); 695*148c5f43SAlan Wright } 6967a8a68f5SJulian Pullen len = res_nsearch(state, svc_name, C_IN, T_SRV, 6977a8a68f5SJulian Pullen msg.buf, sizeof (msg.buf)); 6987a8a68f5SJulian Pullen if (len < 0) { 699*148c5f43SAlan Wright if (DBG(DNS, 0)) { 700*148c5f43SAlan Wright logger(LOG_DEBUG, 701*148c5f43SAlan Wright "DNS search for '%s' failed (%s)", 7027a8a68f5SJulian Pullen svc_name, hstrerror(state->res_h_errno)); 703*148c5f43SAlan Wright } 7047a8a68f5SJulian Pullen return (NULL); 7057a8a68f5SJulian Pullen } 7067a8a68f5SJulian Pullen } else if (dname != NULL) { 707*148c5f43SAlan Wright if (DBG(DNS, 1)) { 708*148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for SRV RRs '%s.%s' ", 7097a8a68f5SJulian Pullen svc_name, dname); 710*148c5f43SAlan Wright } 7117a8a68f5SJulian Pullen 712e3f2c991SKeyur Desai len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV, 713e3f2c991SKeyur Desai msg.buf, sizeof (msg.buf)); 714e3f2c991SKeyur Desai 7157a8a68f5SJulian Pullen if (len < 0) { 716*148c5f43SAlan Wright if (DBG(DNS, 0)) { 717*148c5f43SAlan Wright logger(LOG_DEBUG, "DNS: %s.%s: %s", 718*148c5f43SAlan Wright svc_name, dname, 719*148c5f43SAlan Wright hstrerror(state->res_h_errno)); 720*148c5f43SAlan Wright } 7217a8a68f5SJulian Pullen return (NULL); 7227a8a68f5SJulian Pullen } 7237a8a68f5SJulian Pullen } 7247a8a68f5SJulian Pullen 7257a8a68f5SJulian Pullen if (len > sizeof (msg.buf)) { 726*148c5f43SAlan Wright logger(LOG_ERR, 727*148c5f43SAlan Wright "DNS query %ib message doesn't fit into %ib buffer", 7287a8a68f5SJulian Pullen len, sizeof (msg.buf)); 7297a8a68f5SJulian Pullen return (NULL); 7307a8a68f5SJulian Pullen } 7317a8a68f5SJulian Pullen 7327a8a68f5SJulian Pullen /* 2. parse the reply, skip header and question sections */ 7337a8a68f5SJulian Pullen 7347a8a68f5SJulian Pullen ptr = msg.buf + sizeof (msg.hdr); 7357a8a68f5SJulian Pullen eom = msg.buf + len; 7367a8a68f5SJulian Pullen qdcount = ntohs(msg.hdr.qdcount); 7377a8a68f5SJulian Pullen ancount = ntohs(msg.hdr.ancount); 7387a8a68f5SJulian Pullen 7397a8a68f5SJulian Pullen for (cnt = qdcount; cnt > 0; --cnt) { 7407a8a68f5SJulian Pullen if ((len = dn_skipname(ptr, eom)) < 0) { 7417a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 7427a8a68f5SJulian Pullen return (NULL); 7437a8a68f5SJulian Pullen } 7447a8a68f5SJulian Pullen ptr += len + QFIXEDSZ; 7457a8a68f5SJulian Pullen } 7467a8a68f5SJulian Pullen 7477a8a68f5SJulian Pullen /* 3. walk through the answer section */ 7487a8a68f5SJulian Pullen 7497a8a68f5SJulian Pullen srv_res = calloc(ancount + 1, sizeof (idmap_ad_disc_ds_t)); 750bbf6f00cSJordan Brown if (srv_res == NULL) { 751bbf6f00cSJordan Brown logger(LOG_ERR, "Out of memory"); 752bbf6f00cSJordan Brown return (NULL); 753bbf6f00cSJordan Brown } 754bbf6f00cSJordan Brown 7557a8a68f5SJulian Pullen *ttl = (uint32_t)-1; 7567a8a68f5SJulian Pullen 7577a8a68f5SJulian Pullen for (srv = srv_res, cnt = ancount; 7587a8a68f5SJulian Pullen cnt > 0; --cnt, srv++) { 7597a8a68f5SJulian Pullen 7607a8a68f5SJulian Pullen len = dn_expand(msg.buf, eom, ptr, namebuf, 7617a8a68f5SJulian Pullen sizeof (namebuf)); 7627a8a68f5SJulian Pullen if (len < 0) { 7637a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 764bbf6f00cSJordan Brown goto err; 7657a8a68f5SJulian Pullen } 766bbf6f00cSJordan Brown if (rrname != NULL && *rrname == NULL) { 7677a8a68f5SJulian Pullen *rrname = strdup(namebuf); 768bbf6f00cSJordan Brown if (*rrname == NULL) { 769bbf6f00cSJordan Brown logger(LOG_ERR, "Out of memory"); 770bbf6f00cSJordan Brown goto err; 771bbf6f00cSJordan Brown } 772bbf6f00cSJordan Brown } 7737a8a68f5SJulian Pullen ptr += len; 7747a8a68f5SJulian Pullen NS_GET16(type, ptr); 7757a8a68f5SJulian Pullen NS_GET16(class, ptr); 7767a8a68f5SJulian Pullen NS_GET32(rttl, ptr); 7777a8a68f5SJulian Pullen NS_GET16(size, ptr); 7787a8a68f5SJulian Pullen if ((end = ptr + size) > eom) { 7797a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid message format"); 780bbf6f00cSJordan Brown goto err; 7817a8a68f5SJulian Pullen } 7827a8a68f5SJulian Pullen 7837a8a68f5SJulian Pullen if (type != T_SRV) { 7847a8a68f5SJulian Pullen ptr = end; 7857a8a68f5SJulian Pullen continue; 7867a8a68f5SJulian Pullen } 7877a8a68f5SJulian Pullen 7887a8a68f5SJulian Pullen NS_GET16(srv->priority, ptr); 7897a8a68f5SJulian Pullen NS_GET16(srv->weight, ptr); 7907a8a68f5SJulian Pullen NS_GET16(srv->port, ptr); 7917a8a68f5SJulian Pullen len = dn_expand(msg.buf, eom, ptr, srv->host, 7927a8a68f5SJulian Pullen sizeof (srv->host)); 7937a8a68f5SJulian Pullen if (len < 0) { 7947a8a68f5SJulian Pullen logger(LOG_ERR, "DNS query invalid SRV record"); 795bbf6f00cSJordan Brown goto err; 7967a8a68f5SJulian Pullen } 7977a8a68f5SJulian Pullen 7987a8a68f5SJulian Pullen if (rttl < *ttl) 7997a8a68f5SJulian Pullen *ttl = rttl; 8007a8a68f5SJulian Pullen 801*148c5f43SAlan Wright if (DBG(DNS, 1)) { 802*148c5f43SAlan Wright logger(LOG_DEBUG, " %s", namebuf); 803*148c5f43SAlan Wright logger(LOG_DEBUG, 804*148c5f43SAlan Wright " ttl=%d pri=%d weight=%d %s:%d", 805*148c5f43SAlan Wright rttl, srv->priority, srv->weight, 806*148c5f43SAlan Wright srv->host, srv->port); 807*148c5f43SAlan Wright } 8087a8a68f5SJulian Pullen 8097a8a68f5SJulian Pullen /* 3. move ptr to the end of current record */ 8107a8a68f5SJulian Pullen 8117a8a68f5SJulian Pullen ptr = end; 8127a8a68f5SJulian Pullen } 8137a8a68f5SJulian Pullen 8147a8a68f5SJulian Pullen if (ancount > 1) 8157a8a68f5SJulian Pullen qsort(srv_res, ancount, sizeof (*srv_res), 8167a8a68f5SJulian Pullen (int (*)(const void *, const void *))srvcmp); 8177a8a68f5SJulian Pullen 8187a8a68f5SJulian Pullen return (srv_res); 819bbf6f00cSJordan Brown 820bbf6f00cSJordan Brown err: 821bbf6f00cSJordan Brown free(srv_res); 822bbf6f00cSJordan Brown if (rrname != NULL) { 823bbf6f00cSJordan Brown free(*rrname); 824bbf6f00cSJordan Brown *rrname = NULL; 825bbf6f00cSJordan Brown } 826bbf6f00cSJordan Brown return (NULL); 8277a8a68f5SJulian Pullen } 8287a8a68f5SJulian Pullen 8297a8a68f5SJulian Pullen 8307a8a68f5SJulian Pullen /* 8317a8a68f5SJulian Pullen * A utility function to bind to a Directory server 8327a8a68f5SJulian Pullen */ 8337a8a68f5SJulian Pullen 834c5866007SKeyur Desai static 835c5866007SKeyur Desai LDAP * 8367a8a68f5SJulian Pullen ldap_lookup_init(idmap_ad_disc_ds_t *ds) 8377a8a68f5SJulian Pullen { 8387a8a68f5SJulian Pullen int i; 8397a8a68f5SJulian Pullen int rc, ldversion; 8407a8a68f5SJulian Pullen int zero = 0; 8417a8a68f5SJulian Pullen int timeoutms = 5 * 1000; 8427a8a68f5SJulian Pullen char *saslmech = "GSSAPI"; 8437a8a68f5SJulian Pullen uint32_t saslflags = LDAP_SASL_INTERACTIVE; 8447a8a68f5SJulian Pullen LDAP *ld = NULL; 8457a8a68f5SJulian Pullen 8467a8a68f5SJulian Pullen for (i = 0; ds[i].host[0] != '\0'; i++) { 8477a8a68f5SJulian Pullen ld = ldap_init(ds[i].host, ds[i].port); 8487a8a68f5SJulian Pullen if (ld == NULL) { 849*148c5f43SAlan Wright if (DBG(LDAP, 1)) { 850*148c5f43SAlan Wright logger(LOG_DEBUG, 851*148c5f43SAlan Wright "Couldn't connect to AD DC %s:%d (%s)", 8527a8a68f5SJulian Pullen ds[i].host, ds[i].port, 8537a8a68f5SJulian Pullen strerror(errno)); 854*148c5f43SAlan Wright } 8557a8a68f5SJulian Pullen continue; 8567a8a68f5SJulian Pullen } 8577a8a68f5SJulian Pullen 8587a8a68f5SJulian Pullen ldversion = LDAP_VERSION3; 8597a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 8607a8a68f5SJulian Pullen &ldversion); 8617a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, 8627a8a68f5SJulian Pullen LDAP_OPT_OFF); 8637a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero); 8647a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero); 8657a8a68f5SJulian Pullen /* setup TCP/IP connect timeout */ 8667a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, 8677a8a68f5SJulian Pullen &timeoutms); 8687a8a68f5SJulian Pullen (void) ldap_set_option(ld, LDAP_OPT_RESTART, 8697a8a68f5SJulian Pullen LDAP_OPT_ON); 8707a8a68f5SJulian Pullen 871bd428526SJulian Pullen rc = adutils_set_thread_functions(ld); 872bd428526SJulian Pullen if (rc != LDAP_SUCCESS) { 873bd428526SJulian Pullen /* Error has already been logged */ 874bd428526SJulian Pullen (void) ldap_unbind(ld); 875bd428526SJulian Pullen ld = NULL; 876bd428526SJulian Pullen continue; 877bd428526SJulian Pullen } 878bd428526SJulian Pullen 8797a8a68f5SJulian Pullen rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */, 8807a8a68f5SJulian Pullen saslmech, NULL, NULL, saslflags, &saslcallback, 8817a8a68f5SJulian Pullen NULL /* defaults */); 8827a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) 8837a8a68f5SJulian Pullen break; 8847a8a68f5SJulian Pullen 885*148c5f43SAlan Wright if (DBG(LDAP, 0)) { 886*148c5f43SAlan Wright logger(LOG_INFO, "LDAP: %s:%d: %s", 8877a8a68f5SJulian Pullen ds[i].host, ds[i].port, ldap_err2string(rc)); 888*148c5f43SAlan Wright ldap_perror(ld, ds[i].host); 889*148c5f43SAlan Wright } 8907a8a68f5SJulian Pullen (void) ldap_unbind(ld); 8917a8a68f5SJulian Pullen ld = NULL; 8927a8a68f5SJulian Pullen } 8937a8a68f5SJulian Pullen return (ld); 8947a8a68f5SJulian Pullen } 8957a8a68f5SJulian Pullen 8967a8a68f5SJulian Pullen 8977a8a68f5SJulian Pullen 8987a8a68f5SJulian Pullen /* 8997a8a68f5SJulian Pullen * A utility function to get the value of some attribute of one of one 9007a8a68f5SJulian Pullen * or more AD LDAP objects named by the dn_list; first found one wins. 9017a8a68f5SJulian Pullen */ 9027a8a68f5SJulian Pullen static char * 9037a8a68f5SJulian Pullen ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers, 9047a8a68f5SJulian Pullen char **dn_list, char *attr) 9057a8a68f5SJulian Pullen { 9067a8a68f5SJulian Pullen int i; 9077a8a68f5SJulian Pullen int rc; 9087a8a68f5SJulian Pullen int scope = LDAP_SCOPE_BASE; 9097a8a68f5SJulian Pullen char *attrs[2]; 9107a8a68f5SJulian Pullen LDAPMessage *results = NULL; 9117a8a68f5SJulian Pullen LDAPMessage *entry; 9127a8a68f5SJulian Pullen char **values = NULL; 9137a8a68f5SJulian Pullen char *val = NULL; 9147a8a68f5SJulian Pullen 9157a8a68f5SJulian Pullen attrs[0] = attr; 9167a8a68f5SJulian Pullen attrs[1] = NULL; 9177a8a68f5SJulian Pullen 9187a8a68f5SJulian Pullen if (*ld == NULL) 9197a8a68f5SJulian Pullen *ld = ldap_lookup_init(domainControllers); 9207a8a68f5SJulian Pullen 9217a8a68f5SJulian Pullen if (*ld == NULL) 9227a8a68f5SJulian Pullen return (NULL); 9237a8a68f5SJulian Pullen 9247a8a68f5SJulian Pullen for (i = 0; dn_list[i] != NULL; i++) { 9257a8a68f5SJulian Pullen rc = ldap_search_s(*ld, dn_list[i], scope, 9267a8a68f5SJulian Pullen "(objectclass=*)", attrs, 0, &results); 9277a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 9287a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 9297a8a68f5SJulian Pullen entry != NULL && values == NULL; 9307a8a68f5SJulian Pullen entry = ldap_next_entry(*ld, entry)) { 9317a8a68f5SJulian Pullen values = ldap_get_values( 9327a8a68f5SJulian Pullen *ld, entry, attr); 9337a8a68f5SJulian Pullen } 9347a8a68f5SJulian Pullen 9357a8a68f5SJulian Pullen if (values != NULL) { 9367a8a68f5SJulian Pullen (void) ldap_msgfree(results); 9377a8a68f5SJulian Pullen val = strdup(values[0]); 9387a8a68f5SJulian Pullen ldap_value_free(values); 9397a8a68f5SJulian Pullen return (val); 9407a8a68f5SJulian Pullen } 9417a8a68f5SJulian Pullen } 9427a8a68f5SJulian Pullen if (results != NULL) { 9437a8a68f5SJulian Pullen (void) ldap_msgfree(results); 9447a8a68f5SJulian Pullen results = NULL; 9457a8a68f5SJulian Pullen } 9467a8a68f5SJulian Pullen } 9477a8a68f5SJulian Pullen 9487a8a68f5SJulian Pullen return (NULL); 9497a8a68f5SJulian Pullen } 9507a8a68f5SJulian Pullen 9517a8a68f5SJulian Pullen 9527a8a68f5SJulian Pullen /* 9537a8a68f5SJulian Pullen * Lookup the trusted domains in the global catalog. 9547a8a68f5SJulian Pullen * 9557a8a68f5SJulian Pullen * Returns: 9567a8a68f5SJulian Pullen * array of trusted domains which is terminated by 9577a8a68f5SJulian Pullen * an empty trusted domain. 9587a8a68f5SJulian Pullen * NULL an error occured 9597a8a68f5SJulian Pullen */ 9607a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 9617a8a68f5SJulian Pullen ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog, 9627a8a68f5SJulian Pullen char *base_dn) 9637a8a68f5SJulian Pullen { 9647a8a68f5SJulian Pullen int scope = LDAP_SCOPE_SUBTREE; 9657a8a68f5SJulian Pullen char *attrs[3]; 9667a8a68f5SJulian Pullen int rc; 9677a8a68f5SJulian Pullen LDAPMessage *results = NULL; 9687a8a68f5SJulian Pullen LDAPMessage *entry; 9697a8a68f5SJulian Pullen char *filter; 9707a8a68f5SJulian Pullen char **partner = NULL; 9717a8a68f5SJulian Pullen char **direction = NULL; 9727a8a68f5SJulian Pullen int num = 0; 9737a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 9747a8a68f5SJulian Pullen 975*148c5f43SAlan Wright if (DBG(DISC, 1)) 976*148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for trusted domains..."); 9777a8a68f5SJulian Pullen 9787a8a68f5SJulian Pullen if (*ld == NULL) 9797a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalog); 9807a8a68f5SJulian Pullen 9817a8a68f5SJulian Pullen if (*ld == NULL) 9827a8a68f5SJulian Pullen return (NULL); 9837a8a68f5SJulian Pullen 9847a8a68f5SJulian Pullen attrs[0] = "trustPartner"; 9857a8a68f5SJulian Pullen attrs[1] = "trustDirection"; 9867a8a68f5SJulian Pullen attrs[2] = NULL; 9877a8a68f5SJulian Pullen 988*148c5f43SAlan Wright /* 989*148c5f43SAlan Wright * Trust direction values: 990*148c5f43SAlan Wright * 1 - inbound (they trust us) 991*148c5f43SAlan Wright * 2 - outbound (we trust them) 992*148c5f43SAlan Wright * 3 - bidirectional (we trust each other) 993*148c5f43SAlan Wright */ 9947a8a68f5SJulian Pullen filter = "(&(objectclass=trustedDomain)" 995*148c5f43SAlan Wright "(|(trustDirection=3)(trustDirection=2)))"; 9967a8a68f5SJulian Pullen 9977a8a68f5SJulian Pullen rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results); 998*148c5f43SAlan Wright if (DBG(DISC, 1)) 999*148c5f43SAlan Wright logger(LOG_DEBUG, "Trusted domains:"); 10007a8a68f5SJulian Pullen if (rc == LDAP_SUCCESS) { 10017a8a68f5SJulian Pullen for (entry = ldap_first_entry(*ld, results); 10027a8a68f5SJulian Pullen entry != NULL; entry = ldap_next_entry(*ld, entry)) { 10037a8a68f5SJulian Pullen partner = ldap_get_values(*ld, entry, "trustPartner"); 10047a8a68f5SJulian Pullen direction = ldap_get_values( 10057a8a68f5SJulian Pullen *ld, entry, "trustDirection"); 10067a8a68f5SJulian Pullen 10077a8a68f5SJulian Pullen if (partner != NULL && direction != NULL) { 1008*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1009*148c5f43SAlan Wright logger(LOG_DEBUG, " %s (%s)", 1010*148c5f43SAlan Wright partner[0], direction[0]); 1011*148c5f43SAlan Wright } 10127a8a68f5SJulian Pullen num++; 1013c5866007SKeyur Desai void *tmp = realloc(trusted_domains, 10147a8a68f5SJulian Pullen (num + 1) * 10157a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 1016c5866007SKeyur Desai if (tmp == NULL) { 1017c5866007SKeyur Desai free(trusted_domains); 10187a8a68f5SJulian Pullen ldap_value_free(partner); 10197a8a68f5SJulian Pullen ldap_value_free(direction); 1020*148c5f43SAlan Wright (void) ldap_msgfree(results); 10217a8a68f5SJulian Pullen return (NULL); 10227a8a68f5SJulian Pullen } 1023c5866007SKeyur Desai trusted_domains = tmp; 10247a8a68f5SJulian Pullen /* Last element should be zero */ 1025*148c5f43SAlan Wright (void) memset(&trusted_domains[num], 0, 10267a8a68f5SJulian Pullen sizeof (ad_disc_trusteddomains_t)); 1027*148c5f43SAlan Wright (void) strcpy(trusted_domains[num - 1].domain, 10287a8a68f5SJulian Pullen partner[0]); 10297a8a68f5SJulian Pullen trusted_domains[num - 1].direction = 10307a8a68f5SJulian Pullen atoi(direction[0]); 10317a8a68f5SJulian Pullen } 10327a8a68f5SJulian Pullen if (partner != NULL) 10337a8a68f5SJulian Pullen ldap_value_free(partner); 10347a8a68f5SJulian Pullen if (direction != NULL) 10357a8a68f5SJulian Pullen ldap_value_free(direction); 10367a8a68f5SJulian Pullen } 10377a8a68f5SJulian Pullen } else if (rc == LDAP_NO_RESULTS_RETURNED) { 10387a8a68f5SJulian Pullen /* This is not an error - return empty trusted domain */ 10397a8a68f5SJulian Pullen trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t)); 1040*148c5f43SAlan Wright if (DBG(DISC, 1)) 1041*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 10427a8a68f5SJulian Pullen } 10437a8a68f5SJulian Pullen if (results != NULL) 1044*148c5f43SAlan Wright (void) ldap_msgfree(results); 10457a8a68f5SJulian Pullen 10467a8a68f5SJulian Pullen return (trusted_domains); 10477a8a68f5SJulian Pullen } 10487a8a68f5SJulian Pullen 10497a8a68f5SJulian Pullen 10507a8a68f5SJulian Pullen /* 10517a8a68f5SJulian Pullen * This functions finds all the domains in a forest. 10527a8a68f5SJulian Pullen */ 10537a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 10547a8a68f5SJulian Pullen ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs) 10557a8a68f5SJulian Pullen { 1056928e1f97SJordan Brown static char *attrs[] = { 1057928e1f97SJordan Brown "objectSid", 1058928e1f97SJordan Brown NULL, 1059928e1f97SJordan Brown }; 10607a8a68f5SJulian Pullen int rc; 10617a8a68f5SJulian Pullen LDAPMessage *result = NULL; 10627a8a68f5SJulian Pullen LDAPMessage *entry; 1063928e1f97SJordan Brown int ndomains = 0; 1064928e1f97SJordan Brown int nresults; 10657a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains = NULL; 10667a8a68f5SJulian Pullen 1067*148c5f43SAlan Wright if (DBG(DISC, 2)) 1068*148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for domains in forest..."); 1069*148c5f43SAlan Wright 10707a8a68f5SJulian Pullen if (*ld == NULL) 10717a8a68f5SJulian Pullen *ld = ldap_lookup_init(globalCatalogs); 10727a8a68f5SJulian Pullen 10737a8a68f5SJulian Pullen if (*ld == NULL) 10747a8a68f5SJulian Pullen return (NULL); 10757a8a68f5SJulian Pullen 10767a8a68f5SJulian Pullen /* Find domains */ 1077928e1f97SJordan Brown rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE, 1078928e1f97SJordan Brown "(objectClass=Domain)", attrs, 0, &result); 1079*148c5f43SAlan Wright if (DBG(DISC, 1)) 1080*148c5f43SAlan Wright logger(LOG_DEBUG, "Domains in forest:"); 1081928e1f97SJordan Brown if (rc != LDAP_SUCCESS) 1082928e1f97SJordan Brown goto err; 1083928e1f97SJordan Brown 1084928e1f97SJordan Brown nresults = ldap_count_entries(*ld, result); 1085928e1f97SJordan Brown domains = calloc(nresults + 1, sizeof (*domains)); 1086928e1f97SJordan Brown if (domains == NULL) 1087928e1f97SJordan Brown goto err; 1088928e1f97SJordan Brown 1089928e1f97SJordan Brown for (entry = ldap_first_entry(*ld, result); 1090928e1f97SJordan Brown entry != NULL; 1091928e1f97SJordan Brown entry = ldap_next_entry(*ld, entry)) { 1092928e1f97SJordan Brown struct berval **sid_ber; 1093928e1f97SJordan Brown adutils_sid_t sid; 1094928e1f97SJordan Brown char *sid_str; 1095928e1f97SJordan Brown char *name; 1096bbf6f00cSJordan Brown char *dn; 1097928e1f97SJordan Brown 10987a8a68f5SJulian Pullen sid_ber = ldap_get_values_len(*ld, entry, 10997a8a68f5SJulian Pullen "objectSid"); 1100928e1f97SJordan Brown if (sid_ber == NULL) 1101928e1f97SJordan Brown continue; 11027a8a68f5SJulian Pullen 1103928e1f97SJordan Brown rc = adutils_getsid(sid_ber[0], &sid); 11047a8a68f5SJulian Pullen ldap_value_free_len(sid_ber); 1105928e1f97SJordan Brown if (rc < 0) 1106928e1f97SJordan Brown goto err; 11077a8a68f5SJulian Pullen 1108928e1f97SJordan Brown if ((sid_str = adutils_sid2txt(&sid)) == NULL) 1109928e1f97SJordan Brown goto err; 1110928e1f97SJordan Brown 1111*148c5f43SAlan Wright (void) strcpy(domains[ndomains].sid, sid_str); 11127a8a68f5SJulian Pullen free(sid_str); 11137a8a68f5SJulian Pullen 1114bbf6f00cSJordan Brown dn = ldap_get_dn(*ld, entry); 1115bbf6f00cSJordan Brown name = DN_to_DNS(dn); 1116bbf6f00cSJordan Brown free(dn); 1117928e1f97SJordan Brown if (name == NULL) 1118928e1f97SJordan Brown goto err; 1119928e1f97SJordan Brown 1120*148c5f43SAlan Wright (void) strcpy(domains[ndomains].domain, name); 11217a8a68f5SJulian Pullen free(name); 1122928e1f97SJordan Brown 1123*148c5f43SAlan Wright if (DBG(DISC, 1)) 1124*148c5f43SAlan Wright logger(LOG_DEBUG, " %s", domains[ndomains].domain); 1125928e1f97SJordan Brown 1126928e1f97SJordan Brown ndomains++; 11277a8a68f5SJulian Pullen } 1128928e1f97SJordan Brown 1129*148c5f43SAlan Wright if (ndomains == 0) { 1130*148c5f43SAlan Wright if (DBG(DISC, 1)) 1131*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 1132928e1f97SJordan Brown goto err; 1133*148c5f43SAlan Wright } 1134928e1f97SJordan Brown 1135928e1f97SJordan Brown if (ndomains < nresults) { 1136928e1f97SJordan Brown ad_disc_domainsinforest_t *tmp; 1137928e1f97SJordan Brown tmp = realloc(domains, (ndomains + 1) * sizeof (*domains)); 1138928e1f97SJordan Brown if (tmp == NULL) 1139928e1f97SJordan Brown goto err; 1140928e1f97SJordan Brown domains = tmp; 11417a8a68f5SJulian Pullen } 1142928e1f97SJordan Brown 11437a8a68f5SJulian Pullen if (result != NULL) 1144*148c5f43SAlan Wright (void) ldap_msgfree(result); 11457a8a68f5SJulian Pullen 11467a8a68f5SJulian Pullen return (domains); 1147928e1f97SJordan Brown 1148928e1f97SJordan Brown err: 1149928e1f97SJordan Brown free(domains); 1150928e1f97SJordan Brown if (result != NULL) 1151*148c5f43SAlan Wright (void) ldap_msgfree(result); 1152928e1f97SJordan Brown return (NULL); 11537a8a68f5SJulian Pullen } 11547a8a68f5SJulian Pullen 11557a8a68f5SJulian Pullen 11567a8a68f5SJulian Pullen ad_disc_t 11577a8a68f5SJulian Pullen ad_disc_init(void) 11587a8a68f5SJulian Pullen { 11597a8a68f5SJulian Pullen struct ad_disc *ctx; 11607a8a68f5SJulian Pullen ctx = calloc(1, sizeof (struct ad_disc)); 11617a8a68f5SJulian Pullen if (ctx != NULL) 11627a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 11637a8a68f5SJulian Pullen 11647a8a68f5SJulian Pullen ctx->domain_name.type = AD_STRING; 11657a8a68f5SJulian Pullen ctx->domain_controller.type = AD_DIRECTORY; 11667a8a68f5SJulian Pullen ctx->site_name.type = AD_STRING; 11677a8a68f5SJulian Pullen ctx->forest_name.type = AD_STRING; 11687a8a68f5SJulian Pullen ctx->global_catalog.type = AD_DIRECTORY; 11697a8a68f5SJulian Pullen ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST; 11707a8a68f5SJulian Pullen ctx->trusted_domains.type = AD_TRUSTED_DOMAINS; 11717a8a68f5SJulian Pullen /* Site specific versions */ 11727a8a68f5SJulian Pullen ctx->site_domain_controller.type = AD_DIRECTORY; 11737a8a68f5SJulian Pullen ctx->site_global_catalog.type = AD_DIRECTORY; 11747a8a68f5SJulian Pullen return (ctx); 11757a8a68f5SJulian Pullen } 11767a8a68f5SJulian Pullen 11777a8a68f5SJulian Pullen void 11787a8a68f5SJulian Pullen ad_disc_fini(ad_disc_t ctx) 11797a8a68f5SJulian Pullen { 11807a8a68f5SJulian Pullen if (ctx == NULL) 11817a8a68f5SJulian Pullen return; 11827a8a68f5SJulian Pullen 11837a8a68f5SJulian Pullen if (ctx->res_ninitted) 11847a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 11857a8a68f5SJulian Pullen 11867a8a68f5SJulian Pullen if (ctx->subnets != NULL) 11877a8a68f5SJulian Pullen free(ctx->subnets); 11887a8a68f5SJulian Pullen 11897a8a68f5SJulian Pullen if (ctx->domain_name.value != NULL) 11907a8a68f5SJulian Pullen free(ctx->domain_name.value); 11917a8a68f5SJulian Pullen 11927a8a68f5SJulian Pullen if (ctx->domain_controller.value != NULL) 11937a8a68f5SJulian Pullen free(ctx->domain_controller.value); 11947a8a68f5SJulian Pullen 11957a8a68f5SJulian Pullen if (ctx->site_name.value != NULL) 11967a8a68f5SJulian Pullen free(ctx->site_name.value); 11977a8a68f5SJulian Pullen 11987a8a68f5SJulian Pullen if (ctx->forest_name.value != NULL) 11997a8a68f5SJulian Pullen free(ctx->forest_name.value); 12007a8a68f5SJulian Pullen 12017a8a68f5SJulian Pullen if (ctx->global_catalog.value != NULL) 12027a8a68f5SJulian Pullen free(ctx->global_catalog.value); 12037a8a68f5SJulian Pullen 12047a8a68f5SJulian Pullen if (ctx->domains_in_forest.value != NULL) 12057a8a68f5SJulian Pullen free(ctx->domains_in_forest.value); 12067a8a68f5SJulian Pullen 12077a8a68f5SJulian Pullen if (ctx->trusted_domains.value != NULL) 12087a8a68f5SJulian Pullen free(ctx->trusted_domains.value); 12097a8a68f5SJulian Pullen 12107a8a68f5SJulian Pullen /* Site specific versions */ 12117a8a68f5SJulian Pullen if (ctx->site_domain_controller.value != NULL) 12127a8a68f5SJulian Pullen free(ctx->site_domain_controller.value); 12137a8a68f5SJulian Pullen 12147a8a68f5SJulian Pullen if (ctx->site_global_catalog.value != NULL) 12157a8a68f5SJulian Pullen free(ctx->site_global_catalog.value); 12167a8a68f5SJulian Pullen 12177a8a68f5SJulian Pullen free(ctx); 12187a8a68f5SJulian Pullen } 12197a8a68f5SJulian Pullen 12207a8a68f5SJulian Pullen void 12217a8a68f5SJulian Pullen ad_disc_refresh(ad_disc_t ctx) 12227a8a68f5SJulian Pullen { 12237a8a68f5SJulian Pullen if (ctx->res_ninitted) 12247a8a68f5SJulian Pullen res_ndestroy(&ctx->res_state); 12257a8a68f5SJulian Pullen (void) memset(&ctx->res_state, 0, sizeof (ctx->res_state)); 12267a8a68f5SJulian Pullen ctx->res_ninitted = res_ninit(&ctx->res_state) != -1; 12277a8a68f5SJulian Pullen 12287a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_AUTO) 12297a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 12307a8a68f5SJulian Pullen 12317a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_AUTO) 12327a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 12337a8a68f5SJulian Pullen 12347a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_AUTO) 12357a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 12367a8a68f5SJulian Pullen 12377a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_AUTO) 12387a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 12397a8a68f5SJulian Pullen 12407a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_AUTO) 12417a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 12427a8a68f5SJulian Pullen 12437a8a68f5SJulian Pullen if (ctx->domains_in_forest.state == AD_STATE_AUTO) 12447a8a68f5SJulian Pullen ctx->domains_in_forest.state = AD_STATE_INVALID; 12457a8a68f5SJulian Pullen 12467a8a68f5SJulian Pullen if (ctx->trusted_domains.state == AD_STATE_AUTO) 12477a8a68f5SJulian Pullen ctx->trusted_domains.state = AD_STATE_INVALID; 12487a8a68f5SJulian Pullen 12497a8a68f5SJulian Pullen if (ctx->site_domain_controller.state == AD_STATE_AUTO) 12507a8a68f5SJulian Pullen ctx->site_domain_controller.state = AD_STATE_INVALID; 12517a8a68f5SJulian Pullen 12527a8a68f5SJulian Pullen if (ctx->site_global_catalog.state == AD_STATE_AUTO) 12537a8a68f5SJulian Pullen ctx->site_global_catalog.state = AD_STATE_INVALID; 12547a8a68f5SJulian Pullen } 12557a8a68f5SJulian Pullen 12567a8a68f5SJulian Pullen 1257c5866007SKeyur Desai /* 1258c5866007SKeyur Desai * Called when the discovery cycle is done. Sets a master TTL 1259c5866007SKeyur Desai * that will avoid doing new time-based discoveries too soon after 1260c5866007SKeyur Desai * the last discovery cycle. Most interesting when the discovery 1261c5866007SKeyur Desai * cycle failed, because then the TTLs on the individual items will 1262c5866007SKeyur Desai * not be updated and may go stale. 1263c5866007SKeyur Desai */ 1264c5866007SKeyur Desai void 1265c5866007SKeyur Desai ad_disc_done(ad_disc_t ctx) 1266c5866007SKeyur Desai { 1267c5866007SKeyur Desai time_t now = time(NULL); 1268c5866007SKeyur Desai 1269c5866007SKeyur Desai ctx->expires_not_before = now + MINIMUM_TTL; 1270c5866007SKeyur Desai ctx->expires_not_after = now + MAXIMUM_TTL; 1271c5866007SKeyur Desai } 1272c5866007SKeyur Desai 12737a8a68f5SJulian Pullen 12747a8a68f5SJulian Pullen /* Discover joined Active Directory domainName */ 12757a8a68f5SJulian Pullen static ad_item_t * 12767a8a68f5SJulian Pullen validate_DomainName(ad_disc_t ctx) 12777a8a68f5SJulian Pullen { 12787a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 12797a8a68f5SJulian Pullen char *dname, *srvname; 12807a8a68f5SJulian Pullen uint32_t ttl = 0; 1281928e1f97SJordan Brown int len; 12827a8a68f5SJulian Pullen 12837a8a68f5SJulian Pullen if (is_valid(&ctx->domain_name)) 12847a8a68f5SJulian Pullen return (&ctx->domain_name); 12857a8a68f5SJulian Pullen 12867a8a68f5SJulian Pullen 12877a8a68f5SJulian Pullen /* Try to find our domain by searching for DCs for it */ 12887a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 1289*148c5f43SAlan Wright if (DBG(DISC, 2)) 1290*148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for our AD domain name..."); 1291*148c5f43SAlan Wright domain_controller = srv_query(&ctx->res_state, 1292*148c5f43SAlan Wright LDAP_SRV_HEAD DC_SRV_TAIL, 1293*148c5f43SAlan Wright ctx->domain_name.value, &srvname, &ttl); 12947a8a68f5SJulian Pullen 12957a8a68f5SJulian Pullen /* 12967a8a68f5SJulian Pullen * If we can't find DCs by via res_nsearch() then there's no 12977a8a68f5SJulian Pullen * point in trying anything else to discover the AD domain name. 12987a8a68f5SJulian Pullen */ 1299*148c5f43SAlan Wright if (domain_controller == NULL) { 1300*148c5f43SAlan Wright if (DBG(DISC, 1)) 1301*148c5f43SAlan Wright logger(LOG_DEBUG, "Can't find our domain name."); 13027a8a68f5SJulian Pullen return (NULL); 1303*148c5f43SAlan Wright } 13047a8a68f5SJulian Pullen 13057a8a68f5SJulian Pullen free(domain_controller); 13067a8a68f5SJulian Pullen /* 13077a8a68f5SJulian Pullen * We have the FQDN of the SRV RR name, so now we extract the 13087a8a68f5SJulian Pullen * domainname suffix from it. 13097a8a68f5SJulian Pullen */ 13107a8a68f5SJulian Pullen dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) + 13117a8a68f5SJulian Pullen 1 /* for the dot between RR name and domainname */); 13127a8a68f5SJulian Pullen 13137a8a68f5SJulian Pullen free(srvname); 13147a8a68f5SJulian Pullen 13157a8a68f5SJulian Pullen if (dname == NULL) { 13167a8a68f5SJulian Pullen logger(LOG_ERR, "Out of memory"); 13177a8a68f5SJulian Pullen return (NULL); 13187a8a68f5SJulian Pullen } 13197a8a68f5SJulian Pullen 13207a8a68f5SJulian Pullen /* Eat any trailing dot */ 1321928e1f97SJordan Brown len = strlen(dname); 1322928e1f97SJordan Brown if (len > 0 && dname[len - 1] == '.') 1323928e1f97SJordan Brown dname[len - 1] = '\0'; 13247a8a68f5SJulian Pullen 1325*148c5f43SAlan Wright if (DBG(DISC, 1)) 1326*148c5f43SAlan Wright logger(LOG_DEBUG, "Our domain name: %s", dname); 13277a8a68f5SJulian Pullen update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl); 13287a8a68f5SJulian Pullen 13297a8a68f5SJulian Pullen return (&ctx->domain_name); 13307a8a68f5SJulian Pullen } 13317a8a68f5SJulian Pullen 13327a8a68f5SJulian Pullen 13337a8a68f5SJulian Pullen char * 13347a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered) 13357a8a68f5SJulian Pullen { 13367a8a68f5SJulian Pullen char *domain_name = NULL; 13377a8a68f5SJulian Pullen ad_item_t *domain_name_item; 13387a8a68f5SJulian Pullen 13397a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 13407a8a68f5SJulian Pullen 13417a8a68f5SJulian Pullen if (domain_name_item) { 13427a8a68f5SJulian Pullen domain_name = strdup(domain_name_item->value); 13437a8a68f5SJulian Pullen if (auto_discovered != NULL) 13447a8a68f5SJulian Pullen *auto_discovered = 13457a8a68f5SJulian Pullen (domain_name_item->state == AD_STATE_AUTO); 13467a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 13477a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 13487a8a68f5SJulian Pullen 13497a8a68f5SJulian Pullen return (domain_name); 13507a8a68f5SJulian Pullen } 13517a8a68f5SJulian Pullen 13527a8a68f5SJulian Pullen 13537a8a68f5SJulian Pullen /* Discover domain controllers */ 13547a8a68f5SJulian Pullen static ad_item_t * 13557a8a68f5SJulian Pullen validate_DomainController(ad_disc_t ctx, enum ad_disc_req req) 13567a8a68f5SJulian Pullen { 13577a8a68f5SJulian Pullen uint32_t ttl = 0; 13587a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 13597a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 13607a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 13617a8a68f5SJulian Pullen ad_item_t *domain_name_item; 13627a8a68f5SJulian Pullen ad_item_t *site_name_item = NULL; 13637a8a68f5SJulian Pullen 13647a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 13657a8a68f5SJulian Pullen if (is_fixed(&ctx->domain_controller)) 13667a8a68f5SJulian Pullen return (&ctx->domain_controller); 13677a8a68f5SJulian Pullen 13687a8a68f5SJulian Pullen domain_name_item = validate_DomainName(ctx); 13697a8a68f5SJulian Pullen if (domain_name_item == NULL) 13707a8a68f5SJulian Pullen return (NULL); 13717a8a68f5SJulian Pullen 13727a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 13737a8a68f5SJulian Pullen validate_global = B_TRUE; 13747a8a68f5SJulian Pullen else { 13757a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 13767a8a68f5SJulian Pullen if (site_name_item != NULL) 13777a8a68f5SJulian Pullen validate_site = B_TRUE; 13787a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 13797a8a68f5SJulian Pullen validate_global = B_TRUE; 13807a8a68f5SJulian Pullen } 13817a8a68f5SJulian Pullen 13827a8a68f5SJulian Pullen if (validate_global) { 13837a8a68f5SJulian Pullen if (!is_valid(&ctx->domain_controller) || 13847a8a68f5SJulian Pullen is_changed(&ctx->domain_controller, PARAM1, 13857a8a68f5SJulian Pullen domain_name_item)) { 1386*148c5f43SAlan Wright if (DBG(DISC, 2)) { 1387*148c5f43SAlan Wright logger(LOG_DEBUG, "Looking for DCs for %s", 1388*148c5f43SAlan Wright domain_name_item->value); 1389*148c5f43SAlan Wright } 13907a8a68f5SJulian Pullen /* 13917a8a68f5SJulian Pullen * Lookup DNS SRV RR named 13927a8a68f5SJulian Pullen * _ldap._tcp.dc._msdcs.<DomainName> 13937a8a68f5SJulian Pullen */ 13947a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 13957a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, 13967a8a68f5SJulian Pullen LDAP_SRV_HEAD DC_SRV_TAIL, 13977a8a68f5SJulian Pullen domain_name_item->value, NULL, &ttl); 13987a8a68f5SJulian Pullen 1399*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1400*148c5f43SAlan Wright logger(LOG_DEBUG, "DCs for %s:", 1401*148c5f43SAlan Wright domain_name_item->value); 1402*148c5f43SAlan Wright } 1403*148c5f43SAlan Wright if (domain_controller == NULL) { 1404*148c5f43SAlan Wright if (DBG(DISC, 1)) 1405*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 14067a8a68f5SJulian Pullen return (NULL); 1407*148c5f43SAlan Wright } 1408*148c5f43SAlan Wright 1409*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1410*148c5f43SAlan Wright int i; 1411*148c5f43SAlan Wright 1412*148c5f43SAlan Wright for (i = 0; 1413*148c5f43SAlan Wright domain_controller[i].host[0] != '\0'; 1414*148c5f43SAlan Wright i++) { 1415*148c5f43SAlan Wright logger(LOG_DEBUG, " %s:%d", 1416*148c5f43SAlan Wright domain_controller[i].host, 1417*148c5f43SAlan Wright domain_controller[i].port); 1418*148c5f43SAlan Wright } 1419*148c5f43SAlan Wright } 14207a8a68f5SJulian Pullen 14217a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 14227a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 14237a8a68f5SJulian Pullen update_version(&ctx->domain_controller, PARAM1, 14247a8a68f5SJulian Pullen domain_name_item); 14257a8a68f5SJulian Pullen } 14267a8a68f5SJulian Pullen return (&ctx->domain_controller); 14277a8a68f5SJulian Pullen } 14287a8a68f5SJulian Pullen 14297a8a68f5SJulian Pullen if (validate_site) { 14307a8a68f5SJulian Pullen if (!is_valid(&ctx->site_domain_controller) || 14317a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM1, 14327a8a68f5SJulian Pullen domain_name_item) || 14337a8a68f5SJulian Pullen is_changed(&ctx->site_domain_controller, PARAM2, 14347a8a68f5SJulian Pullen site_name_item)) { 14357a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 1436*148c5f43SAlan Wright if (DBG(DISC, 2)) { 1437*148c5f43SAlan Wright logger(LOG_DEBUG, 1438*148c5f43SAlan Wright "Looking for DCs for %s in %s", 1439*148c5f43SAlan Wright domain_name_item->value, 1440*148c5f43SAlan Wright site_name_item->value); 1441*148c5f43SAlan Wright } 14427a8a68f5SJulian Pullen /* 14437a8a68f5SJulian Pullen * Lookup DNS SRV RR named 14447a8a68f5SJulian Pullen * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName> 14457a8a68f5SJulian Pullen */ 14467a8a68f5SJulian Pullen (void) snprintf(rr_name, sizeof (rr_name), 14477a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL, 14487a8a68f5SJulian Pullen site_name_item->value); 14497a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 14507a8a68f5SJulian Pullen domain_controller = srv_query(&ctx->res_state, rr_name, 14517a8a68f5SJulian Pullen domain_name_item->value, NULL, &ttl); 1452*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1453*148c5f43SAlan Wright logger(LOG_DEBUG, 1454*148c5f43SAlan Wright "DCs for %s in %s", 1455*148c5f43SAlan Wright domain_name_item->value, 1456*148c5f43SAlan Wright site_name_item->value); 1457*148c5f43SAlan Wright } 1458*148c5f43SAlan Wright if (domain_controller == NULL) { 1459*148c5f43SAlan Wright if (DBG(DISC, 1)) 1460*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 14617a8a68f5SJulian Pullen return (NULL); 1462*148c5f43SAlan Wright } 1463*148c5f43SAlan Wright 1464*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1465*148c5f43SAlan Wright int i; 1466*148c5f43SAlan Wright 1467*148c5f43SAlan Wright for (i = 0; 1468*148c5f43SAlan Wright domain_controller[i].host[0] != '\0'; 1469*148c5f43SAlan Wright i++) { 1470*148c5f43SAlan Wright logger(LOG_DEBUG, " %s:%d", 1471*148c5f43SAlan Wright domain_controller[i].host, 1472*148c5f43SAlan Wright domain_controller[i].port); 1473*148c5f43SAlan Wright } 1474*148c5f43SAlan Wright } 14757a8a68f5SJulian Pullen 14767a8a68f5SJulian Pullen update_item(&ctx->site_domain_controller, 14777a8a68f5SJulian Pullen domain_controller, AD_STATE_AUTO, ttl); 14787a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM1, 14797a8a68f5SJulian Pullen domain_name_item); 14807a8a68f5SJulian Pullen update_version(&ctx->site_domain_controller, PARAM2, 14817a8a68f5SJulian Pullen site_name_item); 14827a8a68f5SJulian Pullen } 14837a8a68f5SJulian Pullen return (&ctx->site_domain_controller); 14847a8a68f5SJulian Pullen } 14857a8a68f5SJulian Pullen return (NULL); 14867a8a68f5SJulian Pullen } 14877a8a68f5SJulian Pullen 14887a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 14897a8a68f5SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req, 14907a8a68f5SJulian Pullen boolean_t *auto_discovered) 14917a8a68f5SJulian Pullen { 14927a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 14937a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 14947a8a68f5SJulian Pullen 14957a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, req); 14967a8a68f5SJulian Pullen 14977a8a68f5SJulian Pullen if (domain_controller_item != NULL) { 14987a8a68f5SJulian Pullen domain_controller = ds_dup(domain_controller_item->value); 14997a8a68f5SJulian Pullen if (auto_discovered != NULL) 15007a8a68f5SJulian Pullen *auto_discovered = 15017a8a68f5SJulian Pullen (domain_controller_item->state == AD_STATE_AUTO); 15027a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 15037a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 15047a8a68f5SJulian Pullen 15057a8a68f5SJulian Pullen return (domain_controller); 15067a8a68f5SJulian Pullen } 15077a8a68f5SJulian Pullen 15087a8a68f5SJulian Pullen 15097a8a68f5SJulian Pullen /* Discover site name (for multi-homed systems the first one found wins) */ 15107a8a68f5SJulian Pullen static ad_item_t * 15117a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx) 15127a8a68f5SJulian Pullen { 15137a8a68f5SJulian Pullen LDAP *ld = NULL; 15147a8a68f5SJulian Pullen ad_subnet_t *subnets = NULL; 15157a8a68f5SJulian Pullen char **dn_subnets = NULL; 15167a8a68f5SJulian Pullen char *dn_root[2]; 15177a8a68f5SJulian Pullen char *config_naming_context = NULL; 15187a8a68f5SJulian Pullen char *site_object = NULL; 15197a8a68f5SJulian Pullen char *site_name = NULL; 15207a8a68f5SJulian Pullen char *forest_name; 15217a8a68f5SJulian Pullen int len; 15227a8a68f5SJulian Pullen boolean_t update_required = B_FALSE; 15237a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 15247a8a68f5SJulian Pullen 15257a8a68f5SJulian Pullen if (is_fixed(&ctx->site_name)) 15267a8a68f5SJulian Pullen return (&ctx->site_name); 15277a8a68f5SJulian Pullen 15287a8a68f5SJulian Pullen /* Can't rely on site-specific DCs */ 15297a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 15307a8a68f5SJulian Pullen if (domain_controller_item == NULL) 15317a8a68f5SJulian Pullen return (NULL); 15327a8a68f5SJulian Pullen 15337a8a68f5SJulian Pullen if (!is_valid(&ctx->site_name) || 1534c5866007SKeyur Desai is_changed(&ctx->site_name, PARAM1, domain_controller_item) || 15357a8a68f5SJulian Pullen ctx->subnets == NULL || ctx->subnets_changed) { 15367a8a68f5SJulian Pullen subnets = find_subnets(); 15377a8a68f5SJulian Pullen ctx->subnets_last_check = time(NULL); 15387a8a68f5SJulian Pullen update_required = B_TRUE; 15397a8a68f5SJulian Pullen } else if (ctx->subnets_last_check + 60 < time(NULL)) { 1540c5866007SKeyur Desai /* NEEDSWORK magic constant 60 above */ 15417a8a68f5SJulian Pullen subnets = find_subnets(); 15427a8a68f5SJulian Pullen ctx->subnets_last_check = time(NULL); 15437a8a68f5SJulian Pullen if (cmpsubnets(ctx->subnets, subnets) != 0) 15447a8a68f5SJulian Pullen update_required = B_TRUE; 15457a8a68f5SJulian Pullen } 15467a8a68f5SJulian Pullen 15477a8a68f5SJulian Pullen if (!update_required) { 15487a8a68f5SJulian Pullen free(subnets); 15497a8a68f5SJulian Pullen return (&ctx->site_name); 15507a8a68f5SJulian Pullen } 15517a8a68f5SJulian Pullen 15527a8a68f5SJulian Pullen if (subnets == NULL) 15537a8a68f5SJulian Pullen return (NULL); 15547a8a68f5SJulian Pullen 15557a8a68f5SJulian Pullen dn_root[0] = ""; 15567a8a68f5SJulian Pullen dn_root[1] = NULL; 15577a8a68f5SJulian Pullen 1558*148c5f43SAlan Wright if (DBG(DISC, 1)) 1559*148c5f43SAlan Wright logger(LOG_DEBUG, "Getting site name"); 1560*148c5f43SAlan Wright 15617a8a68f5SJulian Pullen config_naming_context = ldap_lookup_entry_attr( 15627a8a68f5SJulian Pullen &ld, ctx->domain_controller.value, 15637a8a68f5SJulian Pullen dn_root, "configurationNamingContext"); 15647a8a68f5SJulian Pullen if (config_naming_context == NULL) 15657a8a68f5SJulian Pullen goto out; 15667a8a68f5SJulian Pullen /* 15677a8a68f5SJulian Pullen * configurationNamingContext also provides the Forest 15687a8a68f5SJulian Pullen * Name. 15697a8a68f5SJulian Pullen */ 15707a8a68f5SJulian Pullen if (!is_fixed(&ctx->forest_name)) { 15717a8a68f5SJulian Pullen /* 15727a8a68f5SJulian Pullen * The configurationNamingContext should be of 15737a8a68f5SJulian Pullen * form: 15747a8a68f5SJulian Pullen * CN=Configuration,<DNforestName> 15757a8a68f5SJulian Pullen * Remove the first part and convert to DNS form 15767a8a68f5SJulian Pullen * (replace ",DC=" with ".") 15777a8a68f5SJulian Pullen */ 15787a8a68f5SJulian Pullen char *str = "CN=Configuration,"; 15797a8a68f5SJulian Pullen int len = strlen(str); 15807a8a68f5SJulian Pullen if (strncasecmp(config_naming_context, str, len) == 0) { 15817a8a68f5SJulian Pullen forest_name = DN_to_DNS(config_naming_context + len); 1582*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1583*148c5f43SAlan Wright logger(LOG_DEBUG, " forest: %s", 1584*148c5f43SAlan Wright forest_name); 1585*148c5f43SAlan Wright } 15867a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 15877a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1588c5866007SKeyur Desai update_version(&ctx->forest_name, PARAM1, 1589c5866007SKeyur Desai domain_controller_item); 15907a8a68f5SJulian Pullen } 15917a8a68f5SJulian Pullen } 15927a8a68f5SJulian Pullen 1593*148c5f43SAlan Wright if (DBG(DISC, 2)) 1594*148c5f43SAlan Wright logger(LOG_DEBUG, " CNC: %s", config_naming_context); 1595*148c5f43SAlan Wright 1596*148c5f43SAlan Wright if (DBG(DISC, 2)) { 1597*148c5f43SAlan Wright int i; 1598*148c5f43SAlan Wright logger(LOG_DEBUG, " Looking for sites for subnets:"); 1599*148c5f43SAlan Wright for (i = 0; subnets[i].subnet[0] != '\0'; i++) { 1600*148c5f43SAlan Wright logger(LOG_DEBUG, " %s", subnets[i].subnet); 1601*148c5f43SAlan Wright } 1602*148c5f43SAlan Wright } 1603*148c5f43SAlan Wright 16047a8a68f5SJulian Pullen dn_subnets = subnets_to_DNs(subnets, config_naming_context); 16057a8a68f5SJulian Pullen if (dn_subnets == NULL) 16067a8a68f5SJulian Pullen goto out; 16077a8a68f5SJulian Pullen 16087a8a68f5SJulian Pullen site_object = ldap_lookup_entry_attr( 16097a8a68f5SJulian Pullen &ld, domain_controller_item->value, 16107a8a68f5SJulian Pullen dn_subnets, "siteobject"); 16117a8a68f5SJulian Pullen if (site_object != NULL) { 16127a8a68f5SJulian Pullen /* 16137a8a68f5SJulian Pullen * The site object should be of the form 16147a8a68f5SJulian Pullen * CN=<site>,CN=Sites,CN=Configuration, 16157a8a68f5SJulian Pullen * <DN Domain> 16167a8a68f5SJulian Pullen */ 1617*148c5f43SAlan Wright if (DBG(DISC, 2)) 1618*148c5f43SAlan Wright logger(LOG_DEBUG, " Site object: %s", site_object); 16197a8a68f5SJulian Pullen if (strncasecmp(site_object, "CN=", 3) == 0) { 16207a8a68f5SJulian Pullen for (len = 0; site_object[len + 3] != ','; len++) 16217a8a68f5SJulian Pullen ; 16227a8a68f5SJulian Pullen site_name = malloc(len + 1); 16237a8a68f5SJulian Pullen (void) strncpy(site_name, &site_object[3], len); 16247a8a68f5SJulian Pullen site_name[len] = '\0'; 1625*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1626*148c5f43SAlan Wright logger(LOG_DEBUG, " Site name \"%s\"", 1627*148c5f43SAlan Wright site_name); 1628*148c5f43SAlan Wright } 16297a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, 16307a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 1631c5866007SKeyur Desai update_version(&ctx->site_name, PARAM1, 1632c5866007SKeyur Desai domain_controller_item); 16337a8a68f5SJulian Pullen } 16347a8a68f5SJulian Pullen } 16357a8a68f5SJulian Pullen 16367a8a68f5SJulian Pullen if (ctx->subnets != NULL) { 16377a8a68f5SJulian Pullen free(ctx->subnets); 16387a8a68f5SJulian Pullen ctx->subnets = NULL; 16397a8a68f5SJulian Pullen } 16407a8a68f5SJulian Pullen ctx->subnets = subnets; 16417a8a68f5SJulian Pullen subnets = NULL; 16427a8a68f5SJulian Pullen ctx->subnets_changed = B_FALSE; 16437a8a68f5SJulian Pullen 16447a8a68f5SJulian Pullen out: 16457a8a68f5SJulian Pullen if (ld != NULL) 16467a8a68f5SJulian Pullen (void) ldap_unbind(ld); 16477a8a68f5SJulian Pullen 16487a8a68f5SJulian Pullen if (dn_subnets != NULL) { 1649*148c5f43SAlan Wright int i; 16507a8a68f5SJulian Pullen for (i = 0; dn_subnets[i] != NULL; i++) 16517a8a68f5SJulian Pullen free(dn_subnets[i]); 16527a8a68f5SJulian Pullen free(dn_subnets); 16537a8a68f5SJulian Pullen } 16547a8a68f5SJulian Pullen if (config_naming_context != NULL) 16557a8a68f5SJulian Pullen free(config_naming_context); 16567a8a68f5SJulian Pullen if (site_object != NULL) 16577a8a68f5SJulian Pullen free(site_object); 16587a8a68f5SJulian Pullen 16597a8a68f5SJulian Pullen free(subnets); 16607a8a68f5SJulian Pullen if (site_name == NULL) 16617a8a68f5SJulian Pullen return (NULL); 16627a8a68f5SJulian Pullen return (&ctx->site_name); 16637a8a68f5SJulian Pullen 16647a8a68f5SJulian Pullen } 16657a8a68f5SJulian Pullen 16667a8a68f5SJulian Pullen 16677a8a68f5SJulian Pullen char * 16687a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered) 16697a8a68f5SJulian Pullen { 16707a8a68f5SJulian Pullen ad_item_t *site_name_item; 16717a8a68f5SJulian Pullen char *site_name = NULL; 16727a8a68f5SJulian Pullen 16737a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 16747a8a68f5SJulian Pullen if (site_name_item != NULL) { 16757a8a68f5SJulian Pullen site_name = strdup(site_name_item->value); 16767a8a68f5SJulian Pullen if (auto_discovered != NULL) 16777a8a68f5SJulian Pullen *auto_discovered = 16787a8a68f5SJulian Pullen (site_name_item->state == AD_STATE_AUTO); 16797a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 16807a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 16817a8a68f5SJulian Pullen 16827a8a68f5SJulian Pullen return (site_name); 16837a8a68f5SJulian Pullen } 16847a8a68f5SJulian Pullen 16857a8a68f5SJulian Pullen 16867a8a68f5SJulian Pullen 16877a8a68f5SJulian Pullen /* Discover forest name */ 16887a8a68f5SJulian Pullen static ad_item_t * 16897a8a68f5SJulian Pullen validate_ForestName(ad_disc_t ctx) 16907a8a68f5SJulian Pullen { 16917a8a68f5SJulian Pullen LDAP *ld = NULL; 16927a8a68f5SJulian Pullen char *config_naming_context; 16937a8a68f5SJulian Pullen char *forest_name = NULL; 16947a8a68f5SJulian Pullen char *dn_list[2]; 16957a8a68f5SJulian Pullen ad_item_t *domain_controller_item; 16967a8a68f5SJulian Pullen 16977a8a68f5SJulian Pullen if (is_fixed(&ctx->forest_name)) 16987a8a68f5SJulian Pullen return (&ctx->forest_name); 16997a8a68f5SJulian Pullen /* 17007a8a68f5SJulian Pullen * We may not have a site name yet, so we won't rely on 17017a8a68f5SJulian Pullen * site-specific DCs. (But maybe we could replace 17027a8a68f5SJulian Pullen * validate_ForestName() with validate_siteName()?) 17037a8a68f5SJulian Pullen */ 17047a8a68f5SJulian Pullen domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL); 17057a8a68f5SJulian Pullen if (domain_controller_item == NULL) 17067a8a68f5SJulian Pullen return (NULL); 17077a8a68f5SJulian Pullen 17087a8a68f5SJulian Pullen if (!is_valid(&ctx->forest_name) || 17097a8a68f5SJulian Pullen is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) { 17107a8a68f5SJulian Pullen 17117a8a68f5SJulian Pullen dn_list[0] = ""; 17127a8a68f5SJulian Pullen dn_list[1] = NULL; 1713*148c5f43SAlan Wright if (DBG(DISC, 1)) 1714*148c5f43SAlan Wright logger(LOG_DEBUG, "Getting forest name"); 17157a8a68f5SJulian Pullen config_naming_context = ldap_lookup_entry_attr( 17167a8a68f5SJulian Pullen &ld, ctx->domain_controller.value, 17177a8a68f5SJulian Pullen dn_list, "configurationNamingContext"); 17187a8a68f5SJulian Pullen if (config_naming_context != NULL) { 17197a8a68f5SJulian Pullen /* 17207a8a68f5SJulian Pullen * The configurationNamingContext should be of 17217a8a68f5SJulian Pullen * form: 17227a8a68f5SJulian Pullen * CN=Configuration,<DNforestName> 17237a8a68f5SJulian Pullen * Remove the first part and convert to DNS form 17247a8a68f5SJulian Pullen * (replace ",DC=" with ".") 17257a8a68f5SJulian Pullen */ 17267a8a68f5SJulian Pullen char *str = "CN=Configuration,"; 17277a8a68f5SJulian Pullen int len = strlen(str); 17287a8a68f5SJulian Pullen if (strncasecmp(config_naming_context, str, len) == 0) { 17297a8a68f5SJulian Pullen forest_name = DN_to_DNS( 17307a8a68f5SJulian Pullen config_naming_context + len); 17317a8a68f5SJulian Pullen } 17327a8a68f5SJulian Pullen free(config_naming_context); 17337a8a68f5SJulian Pullen } 17347a8a68f5SJulian Pullen if (ld != NULL) 17357a8a68f5SJulian Pullen (void) ldap_unbind(ld); 17367a8a68f5SJulian Pullen 1737*148c5f43SAlan Wright if (forest_name == NULL) { 1738*148c5f43SAlan Wright if (DBG(DISC, 1)) 1739*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 17407a8a68f5SJulian Pullen return (NULL); 1741*148c5f43SAlan Wright } 1742*148c5f43SAlan Wright 1743*148c5f43SAlan Wright if (DBG(DISC, 1)) 1744*148c5f43SAlan Wright logger(LOG_DEBUG, " %s", forest_name); 17457a8a68f5SJulian Pullen 17467a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0); 17477a8a68f5SJulian Pullen update_version(&ctx->forest_name, PARAM1, 17487a8a68f5SJulian Pullen domain_controller_item); 17497a8a68f5SJulian Pullen } 17507a8a68f5SJulian Pullen return (&ctx->forest_name); 17517a8a68f5SJulian Pullen } 17527a8a68f5SJulian Pullen 17537a8a68f5SJulian Pullen 17547a8a68f5SJulian Pullen char * 17557a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered) 17567a8a68f5SJulian Pullen { 17577a8a68f5SJulian Pullen ad_item_t *forest_name_item; 17587a8a68f5SJulian Pullen char *forest_name = NULL; 17597a8a68f5SJulian Pullen 17607a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 17617a8a68f5SJulian Pullen 17627a8a68f5SJulian Pullen if (forest_name_item != NULL) { 17637a8a68f5SJulian Pullen forest_name = strdup(forest_name_item->value); 17647a8a68f5SJulian Pullen if (auto_discovered != NULL) 17657a8a68f5SJulian Pullen *auto_discovered = 17667a8a68f5SJulian Pullen (forest_name_item->state == AD_STATE_AUTO); 17677a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 17687a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 17697a8a68f5SJulian Pullen 17707a8a68f5SJulian Pullen return (forest_name); 17717a8a68f5SJulian Pullen } 17727a8a68f5SJulian Pullen 17737a8a68f5SJulian Pullen 17747a8a68f5SJulian Pullen /* Discover global catalog servers */ 17757a8a68f5SJulian Pullen static ad_item_t * 17767a8a68f5SJulian Pullen validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req) 17777a8a68f5SJulian Pullen { 17787a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 17797a8a68f5SJulian Pullen uint32_t ttl = 0; 17807a8a68f5SJulian Pullen boolean_t validate_global = B_FALSE; 17817a8a68f5SJulian Pullen boolean_t validate_site = B_FALSE; 17827a8a68f5SJulian Pullen ad_item_t *forest_name_item; 17837a8a68f5SJulian Pullen ad_item_t *site_name_item; 17847a8a68f5SJulian Pullen 17857a8a68f5SJulian Pullen /* If the values is fixed there will not be a site specific version */ 17867a8a68f5SJulian Pullen if (is_fixed(&ctx->global_catalog)) 17877a8a68f5SJulian Pullen return (&ctx->global_catalog); 17887a8a68f5SJulian Pullen 17897a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 17907a8a68f5SJulian Pullen if (forest_name_item == NULL) 17917a8a68f5SJulian Pullen return (NULL); 17927a8a68f5SJulian Pullen 17937a8a68f5SJulian Pullen if (req == AD_DISC_GLOBAL) 17947a8a68f5SJulian Pullen validate_global = B_TRUE; 17957a8a68f5SJulian Pullen else { 17967a8a68f5SJulian Pullen site_name_item = validate_SiteName(ctx); 17977a8a68f5SJulian Pullen if (site_name_item != NULL) 17987a8a68f5SJulian Pullen validate_site = B_TRUE; 17997a8a68f5SJulian Pullen else if (req == AD_DISC_PREFER_SITE) 18007a8a68f5SJulian Pullen validate_global = B_TRUE; 18017a8a68f5SJulian Pullen } 18027a8a68f5SJulian Pullen 18037a8a68f5SJulian Pullen if (validate_global) { 18047a8a68f5SJulian Pullen if (!is_valid(&ctx->global_catalog) || 18057a8a68f5SJulian Pullen is_changed(&ctx->global_catalog, PARAM1, 18067a8a68f5SJulian Pullen forest_name_item)) { 18077a8a68f5SJulian Pullen /* 18087a8a68f5SJulian Pullen * Lookup DNS SRV RR named 18097a8a68f5SJulian Pullen * _ldap._tcp.gc._msdcs.<ForestName> 18107a8a68f5SJulian Pullen */ 18117a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 18127a8a68f5SJulian Pullen global_catalog = 18137a8a68f5SJulian Pullen srv_query(&ctx->res_state, 18147a8a68f5SJulian Pullen LDAP_SRV_HEAD GC_SRV_TAIL, 18157a8a68f5SJulian Pullen ctx->forest_name.value, NULL, &ttl); 18167a8a68f5SJulian Pullen 1817*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1818*148c5f43SAlan Wright logger(LOG_DEBUG, 1819*148c5f43SAlan Wright "GC servers for %s:", 1820*148c5f43SAlan Wright ctx->forest_name.value); 1821*148c5f43SAlan Wright } 1822*148c5f43SAlan Wright if (global_catalog == NULL) { 1823*148c5f43SAlan Wright if (DBG(DISC, 1)) 1824*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 18257a8a68f5SJulian Pullen return (NULL); 1826*148c5f43SAlan Wright } 1827*148c5f43SAlan Wright 1828*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1829*148c5f43SAlan Wright int i; 1830*148c5f43SAlan Wright for (i = 0; 1831*148c5f43SAlan Wright global_catalog[i].host[0] != '\0'; 1832*148c5f43SAlan Wright i++) { 1833*148c5f43SAlan Wright logger(LOG_DEBUG, " %s:%d", 1834*148c5f43SAlan Wright global_catalog[i].host, 1835*148c5f43SAlan Wright global_catalog[i].port); 1836*148c5f43SAlan Wright } 1837*148c5f43SAlan Wright } 18387a8a68f5SJulian Pullen 18397a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 18407a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 18417a8a68f5SJulian Pullen update_version(&ctx->global_catalog, PARAM1, 18427a8a68f5SJulian Pullen forest_name_item); 18437a8a68f5SJulian Pullen } 18447a8a68f5SJulian Pullen return (&ctx->global_catalog); 18457a8a68f5SJulian Pullen } 18467a8a68f5SJulian Pullen 18477a8a68f5SJulian Pullen if (validate_site) { 18487a8a68f5SJulian Pullen if (!is_valid(&ctx->site_global_catalog) || 18497a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM1, 18507a8a68f5SJulian Pullen forest_name_item) || 18517a8a68f5SJulian Pullen is_changed(&ctx->site_global_catalog, PARAM2, 18527a8a68f5SJulian Pullen site_name_item)) { 18537a8a68f5SJulian Pullen char rr_name[DNS_MAX_NAME]; 18547a8a68f5SJulian Pullen 18557a8a68f5SJulian Pullen /* 18567a8a68f5SJulian Pullen * Lookup DNS SRV RR named: 18577a8a68f5SJulian Pullen * _ldap._tcp.<siteName>._sites.gc. 18587a8a68f5SJulian Pullen * _msdcs.<ForestName> 18597a8a68f5SJulian Pullen */ 18607a8a68f5SJulian Pullen (void) snprintf(rr_name, 18617a8a68f5SJulian Pullen sizeof (rr_name), 18627a8a68f5SJulian Pullen LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL, 18637a8a68f5SJulian Pullen ctx->site_name.value); 18647a8a68f5SJulian Pullen DO_RES_NINIT(ctx); 18657a8a68f5SJulian Pullen global_catalog = srv_query(&ctx->res_state, rr_name, 18667a8a68f5SJulian Pullen ctx->forest_name.value, NULL, &ttl); 18677a8a68f5SJulian Pullen 1868*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1869*148c5f43SAlan Wright logger(LOG_DEBUG, 1870*148c5f43SAlan Wright "GC servers for %s in %s", 1871*148c5f43SAlan Wright ctx->forest_name.value, 1872*148c5f43SAlan Wright ctx->site_name.value); 1873*148c5f43SAlan Wright } 1874*148c5f43SAlan Wright if (global_catalog == NULL) { 1875*148c5f43SAlan Wright if (DBG(DISC, 1)) 1876*148c5f43SAlan Wright logger(LOG_DEBUG, " not found"); 18777a8a68f5SJulian Pullen return (NULL); 1878*148c5f43SAlan Wright } 1879*148c5f43SAlan Wright 1880*148c5f43SAlan Wright if (DBG(DISC, 1)) { 1881*148c5f43SAlan Wright int i; 1882*148c5f43SAlan Wright for (i = 0; 1883*148c5f43SAlan Wright global_catalog[i].host[0] != '\0'; 1884*148c5f43SAlan Wright i++) { 1885*148c5f43SAlan Wright logger(LOG_DEBUG, " %s:%d", 1886*148c5f43SAlan Wright global_catalog[i].host, 1887*148c5f43SAlan Wright global_catalog[i].port); 1888*148c5f43SAlan Wright } 1889*148c5f43SAlan Wright } 1890*148c5f43SAlan Wright 18917a8a68f5SJulian Pullen update_item(&ctx->site_global_catalog, global_catalog, 18927a8a68f5SJulian Pullen AD_STATE_AUTO, ttl); 18937a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM1, 18947a8a68f5SJulian Pullen forest_name_item); 18957a8a68f5SJulian Pullen update_version(&ctx->site_global_catalog, PARAM2, 18967a8a68f5SJulian Pullen site_name_item); 18977a8a68f5SJulian Pullen } 18987a8a68f5SJulian Pullen return (&ctx->site_global_catalog); 18997a8a68f5SJulian Pullen } 19007a8a68f5SJulian Pullen return (NULL); 19017a8a68f5SJulian Pullen } 19027a8a68f5SJulian Pullen 19037a8a68f5SJulian Pullen 19047a8a68f5SJulian Pullen idmap_ad_disc_ds_t * 19057a8a68f5SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req, 19067a8a68f5SJulian Pullen boolean_t *auto_discovered) 19077a8a68f5SJulian Pullen { 19087a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 19097a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 19107a8a68f5SJulian Pullen 19117a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, req); 19127a8a68f5SJulian Pullen 19137a8a68f5SJulian Pullen if (global_catalog_item != NULL) { 19147a8a68f5SJulian Pullen global_catalog = ds_dup(global_catalog_item->value); 19157a8a68f5SJulian Pullen if (auto_discovered != NULL) 19167a8a68f5SJulian Pullen *auto_discovered = 19177a8a68f5SJulian Pullen (global_catalog_item->state == AD_STATE_AUTO); 19187a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 19197a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 19207a8a68f5SJulian Pullen 19217a8a68f5SJulian Pullen return (global_catalog); 19227a8a68f5SJulian Pullen } 19237a8a68f5SJulian Pullen 19247a8a68f5SJulian Pullen 19257a8a68f5SJulian Pullen static ad_item_t * 19267a8a68f5SJulian Pullen validate_TrustedDomains(ad_disc_t ctx) 19277a8a68f5SJulian Pullen { 19287a8a68f5SJulian Pullen LDAP *ld = NULL; 19297a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 19307a8a68f5SJulian Pullen ad_item_t *forest_name_item; 19317a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains; 19327a8a68f5SJulian Pullen char *dn = NULL; 19337a8a68f5SJulian Pullen char *forest_name_dn; 19347a8a68f5SJulian Pullen int len; 19357a8a68f5SJulian Pullen int num_parts; 19367a8a68f5SJulian Pullen 19377a8a68f5SJulian Pullen if (is_fixed(&ctx->trusted_domains)) 19387a8a68f5SJulian Pullen return (&ctx->trusted_domains); 19397a8a68f5SJulian Pullen 19407a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 19417a8a68f5SJulian Pullen if (global_catalog_item == NULL) 19427a8a68f5SJulian Pullen return (NULL); 19437a8a68f5SJulian Pullen 19447a8a68f5SJulian Pullen forest_name_item = validate_ForestName(ctx); 19457a8a68f5SJulian Pullen if (forest_name_item == NULL) 19467a8a68f5SJulian Pullen return (NULL); 19477a8a68f5SJulian Pullen 19487a8a68f5SJulian Pullen if (!is_valid(&ctx->trusted_domains) || 19497a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) || 19507a8a68f5SJulian Pullen is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) { 19517a8a68f5SJulian Pullen 19527a8a68f5SJulian Pullen forest_name_dn = ldap_dns_to_dn(forest_name_item->value, 19537a8a68f5SJulian Pullen &num_parts); 19547a8a68f5SJulian Pullen if (forest_name_dn == NULL) 19557a8a68f5SJulian Pullen return (NULL); 19567a8a68f5SJulian Pullen 19577a8a68f5SJulian Pullen len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1; 19587a8a68f5SJulian Pullen dn = malloc(len); 19597a8a68f5SJulian Pullen if (dn == NULL) { 19607a8a68f5SJulian Pullen free(forest_name_dn); 19617a8a68f5SJulian Pullen return (NULL); 19627a8a68f5SJulian Pullen } 19637a8a68f5SJulian Pullen (void) snprintf(dn, len, "CN=System,%s", forest_name_dn); 19647a8a68f5SJulian Pullen free(forest_name_dn); 19657a8a68f5SJulian Pullen 19667a8a68f5SJulian Pullen trusted_domains = ldap_lookup_trusted_domains( 19677a8a68f5SJulian Pullen &ld, global_catalog_item->value, dn); 19687a8a68f5SJulian Pullen 19697a8a68f5SJulian Pullen if (ld != NULL) 19707a8a68f5SJulian Pullen (void) ldap_unbind(ld); 19717a8a68f5SJulian Pullen free(dn); 19727a8a68f5SJulian Pullen 19737a8a68f5SJulian Pullen if (trusted_domains == NULL) 19747a8a68f5SJulian Pullen return (NULL); 19757a8a68f5SJulian Pullen 19767a8a68f5SJulian Pullen update_item(&ctx->trusted_domains, trusted_domains, 19777a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 19787a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM1, 19797a8a68f5SJulian Pullen global_catalog_item); 19807a8a68f5SJulian Pullen update_version(&ctx->trusted_domains, PARAM2, 19817a8a68f5SJulian Pullen forest_name_item); 19827a8a68f5SJulian Pullen } 19837a8a68f5SJulian Pullen 19847a8a68f5SJulian Pullen return (&ctx->trusted_domains); 19857a8a68f5SJulian Pullen } 19867a8a68f5SJulian Pullen 19877a8a68f5SJulian Pullen 19887a8a68f5SJulian Pullen ad_disc_trusteddomains_t * 19897a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered) 19907a8a68f5SJulian Pullen { 19917a8a68f5SJulian Pullen ad_disc_trusteddomains_t *trusted_domains = NULL; 19927a8a68f5SJulian Pullen ad_item_t *trusted_domains_item; 19937a8a68f5SJulian Pullen 19947a8a68f5SJulian Pullen trusted_domains_item = validate_TrustedDomains(ctx); 19957a8a68f5SJulian Pullen 19967a8a68f5SJulian Pullen if (trusted_domains_item != NULL) { 19977a8a68f5SJulian Pullen trusted_domains = td_dup(trusted_domains_item->value); 19987a8a68f5SJulian Pullen if (auto_discovered != NULL) 19997a8a68f5SJulian Pullen *auto_discovered = 20007a8a68f5SJulian Pullen (trusted_domains_item->state == AD_STATE_AUTO); 20017a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 20027a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 20037a8a68f5SJulian Pullen 20047a8a68f5SJulian Pullen return (trusted_domains); 20057a8a68f5SJulian Pullen } 20067a8a68f5SJulian Pullen 20077a8a68f5SJulian Pullen 20087a8a68f5SJulian Pullen static ad_item_t * 20097a8a68f5SJulian Pullen validate_DomainsInForest(ad_disc_t ctx) 20107a8a68f5SJulian Pullen { 20117a8a68f5SJulian Pullen ad_item_t *global_catalog_item; 20127a8a68f5SJulian Pullen LDAP *ld = NULL; 20137a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest; 20147a8a68f5SJulian Pullen 20157a8a68f5SJulian Pullen if (is_fixed(&ctx->domains_in_forest)) 20167a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 20177a8a68f5SJulian Pullen 20187a8a68f5SJulian Pullen global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL); 20197a8a68f5SJulian Pullen if (global_catalog_item == NULL) 20207a8a68f5SJulian Pullen return (NULL); 20217a8a68f5SJulian Pullen 20227a8a68f5SJulian Pullen if (!is_valid(&ctx->domains_in_forest) || 20237a8a68f5SJulian Pullen is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) { 20247a8a68f5SJulian Pullen 20257a8a68f5SJulian Pullen domains_in_forest = ldap_lookup_domains_in_forest( 20267a8a68f5SJulian Pullen &ld, global_catalog_item->value); 20277a8a68f5SJulian Pullen 20287a8a68f5SJulian Pullen if (ld != NULL) 20297a8a68f5SJulian Pullen (void) ldap_unbind(ld); 20307a8a68f5SJulian Pullen 20317a8a68f5SJulian Pullen if (domains_in_forest == NULL) 20327a8a68f5SJulian Pullen return (NULL); 20337a8a68f5SJulian Pullen 20347a8a68f5SJulian Pullen update_item(&ctx->domains_in_forest, domains_in_forest, 20357a8a68f5SJulian Pullen AD_STATE_AUTO, 0); 20367a8a68f5SJulian Pullen update_version(&ctx->domains_in_forest, PARAM1, 20377a8a68f5SJulian Pullen global_catalog_item); 20387a8a68f5SJulian Pullen } 20397a8a68f5SJulian Pullen return (&ctx->domains_in_forest); 20407a8a68f5SJulian Pullen } 20417a8a68f5SJulian Pullen 20427a8a68f5SJulian Pullen 20437a8a68f5SJulian Pullen ad_disc_domainsinforest_t * 20447a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered) 20457a8a68f5SJulian Pullen { 20467a8a68f5SJulian Pullen ad_disc_domainsinforest_t *domains_in_forest = NULL; 20477a8a68f5SJulian Pullen ad_item_t *domains_in_forest_item; 20487a8a68f5SJulian Pullen 20497a8a68f5SJulian Pullen domains_in_forest_item = validate_DomainsInForest(ctx); 20507a8a68f5SJulian Pullen 20517a8a68f5SJulian Pullen if (domains_in_forest_item != NULL) { 20527a8a68f5SJulian Pullen domains_in_forest = df_dup(domains_in_forest_item->value); 20537a8a68f5SJulian Pullen if (auto_discovered != NULL) 20547a8a68f5SJulian Pullen *auto_discovered = 20557a8a68f5SJulian Pullen (domains_in_forest_item->state == AD_STATE_AUTO); 20567a8a68f5SJulian Pullen } else if (auto_discovered != NULL) 20577a8a68f5SJulian Pullen *auto_discovered = B_FALSE; 20587a8a68f5SJulian Pullen 20597a8a68f5SJulian Pullen return (domains_in_forest); 20607a8a68f5SJulian Pullen } 20617a8a68f5SJulian Pullen 20627a8a68f5SJulian Pullen 20637a8a68f5SJulian Pullen 20647a8a68f5SJulian Pullen 20657a8a68f5SJulian Pullen int 20667a8a68f5SJulian Pullen ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName) 20677a8a68f5SJulian Pullen { 20687a8a68f5SJulian Pullen char *domain_name = NULL; 20697a8a68f5SJulian Pullen if (domainName != NULL) { 20707a8a68f5SJulian Pullen domain_name = strdup(domainName); 20717a8a68f5SJulian Pullen if (domain_name == NULL) 20727a8a68f5SJulian Pullen return (-1); 20737a8a68f5SJulian Pullen update_item(&ctx->domain_name, domain_name, 20747a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 20757a8a68f5SJulian Pullen } else if (ctx->domain_name.state == AD_STATE_FIXED) 20767a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 20777a8a68f5SJulian Pullen return (0); 20787a8a68f5SJulian Pullen } 20797a8a68f5SJulian Pullen 20807a8a68f5SJulian Pullen 20817a8a68f5SJulian Pullen int 20827a8a68f5SJulian Pullen ad_disc_set_DomainController(ad_disc_t ctx, 20837a8a68f5SJulian Pullen const idmap_ad_disc_ds_t *domainController) 20847a8a68f5SJulian Pullen { 20857a8a68f5SJulian Pullen idmap_ad_disc_ds_t *domain_controller = NULL; 20867a8a68f5SJulian Pullen if (domainController != NULL) { 20877a8a68f5SJulian Pullen domain_controller = ds_dup(domainController); 20887a8a68f5SJulian Pullen if (domain_controller == NULL) 20897a8a68f5SJulian Pullen return (-1); 20907a8a68f5SJulian Pullen update_item(&ctx->domain_controller, domain_controller, 20917a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 20927a8a68f5SJulian Pullen } else if (ctx->domain_controller.state == AD_STATE_FIXED) 20937a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 20947a8a68f5SJulian Pullen return (0); 20957a8a68f5SJulian Pullen } 20967a8a68f5SJulian Pullen 20977a8a68f5SJulian Pullen 20987a8a68f5SJulian Pullen int 20997a8a68f5SJulian Pullen ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName) 21007a8a68f5SJulian Pullen { 21017a8a68f5SJulian Pullen char *site_name = NULL; 21027a8a68f5SJulian Pullen if (siteName != NULL) { 21037a8a68f5SJulian Pullen site_name = strdup(siteName); 21047a8a68f5SJulian Pullen if (site_name == NULL) 21057a8a68f5SJulian Pullen return (-1); 21067a8a68f5SJulian Pullen update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0); 21077a8a68f5SJulian Pullen } else if (ctx->site_name.state == AD_STATE_FIXED) 21087a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 21097a8a68f5SJulian Pullen return (0); 21107a8a68f5SJulian Pullen } 21117a8a68f5SJulian Pullen 21127a8a68f5SJulian Pullen int 21137a8a68f5SJulian Pullen ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName) 21147a8a68f5SJulian Pullen { 21157a8a68f5SJulian Pullen char *forest_name = NULL; 21167a8a68f5SJulian Pullen if (forestName != NULL) { 21177a8a68f5SJulian Pullen forest_name = strdup(forestName); 21187a8a68f5SJulian Pullen if (forest_name == NULL) 21197a8a68f5SJulian Pullen return (-1); 21207a8a68f5SJulian Pullen update_item(&ctx->forest_name, forest_name, 21217a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 21227a8a68f5SJulian Pullen } else if (ctx->forest_name.state == AD_STATE_FIXED) 21237a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 21247a8a68f5SJulian Pullen return (0); 21257a8a68f5SJulian Pullen } 21267a8a68f5SJulian Pullen 21277a8a68f5SJulian Pullen int 21287a8a68f5SJulian Pullen ad_disc_set_GlobalCatalog(ad_disc_t ctx, 21297a8a68f5SJulian Pullen const idmap_ad_disc_ds_t *globalCatalog) 21307a8a68f5SJulian Pullen { 21317a8a68f5SJulian Pullen idmap_ad_disc_ds_t *global_catalog = NULL; 21327a8a68f5SJulian Pullen if (globalCatalog != NULL) { 21337a8a68f5SJulian Pullen global_catalog = ds_dup(globalCatalog); 21347a8a68f5SJulian Pullen if (global_catalog == NULL) 21357a8a68f5SJulian Pullen return (-1); 21367a8a68f5SJulian Pullen update_item(&ctx->global_catalog, global_catalog, 21377a8a68f5SJulian Pullen AD_STATE_FIXED, 0); 21387a8a68f5SJulian Pullen } else if (ctx->global_catalog.state == AD_STATE_FIXED) 21397a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 21407a8a68f5SJulian Pullen return (0); 21417a8a68f5SJulian Pullen } 21427a8a68f5SJulian Pullen 21437a8a68f5SJulian Pullen 21447a8a68f5SJulian Pullen int 21457a8a68f5SJulian Pullen ad_disc_unset(ad_disc_t ctx) 21467a8a68f5SJulian Pullen { 21477a8a68f5SJulian Pullen if (ctx->domain_name.state == AD_STATE_FIXED) 21487a8a68f5SJulian Pullen ctx->domain_name.state = AD_STATE_INVALID; 21497a8a68f5SJulian Pullen 21507a8a68f5SJulian Pullen if (ctx->domain_controller.state == AD_STATE_FIXED) 21517a8a68f5SJulian Pullen ctx->domain_controller.state = AD_STATE_INVALID; 21527a8a68f5SJulian Pullen 21537a8a68f5SJulian Pullen if (ctx->site_name.state == AD_STATE_FIXED) 21547a8a68f5SJulian Pullen ctx->site_name.state = AD_STATE_INVALID; 21557a8a68f5SJulian Pullen 21567a8a68f5SJulian Pullen if (ctx->forest_name.state == AD_STATE_FIXED) 21577a8a68f5SJulian Pullen ctx->forest_name.state = AD_STATE_INVALID; 21587a8a68f5SJulian Pullen 21597a8a68f5SJulian Pullen if (ctx->global_catalog.state == AD_STATE_FIXED) 21607a8a68f5SJulian Pullen ctx->global_catalog.state = AD_STATE_INVALID; 21617a8a68f5SJulian Pullen 21627a8a68f5SJulian Pullen return (0); 21637a8a68f5SJulian Pullen } 21647a8a68f5SJulian Pullen 21657a8a68f5SJulian Pullen /* 21667a8a68f5SJulian Pullen * ad_disc_get_TTL 21677a8a68f5SJulian Pullen * 21687a8a68f5SJulian Pullen * This routines the time to live for AD 21697a8a68f5SJulian Pullen * auto discovered items. 21707a8a68f5SJulian Pullen * 21717a8a68f5SJulian Pullen * Returns: 21727a8a68f5SJulian Pullen * -1 if there are no TTL items 21737a8a68f5SJulian Pullen * 0 if there are expired items 21747a8a68f5SJulian Pullen * else the number of seconds 21757a8a68f5SJulian Pullen * 21767a8a68f5SJulian Pullen * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it 21777a8a68f5SJulian Pullen * is positive -- min() greater than zero. 21787a8a68f5SJulian Pullen */ 21797a8a68f5SJulian Pullen #define MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \ 21807a8a68f5SJulian Pullen (-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x)))) 21817a8a68f5SJulian Pullen int 21827a8a68f5SJulian Pullen ad_disc_get_TTL(ad_disc_t ctx) 21837a8a68f5SJulian Pullen { 2184c5866007SKeyur Desai time_t expires; 21857a8a68f5SJulian Pullen int ttl; 21867a8a68f5SJulian Pullen 2187c5866007SKeyur Desai expires = MIN_GT_ZERO(ctx->domain_controller.expires, 2188c5866007SKeyur Desai ctx->global_catalog.expires); 2189c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires); 2190c5866007SKeyur Desai expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires); 21917a8a68f5SJulian Pullen 2192c5866007SKeyur Desai if (expires == -1) { 21937a8a68f5SJulian Pullen return (-1); 2194c5866007SKeyur Desai } 2195c5866007SKeyur Desai 2196c5866007SKeyur Desai if (ctx->expires_not_before != 0 && 2197c5866007SKeyur Desai expires < ctx->expires_not_before) { 2198c5866007SKeyur Desai expires = ctx->expires_not_before; 2199c5866007SKeyur Desai } 2200c5866007SKeyur Desai 2201c5866007SKeyur Desai if (ctx->expires_not_after != 0 && 2202c5866007SKeyur Desai expires > ctx->expires_not_after) { 2203c5866007SKeyur Desai expires = ctx->expires_not_after; 2204c5866007SKeyur Desai } 2205c5866007SKeyur Desai 2206c5866007SKeyur Desai ttl = expires - time(NULL); 2207c5866007SKeyur Desai 2208c5866007SKeyur Desai if (ttl < 0) { 22097a8a68f5SJulian Pullen return (0); 2210c5866007SKeyur Desai } 22117a8a68f5SJulian Pullen return (ttl); 22127a8a68f5SJulian Pullen } 22137a8a68f5SJulian Pullen 22147a8a68f5SJulian Pullen boolean_t 22157a8a68f5SJulian Pullen ad_disc_SubnetChanged(ad_disc_t ctx) 22167a8a68f5SJulian Pullen { 22177a8a68f5SJulian Pullen ad_subnet_t *subnets; 22187a8a68f5SJulian Pullen 22197a8a68f5SJulian Pullen if (ctx->subnets_changed || ctx->subnets == NULL) 22207a8a68f5SJulian Pullen return (B_TRUE); 22217a8a68f5SJulian Pullen 22227a8a68f5SJulian Pullen if ((subnets = find_subnets()) != NULL) { 22237a8a68f5SJulian Pullen if (cmpsubnets(subnets, ctx->subnets) != 0) 22247a8a68f5SJulian Pullen ctx->subnets_changed = B_TRUE; 22257a8a68f5SJulian Pullen free(subnets); 22267a8a68f5SJulian Pullen } 22277a8a68f5SJulian Pullen 22287a8a68f5SJulian Pullen return (ctx->subnets_changed); 22297a8a68f5SJulian Pullen } 2230