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
update_version(ad_item_t * item,int num,ad_item_t * param)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
is_valid(ad_item_t * item)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
update_item(ad_item_t * item,void * value,enum ad_item_state state,uint32_t ttl)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
ad_disc_compare_ds(idmap_ad_disc_ds_t * ds1,idmap_ad_disc_ds_t * ds2)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 *
ds_dup(const idmap_ad_disc_ds_t * srv)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
ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t * td1,ad_disc_trusteddomains_t * td2)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 *
td_dup(const ad_disc_trusteddomains_t * td)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
ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t * df1,ad_disc_domainsinforest_t * df2)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 *
df_dup(const ad_disc_domainsinforest_t * df)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 *
find_subnets()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
cmpsubnets(ad_subnet_t * subnets1,ad_subnet_t * subnets2)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 *
DN_to_DNS(const char * dn_name)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 **
subnets_to_DNs(ad_subnet_t * subnets,const char * base_dn)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
srvcmp(idmap_ad_disc_ds_t * s1,idmap_ad_disc_ds_t * s2)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 *
srv_query(res_state state,const char * svc_name,const char * dname,char ** rrname,uint32_t * ttl)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 *
ldap_lookup_init(idmap_ad_disc_ds_t * ds)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 *
ldap_lookup_entry_attr(LDAP ** ld,idmap_ad_disc_ds_t * domainControllers,char ** dn_list,char * attr)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 *
ldap_lookup_trusted_domains(LDAP ** ld,idmap_ad_disc_ds_t * globalCatalog,char * base_dn)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 *
ldap_lookup_domains_in_forest(LDAP ** ld,idmap_ad_disc_ds_t * globalCatalogs)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
ad_disc_init(void)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
ad_disc_fini(ad_disc_t ctx)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
ad_disc_refresh(ad_disc_t ctx)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
ad_disc_done(ad_disc_t ctx)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 *
validate_DomainName(ad_disc_t ctx)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 *
ad_disc_get_DomainName(ad_disc_t ctx,boolean_t * auto_discovered)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 *
validate_DomainController(ad_disc_t ctx,enum ad_disc_req req)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 *
ad_disc_get_DomainController(ad_disc_t ctx,enum ad_disc_req req,boolean_t * auto_discovered)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 *
validate_SiteName(ad_disc_t ctx)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 *
ad_disc_get_SiteName(ad_disc_t ctx,boolean_t * auto_discovered)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 *
validate_ForestName(ad_disc_t ctx)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 *
ad_disc_get_ForestName(ad_disc_t ctx,boolean_t * auto_discovered)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 *
validate_GlobalCatalog(ad_disc_t ctx,enum ad_disc_req req)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 *
ad_disc_get_GlobalCatalog(ad_disc_t ctx,enum ad_disc_req req,boolean_t * auto_discovered)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 *
validate_TrustedDomains(ad_disc_t ctx)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 *
ad_disc_get_TrustedDomains(ad_disc_t ctx,boolean_t * auto_discovered)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 *
validate_DomainsInForest(ad_disc_t ctx)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 *
ad_disc_get_DomainsInForest(ad_disc_t ctx,boolean_t * auto_discovered)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
ad_disc_set_DomainName(ad_disc_t ctx,const char * domainName)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
ad_disc_set_DomainController(ad_disc_t ctx,const idmap_ad_disc_ds_t * domainController)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
ad_disc_set_SiteName(ad_disc_t ctx,const char * siteName)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
ad_disc_set_ForestName(ad_disc_t ctx,const char * forestName)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
ad_disc_set_GlobalCatalog(ad_disc_t ctx,const idmap_ad_disc_ds_t * globalCatalog)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
ad_disc_unset(ad_disc_t ctx)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
ad_disc_get_TTL(ad_disc_t ctx)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
ad_disc_SubnetChanged(ad_disc_t ctx)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