xref: /titanic_50/usr/src/lib/libadutils/common/addisc.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
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 /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*b3700b07SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
257a8a68f5SJulian Pullen  */
267a8a68f5SJulian Pullen 
277a8a68f5SJulian Pullen /*
287a8a68f5SJulian Pullen  * Active Directory Auto-Discovery.
297a8a68f5SJulian Pullen  *
307a8a68f5SJulian Pullen  * This [project private] API allows the caller to provide whatever
317a8a68f5SJulian Pullen  * details it knows a priori (i.e., provided via configuration so as to
327a8a68f5SJulian Pullen  * override auto-discovery) and in any order.  Then the caller can ask
337a8a68f5SJulian Pullen  * for any of the auto-discoverable parameters in any order.
347a8a68f5SJulian Pullen  *
357a8a68f5SJulian Pullen  * But there is an actual order in which discovery must be done.  Given
367a8a68f5SJulian Pullen  * the discovery mechanism implemented here, that order is:
377a8a68f5SJulian Pullen  *
387a8a68f5SJulian Pullen  *  - the domain name joined must be discovered first
397a8a68f5SJulian Pullen  *  - then the domain controllers
407a8a68f5SJulian Pullen  *  - then the forest name and site name
417a8a68f5SJulian Pullen  *  - then the global catalog servers, and site-specific domain
427a8a68f5SJulian Pullen  *    controllers and global catalog servers.
437a8a68f5SJulian Pullen  *
447a8a68f5SJulian Pullen  * The API does not require it be called in the same order because there
457a8a68f5SJulian Pullen  * may be other discovery mechanisms in the future, and exposing
467a8a68f5SJulian Pullen  * ordering requirements of the current mechanism now can create trouble
477a8a68f5SJulian Pullen  * down the line.  Also, this makes the API easier to use now, which
487a8a68f5SJulian Pullen  * means less work to do some day when we make this a public API.
497a8a68f5SJulian Pullen  *
507a8a68f5SJulian Pullen  * Domain discovery is done by res_nsearch() of the DNS SRV RR name for
517a8a68f5SJulian Pullen  * domain controllers.  As long as the joined domain appears in the DNS
527a8a68f5SJulian Pullen  * resolver's search list then we'll find it.
537a8a68f5SJulian Pullen  *
547a8a68f5SJulian Pullen  * Domain controller discovery is a matter of formatting the DNS SRV RR
557a8a68f5SJulian Pullen  * FQDN for domain controllers and doing a lookup for them.  Knowledge
567a8a68f5SJulian Pullen  * of the domain name is not fundamentally required, but we separate the
577a8a68f5SJulian Pullen  * two processes, which in practice can lead to one more DNS lookup than
587a8a68f5SJulian Pullen  * is strictly required.
597a8a68f5SJulian Pullen  *
607a8a68f5SJulian Pullen  * Forest and site name discovery require an LDAP search of the AD
617a8a68f5SJulian Pullen  * "configuration partition" at a domain controller for the joined
627a8a68f5SJulian Pullen  * domain.  Forest and site name discovery depend on knowing the joined
637a8a68f5SJulian Pullen  * domain name and domain controllers for that domain.
647a8a68f5SJulian Pullen  *
657a8a68f5SJulian Pullen  * Global catalog server discovery requires knowledge of the forest
667a8a68f5SJulian Pullen  * name in order to format the DNS SRV RR FQDN to lookup.  Site-specific
677a8a68f5SJulian Pullen  * domain controller discovery depends on knowing the site name (and,
687a8a68f5SJulian Pullen  * therefore, joined domain, ...).  Site-specific global catalog server
697a8a68f5SJulian Pullen  * discovery depends on knowledge of the forest and site names, which
707a8a68f5SJulian Pullen  * depend on...
717a8a68f5SJulian Pullen  *
727a8a68f5SJulian Pullen  * All the work of discovering particular items is done by functions
737a8a68f5SJulian Pullen  * named validate_<item>().  Each such function calls validate_<item>()
747a8a68f5SJulian Pullen  * for any items that it depends on.
757a8a68f5SJulian Pullen  *
767a8a68f5SJulian Pullen  * This API is not thread-safe.
777a8a68f5SJulian Pullen  */
787a8a68f5SJulian Pullen 
797a8a68f5SJulian Pullen 
807a8a68f5SJulian Pullen #include <stdio.h>
817a8a68f5SJulian Pullen #include <string.h>
827a8a68f5SJulian Pullen #include <strings.h>
837a8a68f5SJulian Pullen #include <unistd.h>
847a8a68f5SJulian Pullen #include <assert.h>
857a8a68f5SJulian Pullen #include <stdlib.h>
867a8a68f5SJulian Pullen #include <net/if.h>
877a8a68f5SJulian Pullen #include <sys/types.h>
887a8a68f5SJulian Pullen #include <sys/socket.h>
897a8a68f5SJulian Pullen #include <sys/sockio.h>
907a8a68f5SJulian Pullen #include <netinet/in.h>
917a8a68f5SJulian Pullen #include <arpa/inet.h>
927a8a68f5SJulian Pullen #include <arpa/nameser.h>
937a8a68f5SJulian Pullen #include <resolv.h>
947a8a68f5SJulian Pullen #include <netdb.h>
957a8a68f5SJulian Pullen #include <ctype.h>
967a8a68f5SJulian Pullen #include <errno.h>
977a8a68f5SJulian Pullen #include <ldap.h>
98*b3700b07SGordon Ross #include <note.h>
997a8a68f5SJulian Pullen #include <sasl/sasl.h>
1007a8a68f5SJulian Pullen #include <sys/u8_textprep.h>
1017a8a68f5SJulian Pullen #include <syslog.h>
102*b3700b07SGordon Ross #include <uuid/uuid.h>
103*b3700b07SGordon Ross #include <ads/dsgetdc.h>
1047a8a68f5SJulian Pullen #include "adutils_impl.h"
105*b3700b07SGordon Ross #include "addisc_impl.h"
1067a8a68f5SJulian Pullen 
107c5866007SKeyur Desai /*
108c5866007SKeyur Desai  * These set some sanity policies for discovery.  After a discovery
109c5866007SKeyur Desai  * cycle, we will consider the results (successful or unsuccessful)
110c5866007SKeyur Desai  * to be valid for at least MINIMUM_TTL seconds, and for at most
111c5866007SKeyur Desai  * MAXIMUM_TTL seconds.  Note that the caller is free to request
112c5866007SKeyur Desai  * discovery cycles sooner than MINIMUM_TTL if it has reason to believe
113c5866007SKeyur Desai  * that the situation has changed.
114c5866007SKeyur Desai  */
115c5866007SKeyur Desai #define	MINIMUM_TTL	(5 * 60)
116c5866007SKeyur Desai #define	MAXIMUM_TTL	(20 * 60)
1177a8a68f5SJulian Pullen 
1187a8a68f5SJulian Pullen 
1197a8a68f5SJulian Pullen #define	DNS_MAX_NAME	NS_MAXDNAME
1207a8a68f5SJulian Pullen 
121*b3700b07SGordon Ross #define	GC_PORT		3268
1227a8a68f5SJulian Pullen 
1237a8a68f5SJulian Pullen /* SRV RR names for various queries */
1247a8a68f5SJulian Pullen #define	LDAP_SRV_HEAD		"_ldap._tcp."
1257a8a68f5SJulian Pullen #define	SITE_SRV_MIDDLE		"%s._sites."
1267a8a68f5SJulian Pullen #define	GC_SRV_TAIL		"gc._msdcs"
1277a8a68f5SJulian Pullen #define	DC_SRV_TAIL		"dc._msdcs"
1287a8a68f5SJulian Pullen #define	ALL_GC_SRV_TAIL		"_gc._tcp"
1297a8a68f5SJulian Pullen #define	PDC_SRV			 "_ldap._tcp.pdc._msdcs.%s"
1307a8a68f5SJulian Pullen 
1317a8a68f5SJulian Pullen /* A RR name for all GCs -- last resort this works */
1327a8a68f5SJulian Pullen #define	GC_ALL_A_NAME_FSTR "gc._msdcs.%s."
1337a8a68f5SJulian Pullen 
1347a8a68f5SJulian Pullen 
1357a8a68f5SJulian Pullen /*
1367a8a68f5SJulian Pullen  * We try res_ninit() whenever we don't have one.  res_ninit() fails if
1377a8a68f5SJulian Pullen  * idmapd is running before the network is up!
1387a8a68f5SJulian Pullen  */
139*b3700b07SGordon Ross #define	DO_RES_NINIT(ctx)				\
140*b3700b07SGordon Ross 	if (!(ctx)->res_ninitted)			\
141*b3700b07SGordon Ross 		(void) do_res_ninit(ctx)
142*b3700b07SGordon Ross 
143*b3700b07SGordon Ross #define	DO_GETNAMEINFO(b, l, s)				\
144*b3700b07SGordon Ross 	if (ad_disc_getnameinfo(b, l, s) != 0)		\
145*b3700b07SGordon Ross 		(void) strlcpy(b, "?", l)
146*b3700b07SGordon Ross 
147*b3700b07SGordon Ross #define	DEBUG1STATUS(ctx, ...) do { \
148*b3700b07SGordon Ross 	if (DBG(DISC, 1)) \
149*b3700b07SGordon Ross 		logger(LOG_DEBUG, __VA_ARGS__); \
150*b3700b07SGordon Ross 	if (ctx->status_fp) { \
151*b3700b07SGordon Ross 		(void) fprintf(ctx->status_fp, __VA_ARGS__); \
152*b3700b07SGordon Ross 		(void) fprintf(ctx->status_fp, "\n"); \
153*b3700b07SGordon Ross 	} \
154*b3700b07SGordon Ross 	_NOTE(CONSTCOND) \
155*b3700b07SGordon Ross } while (0)
1567a8a68f5SJulian Pullen 
1577a8a68f5SJulian Pullen #define	is_fixed(item)					\
1587a8a68f5SJulian Pullen 	((item)->state == AD_STATE_FIXED)
1597a8a68f5SJulian Pullen 
1607a8a68f5SJulian Pullen #define	is_changed(item, num, param) 			\
1617a8a68f5SJulian Pullen 	((item)->param_version[num] != (param)->version)
1627a8a68f5SJulian Pullen 
163*b3700b07SGordon Ross void * uuid_dup(void *);
164*b3700b07SGordon Ross 
165*b3700b07SGordon Ross static ad_item_t *validate_SiteName(ad_disc_t ctx);
166*b3700b07SGordon Ross static ad_item_t *validate_PreferredDC(ad_disc_t ctx);
167*b3700b07SGordon Ross 
1687a8a68f5SJulian Pullen /*
1697a8a68f5SJulian Pullen  * Function definitions
1707a8a68f5SJulian Pullen  */
1717a8a68f5SJulian Pullen 
1727a8a68f5SJulian Pullen 
173*b3700b07SGordon Ross static int
do_res_ninit(ad_disc_t ctx)174*b3700b07SGordon Ross do_res_ninit(ad_disc_t ctx)
175*b3700b07SGordon Ross {
176*b3700b07SGordon Ross 	int rc;
177*b3700b07SGordon Ross 
178*b3700b07SGordon Ross 	rc = res_ninit(&ctx->res_state);
179*b3700b07SGordon Ross 	if (rc != 0)
180*b3700b07SGordon Ross 		return (rc);
181*b3700b07SGordon Ross 	ctx->res_ninitted = 1;
182*b3700b07SGordon Ross 	/*
183*b3700b07SGordon Ross 	 * The SRV records returnd by AD can be larger than 512 bytes,
184*b3700b07SGordon Ross 	 * so we'd like to use TCP for those searches.  Unfortunately,
185*b3700b07SGordon Ross 	 * the TCP connect timeout seen by the resolver is very long
186*b3700b07SGordon Ross 	 * (more than a couple minutes) and we can't wait that long.
187*b3700b07SGordon Ross 	 * Don't do use TCP until we can override the timeout.
188*b3700b07SGordon Ross 	 *
189*b3700b07SGordon Ross 	 * Note that some queries will try TCP anyway.
190*b3700b07SGordon Ross 	 */
191*b3700b07SGordon Ross #if 0
192*b3700b07SGordon Ross 	ctx->res_state.options |= RES_USEVC;
193*b3700b07SGordon Ross #endif
194*b3700b07SGordon Ross 	return (0);
195*b3700b07SGordon Ross }
196*b3700b07SGordon Ross 
197*b3700b07SGordon Ross /*
198*b3700b07SGordon Ross  * Private getnameinfo(3socket) variant tailored to our needs.
199*b3700b07SGordon Ross  */
200*b3700b07SGordon Ross int
ad_disc_getnameinfo(char * obuf,int olen,struct sockaddr_storage * ss)201*b3700b07SGordon Ross ad_disc_getnameinfo(char *obuf, int olen, struct sockaddr_storage *ss)
202*b3700b07SGordon Ross {
203*b3700b07SGordon Ross 	struct sockaddr *sa;
204*b3700b07SGordon Ross 	int eai, slen;
205*b3700b07SGordon Ross 
206*b3700b07SGordon Ross 	sa = (void *)ss;
207*b3700b07SGordon Ross 	switch (sa->sa_family) {
208*b3700b07SGordon Ross 	case AF_INET:
209*b3700b07SGordon Ross 		slen = sizeof (struct sockaddr_in);
210*b3700b07SGordon Ross 		break;
211*b3700b07SGordon Ross 	case AF_INET6:
212*b3700b07SGordon Ross 		slen = sizeof (struct sockaddr_in6);
213*b3700b07SGordon Ross 		break;
214*b3700b07SGordon Ross 	default:
215*b3700b07SGordon Ross 		return (EAI_FAMILY);
216*b3700b07SGordon Ross 	}
217*b3700b07SGordon Ross 
218*b3700b07SGordon Ross 	eai = getnameinfo(sa, slen, obuf, olen, NULL, 0, NI_NUMERICHOST);
219*b3700b07SGordon Ross 
220*b3700b07SGordon Ross 	return (eai);
221*b3700b07SGordon Ross }
2227a8a68f5SJulian Pullen 
2237a8a68f5SJulian Pullen static void
update_version(ad_item_t * item,int num,ad_item_t * param)2247a8a68f5SJulian Pullen update_version(ad_item_t *item, int  num, ad_item_t *param)
2257a8a68f5SJulian Pullen {
2267a8a68f5SJulian Pullen 	item->param_version[num] = param->version;
2277a8a68f5SJulian Pullen }
2287a8a68f5SJulian Pullen 
2297a8a68f5SJulian Pullen 
2307a8a68f5SJulian Pullen 
2317a8a68f5SJulian Pullen static boolean_t
is_valid(ad_item_t * item)2327a8a68f5SJulian Pullen is_valid(ad_item_t *item)
2337a8a68f5SJulian Pullen {
2347a8a68f5SJulian Pullen 	if (item->value != NULL) {
2357a8a68f5SJulian Pullen 		if (item->state == AD_STATE_FIXED)
2367a8a68f5SJulian Pullen 			return (B_TRUE);
2377a8a68f5SJulian Pullen 		if (item->state == AD_STATE_AUTO &&
238c5866007SKeyur Desai 		    (item->expires == 0 || item->expires > time(NULL)))
2397a8a68f5SJulian Pullen 			return (B_TRUE);
2407a8a68f5SJulian Pullen 	}
2417a8a68f5SJulian Pullen 	return (B_FALSE);
2427a8a68f5SJulian Pullen }
2437a8a68f5SJulian Pullen 
2447a8a68f5SJulian Pullen 
2457a8a68f5SJulian Pullen static void
update_item(ad_item_t * item,void * value,enum ad_item_state state,uint32_t ttl)2467a8a68f5SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state,
2477a8a68f5SJulian Pullen 		uint32_t ttl)
2487a8a68f5SJulian Pullen {
2497a8a68f5SJulian Pullen 	if (item->value != NULL && value != NULL) {
2507a8a68f5SJulian Pullen 		if ((item->type == AD_STRING &&
2517a8a68f5SJulian Pullen 		    strcmp(item->value, value) != 0) ||
252*b3700b07SGordon Ross 		    (item->type == AD_UUID &&
253*b3700b07SGordon Ross 		    ad_disc_compare_uuid(item->value, value) != 0)||
2547a8a68f5SJulian Pullen 		    (item->type == AD_DIRECTORY &&
2557a8a68f5SJulian Pullen 		    ad_disc_compare_ds(item->value, value) != 0)||
2567a8a68f5SJulian Pullen 		    (item->type == AD_DOMAINS_IN_FOREST &&
2577a8a68f5SJulian Pullen 		    ad_disc_compare_domainsinforest(item->value, value) != 0) ||
2587a8a68f5SJulian Pullen 		    (item->type == AD_TRUSTED_DOMAINS &&
2597a8a68f5SJulian Pullen 		    ad_disc_compare_trusteddomains(item->value, value) != 0))
2607a8a68f5SJulian Pullen 			item->version++;
2617a8a68f5SJulian Pullen 	} else if (item->value != value)
2627a8a68f5SJulian Pullen 		item->version++;
2637a8a68f5SJulian Pullen 
2647a8a68f5SJulian Pullen 	if (item->value != NULL)
2657a8a68f5SJulian Pullen 		free(item->value);
2667a8a68f5SJulian Pullen 
2677a8a68f5SJulian Pullen 	item->value = value;
2687a8a68f5SJulian Pullen 	item->state = state;
2697a8a68f5SJulian Pullen 
2707a8a68f5SJulian Pullen 	if (ttl == 0)
271c5866007SKeyur Desai 		item->expires = 0;
2727a8a68f5SJulian Pullen 	else
273c5866007SKeyur Desai 		item->expires = time(NULL) + ttl;
2747a8a68f5SJulian Pullen }
2757a8a68f5SJulian Pullen 
276*b3700b07SGordon Ross /* Compare UUIDs */
277*b3700b07SGordon Ross int
ad_disc_compare_uuid(uuid_t * u1,uuid_t * u2)278*b3700b07SGordon Ross ad_disc_compare_uuid(uuid_t *u1, uuid_t *u2)
279*b3700b07SGordon Ross {
280*b3700b07SGordon Ross 	int rc;
281*b3700b07SGordon Ross 
282*b3700b07SGordon Ross 	rc = memcmp(u1, u2, UUID_LEN);
283*b3700b07SGordon Ross 	return (rc);
284*b3700b07SGordon Ross }
285*b3700b07SGordon Ross 
286*b3700b07SGordon Ross void *
uuid_dup(void * src)287*b3700b07SGordon Ross uuid_dup(void *src)
288*b3700b07SGordon Ross {
289*b3700b07SGordon Ross 	void *dst;
290*b3700b07SGordon Ross 	dst = malloc(UUID_LEN);
291*b3700b07SGordon Ross 	if (dst != NULL)
292*b3700b07SGordon Ross 		(void) memcpy(dst, src, UUID_LEN);
293*b3700b07SGordon Ross 	return (dst);
294*b3700b07SGordon Ross }
2957a8a68f5SJulian Pullen 
2967a8a68f5SJulian Pullen /* Compare DS lists */
2977a8a68f5SJulian Pullen int
ad_disc_compare_ds(ad_disc_ds_t * ds1,ad_disc_ds_t * ds2)298*b3700b07SGordon Ross ad_disc_compare_ds(ad_disc_ds_t *ds1, ad_disc_ds_t *ds2)
2997a8a68f5SJulian Pullen {
3007a8a68f5SJulian Pullen 	int		i, j;
3017a8a68f5SJulian Pullen 	int		num_ds1;
3027a8a68f5SJulian Pullen 	int		num_ds2;
3037a8a68f5SJulian Pullen 	boolean_t	match;
3047a8a68f5SJulian Pullen 
3057a8a68f5SJulian Pullen 	for (i = 0; ds1[i].host[0] != '\0'; i++)
3067a8a68f5SJulian Pullen 		continue;
3077a8a68f5SJulian Pullen 	num_ds1 = i;
3087a8a68f5SJulian Pullen 	for (j = 0; ds2[j].host[0] != '\0'; j++)
3097a8a68f5SJulian Pullen 		continue;
3107a8a68f5SJulian Pullen 	num_ds2 = j;
3117a8a68f5SJulian Pullen 	if (num_ds1 != num_ds2)
3127a8a68f5SJulian Pullen 		return (1);
3137a8a68f5SJulian Pullen 
3147a8a68f5SJulian Pullen 	for (i = 0; i < num_ds1; i++) {
3157a8a68f5SJulian Pullen 		match = B_FALSE;
3167a8a68f5SJulian Pullen 		for (j = 0; j < num_ds2; j++) {
317928e1f97SJordan Brown 			if (strcmp(ds1[i].host, ds2[j].host) == 0 &&
318928e1f97SJordan Brown 			    ds1[i].port == ds2[j].port) {
3197a8a68f5SJulian Pullen 				match = B_TRUE;
3207a8a68f5SJulian Pullen 				break;
3217a8a68f5SJulian Pullen 			}
3227a8a68f5SJulian Pullen 		}
3237a8a68f5SJulian Pullen 		if (!match)
3247a8a68f5SJulian Pullen 			return (1);
3257a8a68f5SJulian Pullen 	}
3267a8a68f5SJulian Pullen 	return (0);
3277a8a68f5SJulian Pullen }
3287a8a68f5SJulian Pullen 
3297a8a68f5SJulian Pullen 
3307a8a68f5SJulian Pullen /* Copy a list of DSs */
331*b3700b07SGordon Ross static ad_disc_ds_t *
ds_dup(const ad_disc_ds_t * srv)332*b3700b07SGordon Ross ds_dup(const ad_disc_ds_t *srv)
3337a8a68f5SJulian Pullen {
3347a8a68f5SJulian Pullen 	int	i;
3357a8a68f5SJulian Pullen 	int	size;
336*b3700b07SGordon Ross 	ad_disc_ds_t *new = NULL;
3377a8a68f5SJulian Pullen 
3387a8a68f5SJulian Pullen 	for (i = 0; srv[i].host[0] != '\0'; i++)
3397a8a68f5SJulian Pullen 		continue;
3407a8a68f5SJulian Pullen 
341*b3700b07SGordon Ross 	size = (i + 1) * sizeof (ad_disc_ds_t);
3427a8a68f5SJulian Pullen 	new = malloc(size);
3437a8a68f5SJulian Pullen 	if (new != NULL)
344148c5f43SAlan Wright 		(void) memcpy(new, srv, size);
3457a8a68f5SJulian Pullen 	return (new);
3467a8a68f5SJulian Pullen }
3477a8a68f5SJulian Pullen 
3487a8a68f5SJulian Pullen 
3497a8a68f5SJulian Pullen int
ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t * td1,ad_disc_trusteddomains_t * td2)3507a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1,
3517a8a68f5SJulian Pullen 			ad_disc_trusteddomains_t *td2)
3527a8a68f5SJulian Pullen {
3537a8a68f5SJulian Pullen 	int		i, j;
3547a8a68f5SJulian Pullen 	int		num_td1;
3557a8a68f5SJulian Pullen 	int		num_td2;
3567a8a68f5SJulian Pullen 	boolean_t	match;
3577a8a68f5SJulian Pullen 
3587a8a68f5SJulian Pullen 	for (i = 0; td1[i].domain[0] != '\0'; i++)
3597a8a68f5SJulian Pullen 		continue;
3607a8a68f5SJulian Pullen 	num_td1 = i;
3617a8a68f5SJulian Pullen 
3627a8a68f5SJulian Pullen 	for (j = 0; td2[j].domain[0] != '\0'; j++)
3637a8a68f5SJulian Pullen 		continue;
3647a8a68f5SJulian Pullen 	num_td2 = j;
3657a8a68f5SJulian Pullen 
3667a8a68f5SJulian Pullen 	if (num_td1 != num_td2)
3677a8a68f5SJulian Pullen 		return (1);
3687a8a68f5SJulian Pullen 
3697a8a68f5SJulian Pullen 	for (i = 0; i < num_td1; i++) {
3707a8a68f5SJulian Pullen 		match = B_FALSE;
3717a8a68f5SJulian Pullen 		for (j = 0; j < num_td2; j++) {
3721fcced4cSJordan Brown 			if (domain_eq(td1[i].domain, td2[j].domain)) {
3737a8a68f5SJulian Pullen 				match = B_TRUE;
3747a8a68f5SJulian Pullen 				break;
3757a8a68f5SJulian Pullen 			}
3767a8a68f5SJulian Pullen 		}
3777a8a68f5SJulian Pullen 		if (!match)
3787a8a68f5SJulian Pullen 			return (1);
3797a8a68f5SJulian Pullen 	}
3807a8a68f5SJulian Pullen 	return (0);
3817a8a68f5SJulian Pullen }
3827a8a68f5SJulian Pullen 
3837a8a68f5SJulian Pullen 
3847a8a68f5SJulian Pullen 
3857a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */
3867a8a68f5SJulian Pullen static ad_disc_trusteddomains_t *
td_dup(const ad_disc_trusteddomains_t * td)3877a8a68f5SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td)
3887a8a68f5SJulian Pullen {
3897a8a68f5SJulian Pullen 	int	i;
3907a8a68f5SJulian Pullen 	int	size;
3917a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *new = NULL;
3927a8a68f5SJulian Pullen 
3937a8a68f5SJulian Pullen 	for (i = 0; td[i].domain[0] != '\0'; i++)
3947a8a68f5SJulian Pullen 		continue;
3957a8a68f5SJulian Pullen 
3967a8a68f5SJulian Pullen 	size = (i + 1) * sizeof (ad_disc_trusteddomains_t);
3977a8a68f5SJulian Pullen 	new = malloc(size);
3987a8a68f5SJulian Pullen 	if (new != NULL)
399148c5f43SAlan Wright 		(void) memcpy(new, td, size);
4007a8a68f5SJulian Pullen 	return (new);
4017a8a68f5SJulian Pullen }
4027a8a68f5SJulian Pullen 
4037a8a68f5SJulian Pullen 
4047a8a68f5SJulian Pullen 
4057a8a68f5SJulian Pullen int
ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t * df1,ad_disc_domainsinforest_t * df2)4067a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1,
4077a8a68f5SJulian Pullen 			ad_disc_domainsinforest_t *df2)
4087a8a68f5SJulian Pullen {
4097a8a68f5SJulian Pullen 	int		i, j;
4107a8a68f5SJulian Pullen 	int		num_df1;
4117a8a68f5SJulian Pullen 	int		num_df2;
4127a8a68f5SJulian Pullen 	boolean_t	match;
4137a8a68f5SJulian Pullen 
4147a8a68f5SJulian Pullen 	for (i = 0; df1[i].domain[0] != '\0'; i++)
4157a8a68f5SJulian Pullen 		continue;
4167a8a68f5SJulian Pullen 	num_df1 = i;
4177a8a68f5SJulian Pullen 
4187a8a68f5SJulian Pullen 	for (j = 0; df2[j].domain[0] != '\0'; j++)
4197a8a68f5SJulian Pullen 		continue;
4207a8a68f5SJulian Pullen 	num_df2 = j;
4217a8a68f5SJulian Pullen 
4227a8a68f5SJulian Pullen 	if (num_df1 != num_df2)
4237a8a68f5SJulian Pullen 		return (1);
4247a8a68f5SJulian Pullen 
4257a8a68f5SJulian Pullen 	for (i = 0; i < num_df1; i++) {
4267a8a68f5SJulian Pullen 		match = B_FALSE;
4277a8a68f5SJulian Pullen 		for (j = 0; j < num_df2; j++) {
4281fcced4cSJordan Brown 			if (domain_eq(df1[i].domain, df2[j].domain) &&
429928e1f97SJordan Brown 			    strcmp(df1[i].sid, df2[j].sid) == 0) {
4307a8a68f5SJulian Pullen 				match = B_TRUE;
4317a8a68f5SJulian Pullen 				break;
4327a8a68f5SJulian Pullen 			}
4337a8a68f5SJulian Pullen 		}
4347a8a68f5SJulian Pullen 		if (!match)
4357a8a68f5SJulian Pullen 			return (1);
4367a8a68f5SJulian Pullen 	}
4377a8a68f5SJulian Pullen 	return (0);
4387a8a68f5SJulian Pullen }
4397a8a68f5SJulian Pullen 
4407a8a68f5SJulian Pullen 
4417a8a68f5SJulian Pullen 
4427a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */
4437a8a68f5SJulian Pullen static ad_disc_domainsinforest_t *
df_dup(const ad_disc_domainsinforest_t * df)4447a8a68f5SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df)
4457a8a68f5SJulian Pullen {
4467a8a68f5SJulian Pullen 	int	i;
4477a8a68f5SJulian Pullen 	int	size;
4487a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *new = NULL;
4497a8a68f5SJulian Pullen 
4507a8a68f5SJulian Pullen 	for (i = 0; df[i].domain[0] != '\0'; i++)
4517a8a68f5SJulian Pullen 		continue;
4527a8a68f5SJulian Pullen 
4537a8a68f5SJulian Pullen 	size = (i + 1) * sizeof (ad_disc_domainsinforest_t);
4547a8a68f5SJulian Pullen 	new = malloc(size);
4557a8a68f5SJulian Pullen 	if (new != NULL)
456148c5f43SAlan Wright 		(void) memcpy(new, df, size);
4577a8a68f5SJulian Pullen 	return (new);
4587a8a68f5SJulian Pullen }
4597a8a68f5SJulian Pullen 
4607a8a68f5SJulian Pullen 
4617a8a68f5SJulian Pullen 
4627a8a68f5SJulian Pullen 
4637a8a68f5SJulian Pullen 
4647a8a68f5SJulian Pullen /*
4657a8a68f5SJulian Pullen  * Returns an array of IPv4 address/prefix length
4667a8a68f5SJulian Pullen  * The last subnet is NULL
4677a8a68f5SJulian Pullen  */
4687a8a68f5SJulian Pullen static ad_subnet_t *
find_subnets()4697a8a68f5SJulian Pullen find_subnets()
4707a8a68f5SJulian Pullen {
4717a8a68f5SJulian Pullen 	int		sock, n, i;
4727a8a68f5SJulian Pullen 	struct lifconf	lifc;
4737a8a68f5SJulian Pullen 	struct lifreq	lifr, *lifrp;
4747a8a68f5SJulian Pullen 	struct lifnum	lifn;
4757a8a68f5SJulian Pullen 	uint32_t	prefix_len;
4767a8a68f5SJulian Pullen 	char		*s;
4777a8a68f5SJulian Pullen 	ad_subnet_t	*results;
4787a8a68f5SJulian Pullen 
4797a8a68f5SJulian Pullen 	lifrp = &lifr;
4807a8a68f5SJulian Pullen 
4817a8a68f5SJulian Pullen 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
4827a8a68f5SJulian Pullen 		logger(LOG_ERR, "Failed to open IPv4 socket for "
4837a8a68f5SJulian Pullen 		    "listing network interfaces (%s)", strerror(errno));
4847a8a68f5SJulian Pullen 		return (NULL);
4857a8a68f5SJulian Pullen 	}
4867a8a68f5SJulian Pullen 
4877a8a68f5SJulian Pullen 	lifn.lifn_family = AF_INET;
4887a8a68f5SJulian Pullen 	lifn.lifn_flags = 0;
4897a8a68f5SJulian Pullen 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
4907a8a68f5SJulian Pullen 		logger(LOG_ERR,
4917a8a68f5SJulian Pullen 		    "Failed to find the number of network interfaces (%s)",
4927a8a68f5SJulian Pullen 		    strerror(errno));
493148c5f43SAlan Wright 		(void) close(sock);
4947a8a68f5SJulian Pullen 		return (NULL);
4957a8a68f5SJulian Pullen 	}
4967a8a68f5SJulian Pullen 
4977a8a68f5SJulian Pullen 	if (lifn.lifn_count < 1) {
4987a8a68f5SJulian Pullen 		logger(LOG_ERR, "No IPv4 network interfaces found");
499148c5f43SAlan Wright 		(void) close(sock);
5007a8a68f5SJulian Pullen 		return (NULL);
5017a8a68f5SJulian Pullen 	}
5027a8a68f5SJulian Pullen 
5037a8a68f5SJulian Pullen 	lifc.lifc_family = AF_INET;
5047a8a68f5SJulian Pullen 	lifc.lifc_flags = 0;
5057a8a68f5SJulian Pullen 	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
5067a8a68f5SJulian Pullen 	lifc.lifc_buf = malloc(lifc.lifc_len);
5077a8a68f5SJulian Pullen 
5087a8a68f5SJulian Pullen 	if (lifc.lifc_buf == NULL) {
5097a8a68f5SJulian Pullen 		logger(LOG_ERR, "Out of memory");
510148c5f43SAlan Wright 		(void) close(sock);
5117a8a68f5SJulian Pullen 		return (NULL);
5127a8a68f5SJulian Pullen 	}
5137a8a68f5SJulian Pullen 
5147a8a68f5SJulian Pullen 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
5157a8a68f5SJulian Pullen 		logger(LOG_ERR, "Failed to list network interfaces (%s)",
5167a8a68f5SJulian Pullen 		    strerror(errno));
5177a8a68f5SJulian Pullen 		free(lifc.lifc_buf);
518148c5f43SAlan Wright 		(void) close(sock);
5197a8a68f5SJulian Pullen 		return (NULL);
5207a8a68f5SJulian Pullen 	}
5217a8a68f5SJulian Pullen 
5227a8a68f5SJulian Pullen 	n = lifc.lifc_len / (int)sizeof (struct lifreq);
5237a8a68f5SJulian Pullen 
5247a8a68f5SJulian Pullen 	if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) {
5257a8a68f5SJulian Pullen 		free(lifc.lifc_buf);
526148c5f43SAlan Wright 		(void) close(sock);
5277a8a68f5SJulian Pullen 		return (NULL);
5287a8a68f5SJulian Pullen 	}
5297a8a68f5SJulian Pullen 
5307a8a68f5SJulian Pullen 	for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) {
5317a8a68f5SJulian Pullen 		if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0)
5327a8a68f5SJulian Pullen 			continue;
5337a8a68f5SJulian Pullen 
5347a8a68f5SJulian Pullen 		if ((lifrp->lifr_flags & IFF_UP) == 0)
5357a8a68f5SJulian Pullen 			continue;
5367a8a68f5SJulian Pullen 
5377a8a68f5SJulian Pullen 		if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0)
5387a8a68f5SJulian Pullen 			continue;
5397a8a68f5SJulian Pullen 
5407a8a68f5SJulian Pullen 		prefix_len = lifrp->lifr_addrlen;
5417a8a68f5SJulian Pullen 
5427a8a68f5SJulian Pullen 		s = inet_ntoa(((struct sockaddr_in *)
5437a8a68f5SJulian Pullen 		    &lifrp->lifr_addr)->sin_addr);
5447a8a68f5SJulian Pullen 
5457a8a68f5SJulian Pullen 		(void) snprintf(results[i].subnet, sizeof (ad_subnet_t),
5467a8a68f5SJulian Pullen 		    "%s/%d", s, prefix_len);
5477a8a68f5SJulian Pullen 	}
5487a8a68f5SJulian Pullen 
5497a8a68f5SJulian Pullen 	free(lifc.lifc_buf);
550148c5f43SAlan Wright 	(void) close(sock);
5517a8a68f5SJulian Pullen 
5527a8a68f5SJulian Pullen 	return (results);
5537a8a68f5SJulian Pullen }
5547a8a68f5SJulian Pullen 
5557a8a68f5SJulian Pullen static int
cmpsubnets(ad_subnet_t * subnets1,ad_subnet_t * subnets2)5567a8a68f5SJulian Pullen cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2)
5577a8a68f5SJulian Pullen {
5587a8a68f5SJulian Pullen 	int num_subnets1;
5597a8a68f5SJulian Pullen 	int num_subnets2;
5607a8a68f5SJulian Pullen 	boolean_t matched;
5617a8a68f5SJulian Pullen 	int i, j;
5627a8a68f5SJulian Pullen 
5637a8a68f5SJulian Pullen 	for (i = 0; subnets1[i].subnet[0] != '\0'; i++)
5647a8a68f5SJulian Pullen 		continue;
5657a8a68f5SJulian Pullen 	num_subnets1 = i;
5667a8a68f5SJulian Pullen 
5677a8a68f5SJulian Pullen 	for (i = 0; subnets2[i].subnet[0] != '\0'; i++)
5687a8a68f5SJulian Pullen 		continue;
5697a8a68f5SJulian Pullen 	num_subnets2 = i;
5707a8a68f5SJulian Pullen 
5717a8a68f5SJulian Pullen 	if (num_subnets1 != num_subnets2)
5727a8a68f5SJulian Pullen 		return (1);
5737a8a68f5SJulian Pullen 
5747a8a68f5SJulian Pullen 	for (i = 0;  i < num_subnets1; i++) {
5757a8a68f5SJulian Pullen 		matched = B_FALSE;
5767a8a68f5SJulian Pullen 		for (j = 0; j < num_subnets2; j++) {
5777a8a68f5SJulian Pullen 			if (strcmp(subnets1[i].subnet,
5787a8a68f5SJulian Pullen 			    subnets2[j].subnet) == 0) {
5797a8a68f5SJulian Pullen 				matched = B_TRUE;
5807a8a68f5SJulian Pullen 				break;
5817a8a68f5SJulian Pullen 			}
5827a8a68f5SJulian Pullen 		}
5837a8a68f5SJulian Pullen 		if (!matched)
5847a8a68f5SJulian Pullen 			return (1);
5857a8a68f5SJulian Pullen 	}
5867a8a68f5SJulian Pullen 	return (0);
5877a8a68f5SJulian Pullen }
5887a8a68f5SJulian Pullen 
5897a8a68f5SJulian Pullen 
5907a8a68f5SJulian Pullen 
5917a8a68f5SJulian Pullen 
5927a8a68f5SJulian Pullen /* Convert a DN's DC components into a DNS domainname */
5937a8a68f5SJulian Pullen char *
DN_to_DNS(const char * dn_name)5947a8a68f5SJulian Pullen DN_to_DNS(const char *dn_name)
5957a8a68f5SJulian Pullen {
5967a8a68f5SJulian Pullen 	char	dns[DNS_MAX_NAME];
5977a8a68f5SJulian Pullen 	char	*dns_name;
5987a8a68f5SJulian Pullen 	int	i, j;
5997a8a68f5SJulian Pullen 	int	num = 0;
6007a8a68f5SJulian Pullen 
6017a8a68f5SJulian Pullen 	j = 0;
6027a8a68f5SJulian Pullen 	i = 0;
6037a8a68f5SJulian Pullen 
6047a8a68f5SJulian Pullen 	if (dn_name == NULL)
6057a8a68f5SJulian Pullen 		return (NULL);
6067a8a68f5SJulian Pullen 	/*
6077a8a68f5SJulian Pullen 	 * Find all DC=<value> and form DNS name of the
6087a8a68f5SJulian Pullen 	 * form <value1>.<value2>...
6097a8a68f5SJulian Pullen 	 */
6107a8a68f5SJulian Pullen 	while (dn_name[i] != '\0') {
6117a8a68f5SJulian Pullen 		if (strncasecmp(&dn_name[i], "DC=", 3) == 0) {
6127a8a68f5SJulian Pullen 			i += 3;
6137a8a68f5SJulian Pullen 			if (dn_name[i] != '\0' && num > 0)
6147a8a68f5SJulian Pullen 				dns[j++] = '.';
6157a8a68f5SJulian Pullen 			while (dn_name[i] != '\0' &&
6167a8a68f5SJulian Pullen 			    dn_name[i] != ',' && dn_name[i] != '+')
6177a8a68f5SJulian Pullen 				dns[j++] = dn_name[i++];
6187a8a68f5SJulian Pullen 			num++;
6197a8a68f5SJulian Pullen 		} else {
6207a8a68f5SJulian Pullen 			/* Skip attr=value as it is not DC= */
6217a8a68f5SJulian Pullen 			while (dn_name[i] != '\0' &&
6227a8a68f5SJulian Pullen 			    dn_name[i] != ',' && dn_name[i] != '+')
6237a8a68f5SJulian Pullen 				i++;
6247a8a68f5SJulian Pullen 		}
6257a8a68f5SJulian Pullen 		/* Skip over separator ','  or '+' */
6267a8a68f5SJulian Pullen 		if (dn_name[i] != '\0') i++;
6277a8a68f5SJulian Pullen 	}
6287a8a68f5SJulian Pullen 	dns[j] = '\0';
6297a8a68f5SJulian Pullen 	dns_name = malloc(j + 1);
6307a8a68f5SJulian Pullen 	if (dns_name != NULL)
6317a8a68f5SJulian Pullen 		(void) strlcpy(dns_name, dns, j + 1);
6327a8a68f5SJulian Pullen 	return (dns_name);
6337a8a68f5SJulian Pullen }
6347a8a68f5SJulian Pullen 
6357a8a68f5SJulian Pullen 
6367a8a68f5SJulian Pullen /*
6377a8a68f5SJulian Pullen  * A utility function to bind to a Directory server
6387a8a68f5SJulian Pullen  */
6397a8a68f5SJulian Pullen 
640c5866007SKeyur Desai static
641c5866007SKeyur Desai LDAP *
ldap_lookup_init(ad_disc_ds_t * ds)642*b3700b07SGordon Ross ldap_lookup_init(ad_disc_ds_t *ds)
6437a8a68f5SJulian Pullen {
6447a8a68f5SJulian Pullen 	int 	i;
6457a8a68f5SJulian Pullen 	int	rc, ldversion;
6467a8a68f5SJulian Pullen 	int	zero = 0;
6477a8a68f5SJulian Pullen 	int 	timeoutms = 5 * 1000;
6487a8a68f5SJulian Pullen 	char 	*saslmech = "GSSAPI";
6497a8a68f5SJulian Pullen 	uint32_t saslflags = LDAP_SASL_INTERACTIVE;
6507a8a68f5SJulian Pullen 	LDAP 	*ld = NULL;
6517a8a68f5SJulian Pullen 
6527a8a68f5SJulian Pullen 	for (i = 0; ds[i].host[0] != '\0'; i++) {
653*b3700b07SGordon Ross 		if (DBG(LDAP, 2)) {
654*b3700b07SGordon Ross 			logger(LOG_DEBUG, "adutils: ldap_lookup_init, host %s",
655*b3700b07SGordon Ross 			    ds[i].host);
656*b3700b07SGordon Ross 		}
657*b3700b07SGordon Ross 
6587a8a68f5SJulian Pullen 		ld = ldap_init(ds[i].host, ds[i].port);
6597a8a68f5SJulian Pullen 		if (ld == NULL) {
660148c5f43SAlan Wright 			if (DBG(LDAP, 1)) {
661148c5f43SAlan Wright 				logger(LOG_DEBUG,
662148c5f43SAlan Wright 				    "Couldn't connect to AD DC %s:%d (%s)",
6637a8a68f5SJulian Pullen 				    ds[i].host, ds[i].port,
6647a8a68f5SJulian Pullen 				    strerror(errno));
665148c5f43SAlan Wright 			}
6667a8a68f5SJulian Pullen 			continue;
6677a8a68f5SJulian Pullen 		}
6687a8a68f5SJulian Pullen 
6697a8a68f5SJulian Pullen 		ldversion = LDAP_VERSION3;
6707a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
6717a8a68f5SJulian Pullen 		    &ldversion);
6727a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS,
6737a8a68f5SJulian Pullen 		    LDAP_OPT_OFF);
6747a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
6757a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
6767a8a68f5SJulian Pullen 		/* setup TCP/IP connect timeout */
6777a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
6787a8a68f5SJulian Pullen 		    &timeoutms);
6797a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_RESTART,
6807a8a68f5SJulian Pullen 		    LDAP_OPT_ON);
6817a8a68f5SJulian Pullen 
682bd428526SJulian Pullen 		rc = adutils_set_thread_functions(ld);
683bd428526SJulian Pullen 		if (rc != LDAP_SUCCESS) {
684bd428526SJulian Pullen 			/* Error has already been logged */
685bd428526SJulian Pullen 			(void) ldap_unbind(ld);
686bd428526SJulian Pullen 			ld = NULL;
687bd428526SJulian Pullen 			continue;
688bd428526SJulian Pullen 		}
689bd428526SJulian Pullen 
6907a8a68f5SJulian Pullen 		rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */,
6917a8a68f5SJulian Pullen 		    saslmech, NULL, NULL, saslflags, &saslcallback,
6927a8a68f5SJulian Pullen 		    NULL /* defaults */);
6937a8a68f5SJulian Pullen 		if (rc == LDAP_SUCCESS)
6947a8a68f5SJulian Pullen 			break;
6957a8a68f5SJulian Pullen 
696148c5f43SAlan Wright 		if (DBG(LDAP, 0)) {
697148c5f43SAlan Wright 			logger(LOG_INFO, "LDAP: %s:%d: %s",
6987a8a68f5SJulian Pullen 			    ds[i].host, ds[i].port, ldap_err2string(rc));
699148c5f43SAlan Wright 			ldap_perror(ld, ds[i].host);
700148c5f43SAlan Wright 		}
7017a8a68f5SJulian Pullen 		(void) ldap_unbind(ld);
7027a8a68f5SJulian Pullen 		ld = NULL;
7037a8a68f5SJulian Pullen 	}
7047a8a68f5SJulian Pullen 	return (ld);
7057a8a68f5SJulian Pullen }
7067a8a68f5SJulian Pullen 
7077a8a68f5SJulian Pullen 
7087a8a68f5SJulian Pullen 
7097a8a68f5SJulian Pullen /*
7107a8a68f5SJulian Pullen  * Lookup the trusted domains in the global catalog.
7117a8a68f5SJulian Pullen  *
7127a8a68f5SJulian Pullen  * Returns:
7137a8a68f5SJulian Pullen  *	array of trusted domains which is terminated by
7147a8a68f5SJulian Pullen  *		an empty trusted domain.
7157a8a68f5SJulian Pullen  *	NULL an error occured
7167a8a68f5SJulian Pullen  */
7177a8a68f5SJulian Pullen ad_disc_trusteddomains_t *
ldap_lookup_trusted_domains(LDAP ** ld,ad_disc_ds_t * globalCatalog,char * base_dn)718*b3700b07SGordon Ross ldap_lookup_trusted_domains(LDAP **ld, ad_disc_ds_t *globalCatalog,
7197a8a68f5SJulian Pullen 			char *base_dn)
7207a8a68f5SJulian Pullen {
7217a8a68f5SJulian Pullen 	int		scope = LDAP_SCOPE_SUBTREE;
7227a8a68f5SJulian Pullen 	char		*attrs[3];
7237a8a68f5SJulian Pullen 	int		rc;
7247a8a68f5SJulian Pullen 	LDAPMessage	*results = NULL;
7257a8a68f5SJulian Pullen 	LDAPMessage	*entry;
7267a8a68f5SJulian Pullen 	char		*filter;
7277a8a68f5SJulian Pullen 	char		**partner = NULL;
7287a8a68f5SJulian Pullen 	char		**direction = NULL;
7297a8a68f5SJulian Pullen 	int		num = 0;
7307a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *trusted_domains = NULL;
7317a8a68f5SJulian Pullen 
732148c5f43SAlan Wright 	if (DBG(DISC, 1))
733148c5f43SAlan Wright 		logger(LOG_DEBUG, "Looking for trusted domains...");
7347a8a68f5SJulian Pullen 
7357a8a68f5SJulian Pullen 	if (*ld == NULL)
7367a8a68f5SJulian Pullen 		*ld = ldap_lookup_init(globalCatalog);
7377a8a68f5SJulian Pullen 
738*b3700b07SGordon Ross 	if (*ld == NULL) {
739*b3700b07SGordon Ross 		logger(LOG_ERR, "adutils: ldap_lookup_init failed");
7407a8a68f5SJulian Pullen 		return (NULL);
741*b3700b07SGordon Ross 	}
7427a8a68f5SJulian Pullen 
7437a8a68f5SJulian Pullen 	attrs[0] = "trustPartner";
7447a8a68f5SJulian Pullen 	attrs[1] = "trustDirection";
7457a8a68f5SJulian Pullen 	attrs[2] = NULL;
7467a8a68f5SJulian Pullen 
747148c5f43SAlan Wright 	/*
748148c5f43SAlan Wright 	 * Trust direction values:
749148c5f43SAlan Wright 	 * 1 - inbound (they trust us)
750148c5f43SAlan Wright 	 * 2 - outbound (we trust them)
751148c5f43SAlan Wright 	 * 3 - bidirectional (we trust each other)
752148c5f43SAlan Wright 	 */
7537a8a68f5SJulian Pullen 	filter = "(&(objectclass=trustedDomain)"
754148c5f43SAlan Wright 	    "(|(trustDirection=3)(trustDirection=2)))";
7557a8a68f5SJulian Pullen 
7567a8a68f5SJulian Pullen 	rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results);
757148c5f43SAlan Wright 	if (DBG(DISC, 1))
758148c5f43SAlan Wright 		logger(LOG_DEBUG, "Trusted domains:");
7597a8a68f5SJulian Pullen 	if (rc == LDAP_SUCCESS) {
7607a8a68f5SJulian Pullen 		for (entry = ldap_first_entry(*ld, results);
7617a8a68f5SJulian Pullen 		    entry != NULL; entry = ldap_next_entry(*ld, entry)) {
7627a8a68f5SJulian Pullen 			partner = ldap_get_values(*ld, entry, "trustPartner");
7637a8a68f5SJulian Pullen 			direction = ldap_get_values(
7647a8a68f5SJulian Pullen 			    *ld, entry, "trustDirection");
7657a8a68f5SJulian Pullen 
7667a8a68f5SJulian Pullen 			if (partner != NULL && direction != NULL) {
767148c5f43SAlan Wright 				if (DBG(DISC, 1)) {
768148c5f43SAlan Wright 					logger(LOG_DEBUG, "    %s (%s)",
769148c5f43SAlan Wright 					    partner[0], direction[0]);
770148c5f43SAlan Wright 				}
7717a8a68f5SJulian Pullen 				num++;
772c5866007SKeyur Desai 				void *tmp = realloc(trusted_domains,
7737a8a68f5SJulian Pullen 				    (num + 1) *
7747a8a68f5SJulian Pullen 				    sizeof (ad_disc_trusteddomains_t));
775c5866007SKeyur Desai 				if (tmp == NULL) {
776c5866007SKeyur Desai 					free(trusted_domains);
7777a8a68f5SJulian Pullen 					ldap_value_free(partner);
7787a8a68f5SJulian Pullen 					ldap_value_free(direction);
779148c5f43SAlan Wright 					(void) ldap_msgfree(results);
7807a8a68f5SJulian Pullen 					return (NULL);
7817a8a68f5SJulian Pullen 				}
782c5866007SKeyur Desai 				trusted_domains = tmp;
7837a8a68f5SJulian Pullen 				/* Last element should be zero */
784148c5f43SAlan Wright 				(void) memset(&trusted_domains[num], 0,
7857a8a68f5SJulian Pullen 				    sizeof (ad_disc_trusteddomains_t));
786148c5f43SAlan Wright 				(void) strcpy(trusted_domains[num - 1].domain,
7877a8a68f5SJulian Pullen 				    partner[0]);
7887a8a68f5SJulian Pullen 				trusted_domains[num - 1].direction =
7897a8a68f5SJulian Pullen 				    atoi(direction[0]);
7907a8a68f5SJulian Pullen 			}
7917a8a68f5SJulian Pullen 			if (partner != NULL)
7927a8a68f5SJulian Pullen 				ldap_value_free(partner);
7937a8a68f5SJulian Pullen 			if (direction != NULL)
7947a8a68f5SJulian Pullen 				ldap_value_free(direction);
7957a8a68f5SJulian Pullen 		}
7967a8a68f5SJulian Pullen 	} else if (rc == LDAP_NO_RESULTS_RETURNED) {
7977a8a68f5SJulian Pullen 		/* This is not an error - return empty trusted domain */
7987a8a68f5SJulian Pullen 		trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t));
799148c5f43SAlan Wright 		if (DBG(DISC, 1))
800148c5f43SAlan Wright 			logger(LOG_DEBUG, "    not found");
801*b3700b07SGordon Ross 	} else {
802*b3700b07SGordon Ross 		if (DBG(DISC, 1))
803*b3700b07SGordon Ross 			logger(LOG_DEBUG, "    rc=%d", rc);
8047a8a68f5SJulian Pullen 	}
8057a8a68f5SJulian Pullen 	if (results != NULL)
806148c5f43SAlan Wright 		(void) ldap_msgfree(results);
8077a8a68f5SJulian Pullen 
8087a8a68f5SJulian Pullen 	return (trusted_domains);
8097a8a68f5SJulian Pullen }
8107a8a68f5SJulian Pullen 
8117a8a68f5SJulian Pullen 
8127a8a68f5SJulian Pullen /*
8137a8a68f5SJulian Pullen  * This functions finds all the domains in a forest.
8147a8a68f5SJulian Pullen  */
8157a8a68f5SJulian Pullen ad_disc_domainsinforest_t *
ldap_lookup_domains_in_forest(LDAP ** ld,ad_disc_ds_t * globalCatalogs)816*b3700b07SGordon Ross ldap_lookup_domains_in_forest(LDAP **ld, ad_disc_ds_t *globalCatalogs)
8177a8a68f5SJulian Pullen {
818928e1f97SJordan Brown 	static char	*attrs[] = {
819928e1f97SJordan Brown 		"objectSid",
820928e1f97SJordan Brown 		NULL,
821928e1f97SJordan Brown 	};
8227a8a68f5SJulian Pullen 	int		rc;
8237a8a68f5SJulian Pullen 	LDAPMessage	*result = NULL;
8247a8a68f5SJulian Pullen 	LDAPMessage	*entry;
825928e1f97SJordan Brown 	int		ndomains = 0;
826928e1f97SJordan Brown 	int		nresults;
8277a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *domains = NULL;
8287a8a68f5SJulian Pullen 
829*b3700b07SGordon Ross 	if (DBG(DISC, 1))
830148c5f43SAlan Wright 		logger(LOG_DEBUG, "Looking for domains in forest...");
831148c5f43SAlan Wright 
8327a8a68f5SJulian Pullen 	if (*ld == NULL)
8337a8a68f5SJulian Pullen 		*ld = ldap_lookup_init(globalCatalogs);
8347a8a68f5SJulian Pullen 
835*b3700b07SGordon Ross 	if (*ld == NULL) {
836*b3700b07SGordon Ross 		logger(LOG_ERR, "adutils: ldap_lookup_init failed");
8377a8a68f5SJulian Pullen 		return (NULL);
838*b3700b07SGordon Ross 	}
8397a8a68f5SJulian Pullen 
8407a8a68f5SJulian Pullen 	/* Find domains */
841928e1f97SJordan Brown 	rc = ldap_search_s(*ld, "", LDAP_SCOPE_SUBTREE,
842928e1f97SJordan Brown 	    "(objectClass=Domain)", attrs, 0, &result);
843*b3700b07SGordon Ross 	if (rc != LDAP_SUCCESS) {
844*b3700b07SGordon Ross 		logger(LOG_ERR, "adutils: ldap_search, rc=%d", rc);
845*b3700b07SGordon Ross 		goto err;
846*b3700b07SGordon Ross 	}
847148c5f43SAlan Wright 	if (DBG(DISC, 1))
848148c5f43SAlan Wright 		logger(LOG_DEBUG, "Domains in forest:");
849928e1f97SJordan Brown 
850928e1f97SJordan Brown 	nresults = ldap_count_entries(*ld, result);
851928e1f97SJordan Brown 	domains = calloc(nresults + 1, sizeof (*domains));
852*b3700b07SGordon Ross 	if (domains == NULL) {
853*b3700b07SGordon Ross 		if (DBG(DISC, 1))
854*b3700b07SGordon Ross 			logger(LOG_DEBUG, "    (nomem)");
855928e1f97SJordan Brown 		goto err;
856*b3700b07SGordon Ross 	}
857928e1f97SJordan Brown 
858928e1f97SJordan Brown 	for (entry = ldap_first_entry(*ld, result);
859928e1f97SJordan Brown 	    entry != NULL;
860928e1f97SJordan Brown 	    entry = ldap_next_entry(*ld, entry)) {
861928e1f97SJordan Brown 		struct berval	**sid_ber;
862928e1f97SJordan Brown 		adutils_sid_t	sid;
863928e1f97SJordan Brown 		char		*sid_str;
864928e1f97SJordan Brown 		char 		*name;
865bbf6f00cSJordan Brown 		char		*dn;
866928e1f97SJordan Brown 
8677a8a68f5SJulian Pullen 		sid_ber = ldap_get_values_len(*ld, entry,
8687a8a68f5SJulian Pullen 		    "objectSid");
869928e1f97SJordan Brown 		if (sid_ber == NULL)
870928e1f97SJordan Brown 			continue;
8717a8a68f5SJulian Pullen 
872928e1f97SJordan Brown 		rc = adutils_getsid(sid_ber[0], &sid);
8737a8a68f5SJulian Pullen 		ldap_value_free_len(sid_ber);
874928e1f97SJordan Brown 		if (rc < 0)
875928e1f97SJordan Brown 			goto err;
8767a8a68f5SJulian Pullen 
877928e1f97SJordan Brown 		if ((sid_str = adutils_sid2txt(&sid)) == NULL)
878928e1f97SJordan Brown 			goto err;
879928e1f97SJordan Brown 
880148c5f43SAlan Wright 		(void) strcpy(domains[ndomains].sid, sid_str);
8817a8a68f5SJulian Pullen 		free(sid_str);
8827a8a68f5SJulian Pullen 
883bbf6f00cSJordan Brown 		dn = ldap_get_dn(*ld, entry);
884bbf6f00cSJordan Brown 		name = DN_to_DNS(dn);
885bbf6f00cSJordan Brown 		free(dn);
886928e1f97SJordan Brown 		if (name == NULL)
887928e1f97SJordan Brown 			goto err;
888928e1f97SJordan Brown 
889148c5f43SAlan Wright 		(void) strcpy(domains[ndomains].domain, name);
8907a8a68f5SJulian Pullen 		free(name);
891928e1f97SJordan Brown 
892148c5f43SAlan Wright 		if (DBG(DISC, 1))
893148c5f43SAlan Wright 			logger(LOG_DEBUG, "    %s", domains[ndomains].domain);
894928e1f97SJordan Brown 
895928e1f97SJordan Brown 		ndomains++;
8967a8a68f5SJulian Pullen 	}
897928e1f97SJordan Brown 
898148c5f43SAlan Wright 	if (ndomains == 0) {
899148c5f43SAlan Wright 		if (DBG(DISC, 1))
900148c5f43SAlan Wright 			logger(LOG_DEBUG, "    not found");
901928e1f97SJordan Brown 		goto err;
902148c5f43SAlan Wright 	}
903928e1f97SJordan Brown 
904928e1f97SJordan Brown 	if (ndomains < nresults) {
905928e1f97SJordan Brown 		ad_disc_domainsinforest_t *tmp;
906928e1f97SJordan Brown 		tmp = realloc(domains, (ndomains + 1) * sizeof (*domains));
907928e1f97SJordan Brown 		if (tmp == NULL)
908928e1f97SJordan Brown 			goto err;
909928e1f97SJordan Brown 		domains = tmp;
9107a8a68f5SJulian Pullen 	}
911928e1f97SJordan Brown 
9127a8a68f5SJulian Pullen 	if (result != NULL)
913148c5f43SAlan Wright 		(void) ldap_msgfree(result);
9147a8a68f5SJulian Pullen 
9157a8a68f5SJulian Pullen 	return (domains);
916928e1f97SJordan Brown 
917928e1f97SJordan Brown err:
918928e1f97SJordan Brown 	free(domains);
919928e1f97SJordan Brown 	if (result != NULL)
920148c5f43SAlan Wright 		(void) ldap_msgfree(result);
921928e1f97SJordan Brown 	return (NULL);
9227a8a68f5SJulian Pullen }
9237a8a68f5SJulian Pullen 
9247a8a68f5SJulian Pullen 
9257a8a68f5SJulian Pullen ad_disc_t
ad_disc_init(void)9267a8a68f5SJulian Pullen ad_disc_init(void)
9277a8a68f5SJulian Pullen {
9287a8a68f5SJulian Pullen 	struct ad_disc *ctx;
9297a8a68f5SJulian Pullen 	ctx = calloc(1, sizeof (struct ad_disc));
9307a8a68f5SJulian Pullen 	if (ctx != NULL)
9317a8a68f5SJulian Pullen 		DO_RES_NINIT(ctx);
9327a8a68f5SJulian Pullen 
9337a8a68f5SJulian Pullen 	ctx->domain_name.type = AD_STRING;
934*b3700b07SGordon Ross 	ctx->domain_guid.type = AD_UUID;
9357a8a68f5SJulian Pullen 	ctx->domain_controller.type = AD_DIRECTORY;
936*b3700b07SGordon Ross 	ctx->preferred_dc.type = AD_DIRECTORY;
9377a8a68f5SJulian Pullen 	ctx->site_name.type = AD_STRING;
9387a8a68f5SJulian Pullen 	ctx->forest_name.type = AD_STRING;
9397a8a68f5SJulian Pullen 	ctx->global_catalog.type = AD_DIRECTORY;
9407a8a68f5SJulian Pullen 	ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST;
9417a8a68f5SJulian Pullen 	ctx->trusted_domains.type = AD_TRUSTED_DOMAINS;
9427a8a68f5SJulian Pullen 	/* Site specific versions */
9437a8a68f5SJulian Pullen 	ctx->site_domain_controller.type = AD_DIRECTORY;
9447a8a68f5SJulian Pullen 	ctx->site_global_catalog.type = AD_DIRECTORY;
9457a8a68f5SJulian Pullen 	return (ctx);
9467a8a68f5SJulian Pullen }
9477a8a68f5SJulian Pullen 
9487a8a68f5SJulian Pullen void
ad_disc_fini(ad_disc_t ctx)9497a8a68f5SJulian Pullen ad_disc_fini(ad_disc_t ctx)
9507a8a68f5SJulian Pullen {
9517a8a68f5SJulian Pullen 	if (ctx == NULL)
9527a8a68f5SJulian Pullen 		return;
9537a8a68f5SJulian Pullen 
9547a8a68f5SJulian Pullen 	if (ctx->res_ninitted)
9557a8a68f5SJulian Pullen 		res_ndestroy(&ctx->res_state);
9567a8a68f5SJulian Pullen 
9577a8a68f5SJulian Pullen 	if (ctx->subnets != NULL)
9587a8a68f5SJulian Pullen 		free(ctx->subnets);
9597a8a68f5SJulian Pullen 
9607a8a68f5SJulian Pullen 	if (ctx->domain_name.value != NULL)
9617a8a68f5SJulian Pullen 		free(ctx->domain_name.value);
9627a8a68f5SJulian Pullen 
963*b3700b07SGordon Ross 	if (ctx->domain_guid.value != NULL)
964*b3700b07SGordon Ross 		free(ctx->domain_guid.value);
965*b3700b07SGordon Ross 
9667a8a68f5SJulian Pullen 	if (ctx->domain_controller.value != NULL)
9677a8a68f5SJulian Pullen 		free(ctx->domain_controller.value);
9687a8a68f5SJulian Pullen 
969*b3700b07SGordon Ross 	if (ctx->preferred_dc.value != NULL)
970*b3700b07SGordon Ross 		free(ctx->preferred_dc.value);
971*b3700b07SGordon Ross 
9727a8a68f5SJulian Pullen 	if (ctx->site_name.value != NULL)
9737a8a68f5SJulian Pullen 		free(ctx->site_name.value);
9747a8a68f5SJulian Pullen 
9757a8a68f5SJulian Pullen 	if (ctx->forest_name.value != NULL)
9767a8a68f5SJulian Pullen 		free(ctx->forest_name.value);
9777a8a68f5SJulian Pullen 
9787a8a68f5SJulian Pullen 	if (ctx->global_catalog.value != NULL)
9797a8a68f5SJulian Pullen 		free(ctx->global_catalog.value);
9807a8a68f5SJulian Pullen 
9817a8a68f5SJulian Pullen 	if (ctx->domains_in_forest.value != NULL)
9827a8a68f5SJulian Pullen 		free(ctx->domains_in_forest.value);
9837a8a68f5SJulian Pullen 
9847a8a68f5SJulian Pullen 	if (ctx->trusted_domains.value != NULL)
9857a8a68f5SJulian Pullen 		free(ctx->trusted_domains.value);
9867a8a68f5SJulian Pullen 
9877a8a68f5SJulian Pullen 	/* Site specific versions */
9887a8a68f5SJulian Pullen 	if (ctx->site_domain_controller.value != NULL)
9897a8a68f5SJulian Pullen 		free(ctx->site_domain_controller.value);
9907a8a68f5SJulian Pullen 
9917a8a68f5SJulian Pullen 	if (ctx->site_global_catalog.value != NULL)
9927a8a68f5SJulian Pullen 		free(ctx->site_global_catalog.value);
9937a8a68f5SJulian Pullen 
9947a8a68f5SJulian Pullen 	free(ctx);
9957a8a68f5SJulian Pullen }
9967a8a68f5SJulian Pullen 
9977a8a68f5SJulian Pullen void
ad_disc_refresh(ad_disc_t ctx)9987a8a68f5SJulian Pullen ad_disc_refresh(ad_disc_t ctx)
9997a8a68f5SJulian Pullen {
1000*b3700b07SGordon Ross 	if (ctx->res_ninitted) {
10017a8a68f5SJulian Pullen 		res_ndestroy(&ctx->res_state);
1002*b3700b07SGordon Ross 		ctx->res_ninitted = 0;
1003*b3700b07SGordon Ross 	}
10047a8a68f5SJulian Pullen 	(void) memset(&ctx->res_state, 0, sizeof (ctx->res_state));
1005*b3700b07SGordon Ross 	DO_RES_NINIT(ctx);
10067a8a68f5SJulian Pullen 
10077a8a68f5SJulian Pullen 	if (ctx->domain_name.state == AD_STATE_AUTO)
10087a8a68f5SJulian Pullen 		ctx->domain_name.state = AD_STATE_INVALID;
10097a8a68f5SJulian Pullen 
1010*b3700b07SGordon Ross 	if (ctx->domain_guid.state == AD_STATE_AUTO)
1011*b3700b07SGordon Ross 		ctx->domain_guid.state = AD_STATE_INVALID;
1012*b3700b07SGordon Ross 
10137a8a68f5SJulian Pullen 	if (ctx->domain_controller.state == AD_STATE_AUTO)
10147a8a68f5SJulian Pullen 		ctx->domain_controller.state  = AD_STATE_INVALID;
10157a8a68f5SJulian Pullen 
1016*b3700b07SGordon Ross 	if (ctx->preferred_dc.state == AD_STATE_AUTO)
1017*b3700b07SGordon Ross 		ctx->preferred_dc.state  = AD_STATE_INVALID;
1018*b3700b07SGordon Ross 
10197a8a68f5SJulian Pullen 	if (ctx->site_name.state == AD_STATE_AUTO)
10207a8a68f5SJulian Pullen 		ctx->site_name.state = AD_STATE_INVALID;
10217a8a68f5SJulian Pullen 
10227a8a68f5SJulian Pullen 	if (ctx->forest_name.state == AD_STATE_AUTO)
10237a8a68f5SJulian Pullen 		ctx->forest_name.state = AD_STATE_INVALID;
10247a8a68f5SJulian Pullen 
10257a8a68f5SJulian Pullen 	if (ctx->global_catalog.state == AD_STATE_AUTO)
10267a8a68f5SJulian Pullen 		ctx->global_catalog.state = AD_STATE_INVALID;
10277a8a68f5SJulian Pullen 
10287a8a68f5SJulian Pullen 	if (ctx->domains_in_forest.state == AD_STATE_AUTO)
10297a8a68f5SJulian Pullen 		ctx->domains_in_forest.state  = AD_STATE_INVALID;
10307a8a68f5SJulian Pullen 
10317a8a68f5SJulian Pullen 	if (ctx->trusted_domains.state == AD_STATE_AUTO)
10327a8a68f5SJulian Pullen 		ctx->trusted_domains.state  = AD_STATE_INVALID;
10337a8a68f5SJulian Pullen 
10347a8a68f5SJulian Pullen 	if (ctx->site_domain_controller.state == AD_STATE_AUTO)
10357a8a68f5SJulian Pullen 		ctx->site_domain_controller.state  = AD_STATE_INVALID;
10367a8a68f5SJulian Pullen 
10377a8a68f5SJulian Pullen 	if (ctx->site_global_catalog.state == AD_STATE_AUTO)
10387a8a68f5SJulian Pullen 		ctx->site_global_catalog.state = AD_STATE_INVALID;
10397a8a68f5SJulian Pullen }
10407a8a68f5SJulian Pullen 
10417a8a68f5SJulian Pullen 
1042c5866007SKeyur Desai /*
1043c5866007SKeyur Desai  * Called when the discovery cycle is done.  Sets a master TTL
1044c5866007SKeyur Desai  * that will avoid doing new time-based discoveries too soon after
1045c5866007SKeyur Desai  * the last discovery cycle.  Most interesting when the discovery
1046c5866007SKeyur Desai  * cycle failed, because then the TTLs on the individual items will
1047c5866007SKeyur Desai  * not be updated and may go stale.
1048c5866007SKeyur Desai  */
1049c5866007SKeyur Desai void
ad_disc_done(ad_disc_t ctx)1050c5866007SKeyur Desai ad_disc_done(ad_disc_t ctx)
1051c5866007SKeyur Desai {
1052c5866007SKeyur Desai 	time_t now = time(NULL);
1053c5866007SKeyur Desai 
1054c5866007SKeyur Desai 	ctx->expires_not_before = now + MINIMUM_TTL;
1055c5866007SKeyur Desai 	ctx->expires_not_after = now + MAXIMUM_TTL;
1056c5866007SKeyur Desai }
1057c5866007SKeyur Desai 
1058*b3700b07SGordon Ross static void
log_cds(ad_disc_t ctx,ad_disc_cds_t * cds)1059*b3700b07SGordon Ross log_cds(ad_disc_t ctx, ad_disc_cds_t *cds)
1060*b3700b07SGordon Ross {
1061*b3700b07SGordon Ross 	char buf[INET6_ADDRSTRLEN];
1062*b3700b07SGordon Ross 	struct addrinfo *ai;
1063*b3700b07SGordon Ross 
1064*b3700b07SGordon Ross 	if (!DBG(DISC, 1) && ctx->status_fp == NULL)
1065*b3700b07SGordon Ross 		return;
1066*b3700b07SGordon Ross 
1067*b3700b07SGordon Ross 	DEBUG1STATUS(ctx, "Candidate servers:");
1068*b3700b07SGordon Ross 	if (cds->cds_ds.host[0] == '\0') {
1069*b3700b07SGordon Ross 		DEBUG1STATUS(ctx, "  (empty list)");
1070*b3700b07SGordon Ross 		return;
1071*b3700b07SGordon Ross 	}
1072*b3700b07SGordon Ross 
1073*b3700b07SGordon Ross 	while (cds->cds_ds.host[0] != '\0') {
1074*b3700b07SGordon Ross 
1075*b3700b07SGordon Ross 		DEBUG1STATUS(ctx, "  %s  p=%d w=%d",
1076*b3700b07SGordon Ross 		    cds->cds_ds.host,
1077*b3700b07SGordon Ross 		    cds->cds_ds.priority,
1078*b3700b07SGordon Ross 		    cds->cds_ds.weight);
1079*b3700b07SGordon Ross 
1080*b3700b07SGordon Ross 		ai = cds->cds_ai;
1081*b3700b07SGordon Ross 		if (ai == NULL) {
1082*b3700b07SGordon Ross 			DEBUG1STATUS(ctx, "    (no address)");
1083*b3700b07SGordon Ross 		}
1084*b3700b07SGordon Ross 		while (ai != NULL) {
1085*b3700b07SGordon Ross 			int eai;
1086*b3700b07SGordon Ross 
1087*b3700b07SGordon Ross 			eai = getnameinfo(ai->ai_addr, ai->ai_addrlen,
1088*b3700b07SGordon Ross 			    buf, sizeof (buf), NULL, 0, NI_NUMERICHOST);
1089*b3700b07SGordon Ross 			if (eai != 0)
1090*b3700b07SGordon Ross 				(void) strlcpy(buf, "?", sizeof (buf));
1091*b3700b07SGordon Ross 
1092*b3700b07SGordon Ross 			DEBUG1STATUS(ctx, "    %s", buf);
1093*b3700b07SGordon Ross 			ai = ai->ai_next;
1094*b3700b07SGordon Ross 		}
1095*b3700b07SGordon Ross 		cds++;
1096*b3700b07SGordon Ross 	}
1097*b3700b07SGordon Ross }
1098*b3700b07SGordon Ross 
1099*b3700b07SGordon Ross static void
log_ds(ad_disc_t ctx,ad_disc_ds_t * ds)1100*b3700b07SGordon Ross log_ds(ad_disc_t ctx, ad_disc_ds_t *ds)
1101*b3700b07SGordon Ross {
1102*b3700b07SGordon Ross 	char buf[INET6_ADDRSTRLEN];
1103*b3700b07SGordon Ross 
1104*b3700b07SGordon Ross 	if (!DBG(DISC, 1) && ctx->status_fp == NULL)
1105*b3700b07SGordon Ross 		return;
1106*b3700b07SGordon Ross 
1107*b3700b07SGordon Ross 	DEBUG1STATUS(ctx, "Responding servers:");
1108*b3700b07SGordon Ross 	if (ds->host[0] == '\0') {
1109*b3700b07SGordon Ross 		DEBUG1STATUS(ctx, "  (empty list)");
1110*b3700b07SGordon Ross 		return;
1111*b3700b07SGordon Ross 	}
1112*b3700b07SGordon Ross 
1113*b3700b07SGordon Ross 	while (ds->host[0] != '\0') {
1114*b3700b07SGordon Ross 
1115*b3700b07SGordon Ross 		DEBUG1STATUS(ctx, "  %s", ds->host);
1116*b3700b07SGordon Ross 		DO_GETNAMEINFO(buf, sizeof (buf), &ds->addr);
1117*b3700b07SGordon Ross 		DEBUG1STATUS(ctx, "    %s", buf);
1118*b3700b07SGordon Ross 
1119*b3700b07SGordon Ross 		ds++;
1120*b3700b07SGordon Ross 	}
1121*b3700b07SGordon Ross }
11227a8a68f5SJulian Pullen 
11237a8a68f5SJulian Pullen /* Discover joined Active Directory domainName */
11247a8a68f5SJulian Pullen static ad_item_t *
validate_DomainName(ad_disc_t ctx)11257a8a68f5SJulian Pullen validate_DomainName(ad_disc_t ctx)
11267a8a68f5SJulian Pullen {
11277a8a68f5SJulian Pullen 	char *dname, *srvname;
1128*b3700b07SGordon Ross 	int len, rc;
11297a8a68f5SJulian Pullen 
11307a8a68f5SJulian Pullen 	if (is_valid(&ctx->domain_name))
11317a8a68f5SJulian Pullen 		return (&ctx->domain_name);
11327a8a68f5SJulian Pullen 
11337a8a68f5SJulian Pullen 
11347a8a68f5SJulian Pullen 	/* Try to find our domain by searching for DCs for it */
11357a8a68f5SJulian Pullen 	DO_RES_NINIT(ctx);
1136*b3700b07SGordon Ross 	if (DBG(DISC, 1))
1137148c5f43SAlan Wright 		logger(LOG_DEBUG, "Looking for our AD domain name...");
1138*b3700b07SGordon Ross 	rc = srv_getdom(&ctx->res_state,
1139*b3700b07SGordon Ross 	    LDAP_SRV_HEAD DC_SRV_TAIL, &srvname);
11407a8a68f5SJulian Pullen 
11417a8a68f5SJulian Pullen 	/*
11427a8a68f5SJulian Pullen 	 * If we can't find DCs by via res_nsearch() then there's no
11437a8a68f5SJulian Pullen 	 * point in trying anything else to discover the AD domain name.
11447a8a68f5SJulian Pullen 	 */
1145*b3700b07SGordon Ross 	if (rc < 0) {
1146148c5f43SAlan Wright 		if (DBG(DISC, 1))
1147148c5f43SAlan Wright 			logger(LOG_DEBUG, "Can't find our domain name.");
11487a8a68f5SJulian Pullen 		return (NULL);
1149148c5f43SAlan Wright 	}
11507a8a68f5SJulian Pullen 
11517a8a68f5SJulian Pullen 	/*
11527a8a68f5SJulian Pullen 	 * We have the FQDN of the SRV RR name, so now we extract the
11537a8a68f5SJulian Pullen 	 * domainname suffix from it.
11547a8a68f5SJulian Pullen 	 */
11557a8a68f5SJulian Pullen 	dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) +
11567a8a68f5SJulian Pullen 	    1 /* for the dot between RR name and domainname */);
11577a8a68f5SJulian Pullen 
11587a8a68f5SJulian Pullen 	free(srvname);
11597a8a68f5SJulian Pullen 
11607a8a68f5SJulian Pullen 	if (dname == NULL) {
11617a8a68f5SJulian Pullen 		logger(LOG_ERR, "Out of memory");
11627a8a68f5SJulian Pullen 		return (NULL);
11637a8a68f5SJulian Pullen 	}
11647a8a68f5SJulian Pullen 
11657a8a68f5SJulian Pullen 	/* Eat any trailing dot */
1166928e1f97SJordan Brown 	len = strlen(dname);
1167928e1f97SJordan Brown 	if (len > 0 && dname[len - 1] == '.')
1168928e1f97SJordan Brown 		dname[len - 1] = '\0';
11697a8a68f5SJulian Pullen 
1170148c5f43SAlan Wright 	if (DBG(DISC, 1))
1171148c5f43SAlan Wright 		logger(LOG_DEBUG, "Our domain name:  %s", dname);
1172*b3700b07SGordon Ross 
1173*b3700b07SGordon Ross 	/*
1174*b3700b07SGordon Ross 	 * There is no "time to live" on the discovered domain,
1175*b3700b07SGordon Ross 	 * so passing zero as TTL here, making it non-expiring.
1176*b3700b07SGordon Ross 	 * Note that current consumers do not auto-discover the
1177*b3700b07SGordon Ross 	 * domain name, though a future installer could.
1178*b3700b07SGordon Ross 	 */
1179*b3700b07SGordon Ross 	update_item(&ctx->domain_name, dname, AD_STATE_AUTO, 0);
11807a8a68f5SJulian Pullen 
11817a8a68f5SJulian Pullen 	return (&ctx->domain_name);
11827a8a68f5SJulian Pullen }
11837a8a68f5SJulian Pullen 
11847a8a68f5SJulian Pullen 
11857a8a68f5SJulian Pullen char *
ad_disc_get_DomainName(ad_disc_t ctx,boolean_t * auto_discovered)11867a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered)
11877a8a68f5SJulian Pullen {
11887a8a68f5SJulian Pullen 	char *domain_name = NULL;
11897a8a68f5SJulian Pullen 	ad_item_t *domain_name_item;
11907a8a68f5SJulian Pullen 
11917a8a68f5SJulian Pullen 	domain_name_item = validate_DomainName(ctx);
11927a8a68f5SJulian Pullen 
11937a8a68f5SJulian Pullen 	if (domain_name_item) {
11947a8a68f5SJulian Pullen 		domain_name = strdup(domain_name_item->value);
11957a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
11967a8a68f5SJulian Pullen 			*auto_discovered =
11977a8a68f5SJulian Pullen 			    (domain_name_item->state == AD_STATE_AUTO);
11987a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
11997a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
12007a8a68f5SJulian Pullen 
12017a8a68f5SJulian Pullen 	return (domain_name);
12027a8a68f5SJulian Pullen }
12037a8a68f5SJulian Pullen 
12047a8a68f5SJulian Pullen 
12057a8a68f5SJulian Pullen /* Discover domain controllers */
12067a8a68f5SJulian Pullen static ad_item_t *
validate_DomainController(ad_disc_t ctx,enum ad_disc_req req)12077a8a68f5SJulian Pullen validate_DomainController(ad_disc_t ctx, enum ad_disc_req req)
12087a8a68f5SJulian Pullen {
1209*b3700b07SGordon Ross 	ad_disc_ds_t *dc = NULL;
1210*b3700b07SGordon Ross 	ad_disc_cds_t *cdc = NULL;
12117a8a68f5SJulian Pullen 	boolean_t validate_global = B_FALSE;
12127a8a68f5SJulian Pullen 	boolean_t validate_site = B_FALSE;
12137a8a68f5SJulian Pullen 	ad_item_t *domain_name_item;
1214*b3700b07SGordon Ross 	char *domain_name;
12157a8a68f5SJulian Pullen 	ad_item_t *site_name_item = NULL;
1216*b3700b07SGordon Ross 	char *site_name;
1217*b3700b07SGordon Ross 	ad_item_t *prefer_dc_item;
1218*b3700b07SGordon Ross 	ad_disc_ds_t *prefer_dc = NULL;
12197a8a68f5SJulian Pullen 
12207a8a68f5SJulian Pullen 	/* If the values is fixed there will not be a site specific version */
12217a8a68f5SJulian Pullen 	if (is_fixed(&ctx->domain_controller))
12227a8a68f5SJulian Pullen 		return (&ctx->domain_controller);
12237a8a68f5SJulian Pullen 
12247a8a68f5SJulian Pullen 	domain_name_item = validate_DomainName(ctx);
12257a8a68f5SJulian Pullen 	if (domain_name_item == NULL)
12267a8a68f5SJulian Pullen 		return (NULL);
1227*b3700b07SGordon Ross 	domain_name = (char *)domain_name_item->value;
1228*b3700b07SGordon Ross 
1229*b3700b07SGordon Ross 	/* Get (optional) preferred DC. */
1230*b3700b07SGordon Ross 	prefer_dc_item = validate_PreferredDC(ctx);
1231*b3700b07SGordon Ross 	if (prefer_dc_item != NULL)
1232*b3700b07SGordon Ross 		prefer_dc = prefer_dc_item->value;
12337a8a68f5SJulian Pullen 
12347a8a68f5SJulian Pullen 	if (req == AD_DISC_GLOBAL)
12357a8a68f5SJulian Pullen 		validate_global = B_TRUE;
12367a8a68f5SJulian Pullen 	else {
1237*b3700b07SGordon Ross 		if (is_fixed(&ctx->site_name))
12387a8a68f5SJulian Pullen 			validate_site = B_TRUE;
12397a8a68f5SJulian Pullen 		else if (req == AD_DISC_PREFER_SITE)
12407a8a68f5SJulian Pullen 			validate_global = B_TRUE;
12417a8a68f5SJulian Pullen 	}
12427a8a68f5SJulian Pullen 
12437a8a68f5SJulian Pullen 	if (validate_global) {
12447a8a68f5SJulian Pullen 		if (!is_valid(&ctx->domain_controller) ||
12457a8a68f5SJulian Pullen 		    is_changed(&ctx->domain_controller, PARAM1,
12467a8a68f5SJulian Pullen 		    domain_name_item)) {
1247*b3700b07SGordon Ross 
12487a8a68f5SJulian Pullen 			/*
12497a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named
12507a8a68f5SJulian Pullen 			 * _ldap._tcp.dc._msdcs.<DomainName>
12517a8a68f5SJulian Pullen 			 */
1252*b3700b07SGordon Ross 			DEBUG1STATUS(ctx, "DNS SRV query, dom=%s",
1253*b3700b07SGordon Ross 			    domain_name);
12547a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1255*b3700b07SGordon Ross 			cdc = srv_query(&ctx->res_state,
12567a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD DC_SRV_TAIL,
1257*b3700b07SGordon Ross 			    domain_name, prefer_dc);
12587a8a68f5SJulian Pullen 
1259*b3700b07SGordon Ross 			if (cdc == NULL) {
1260*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no DNS response)");
12617a8a68f5SJulian Pullen 				return (NULL);
1262148c5f43SAlan Wright 			}
1263*b3700b07SGordon Ross 			log_cds(ctx, cdc);
1264148c5f43SAlan Wright 
1265*b3700b07SGordon Ross 			/*
1266*b3700b07SGordon Ross 			 * Filter out unresponsive servers, and
1267*b3700b07SGordon Ross 			 * save the domain info we get back.
1268*b3700b07SGordon Ross 			 */
1269*b3700b07SGordon Ross 			dc = ldap_ping(
1270*b3700b07SGordon Ross 			    ctx,
1271*b3700b07SGordon Ross 			    cdc,
1272*b3700b07SGordon Ross 			    domain_name,
1273*b3700b07SGordon Ross 			    DS_DS_FLAG);
1274*b3700b07SGordon Ross 			srv_free(cdc);
1275*b3700b07SGordon Ross 			cdc = NULL;
1276148c5f43SAlan Wright 
1277*b3700b07SGordon Ross 			if (dc == NULL) {
1278*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no LDAP response)");
1279*b3700b07SGordon Ross 				return (NULL);
1280148c5f43SAlan Wright 			}
1281*b3700b07SGordon Ross 			log_ds(ctx, dc);
12827a8a68f5SJulian Pullen 
1283*b3700b07SGordon Ross 			update_item(&ctx->domain_controller, dc,
1284*b3700b07SGordon Ross 			    AD_STATE_AUTO, dc->ttl);
12857a8a68f5SJulian Pullen 			update_version(&ctx->domain_controller, PARAM1,
12867a8a68f5SJulian Pullen 			    domain_name_item);
12877a8a68f5SJulian Pullen 		}
12887a8a68f5SJulian Pullen 		return (&ctx->domain_controller);
12897a8a68f5SJulian Pullen 	}
12907a8a68f5SJulian Pullen 
12917a8a68f5SJulian Pullen 	if (validate_site) {
1292*b3700b07SGordon Ross 		site_name_item = &ctx->site_name;
1293*b3700b07SGordon Ross 		site_name = (char *)site_name_item->value;
1294*b3700b07SGordon Ross 
12957a8a68f5SJulian Pullen 		if (!is_valid(&ctx->site_domain_controller) ||
12967a8a68f5SJulian Pullen 		    is_changed(&ctx->site_domain_controller, PARAM1,
12977a8a68f5SJulian Pullen 		    domain_name_item) ||
12987a8a68f5SJulian Pullen 		    is_changed(&ctx->site_domain_controller, PARAM2,
12997a8a68f5SJulian Pullen 		    site_name_item)) {
13007a8a68f5SJulian Pullen 			char rr_name[DNS_MAX_NAME];
1301*b3700b07SGordon Ross 
13027a8a68f5SJulian Pullen 			/*
13037a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named
13047a8a68f5SJulian Pullen 			 * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName>
13057a8a68f5SJulian Pullen 			 */
1306*b3700b07SGordon Ross 			DEBUG1STATUS(ctx, "DNS SRV query, dom=%s, site=%s",
1307*b3700b07SGordon Ross 			    domain_name, site_name);
13087a8a68f5SJulian Pullen 			(void) snprintf(rr_name, sizeof (rr_name),
13097a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL,
1310*b3700b07SGordon Ross 			    site_name);
13117a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1312*b3700b07SGordon Ross 			cdc = srv_query(&ctx->res_state, rr_name,
1313*b3700b07SGordon Ross 			    domain_name, prefer_dc);
1314*b3700b07SGordon Ross 
1315*b3700b07SGordon Ross 			if (cdc == NULL) {
1316*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no DNS response)");
13177a8a68f5SJulian Pullen 				return (NULL);
1318148c5f43SAlan Wright 			}
1319*b3700b07SGordon Ross 			log_cds(ctx, cdc);
1320148c5f43SAlan Wright 
1321*b3700b07SGordon Ross 			/*
1322*b3700b07SGordon Ross 			 * Filter out unresponsive servers, and
1323*b3700b07SGordon Ross 			 * save the domain info we get back.
1324*b3700b07SGordon Ross 			 */
1325*b3700b07SGordon Ross 			dc = ldap_ping(
1326*b3700b07SGordon Ross 			    ctx,
1327*b3700b07SGordon Ross 			    cdc,
1328*b3700b07SGordon Ross 			    domain_name,
1329*b3700b07SGordon Ross 			    DS_DS_FLAG);
1330*b3700b07SGordon Ross 			srv_free(cdc);
1331*b3700b07SGordon Ross 			cdc = NULL;
1332148c5f43SAlan Wright 
1333*b3700b07SGordon Ross 			if (dc == NULL) {
1334*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no LDAP response)");
1335*b3700b07SGordon Ross 				return (NULL);
1336148c5f43SAlan Wright 			}
1337*b3700b07SGordon Ross 			log_ds(ctx, dc);
13387a8a68f5SJulian Pullen 
1339*b3700b07SGordon Ross 			update_item(&ctx->site_domain_controller, dc,
1340*b3700b07SGordon Ross 			    AD_STATE_AUTO, dc->ttl);
13417a8a68f5SJulian Pullen 			update_version(&ctx->site_domain_controller, PARAM1,
13427a8a68f5SJulian Pullen 			    domain_name_item);
13437a8a68f5SJulian Pullen 			update_version(&ctx->site_domain_controller, PARAM2,
13447a8a68f5SJulian Pullen 			    site_name_item);
13457a8a68f5SJulian Pullen 		}
13467a8a68f5SJulian Pullen 		return (&ctx->site_domain_controller);
13477a8a68f5SJulian Pullen 	}
13487a8a68f5SJulian Pullen 	return (NULL);
13497a8a68f5SJulian Pullen }
13507a8a68f5SJulian Pullen 
1351*b3700b07SGordon Ross ad_disc_ds_t *
ad_disc_get_DomainController(ad_disc_t ctx,enum ad_disc_req req,boolean_t * auto_discovered)13527a8a68f5SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req,
13537a8a68f5SJulian Pullen     boolean_t *auto_discovered)
13547a8a68f5SJulian Pullen {
13557a8a68f5SJulian Pullen 	ad_item_t *domain_controller_item;
1356*b3700b07SGordon Ross 	ad_disc_ds_t *domain_controller = NULL;
13577a8a68f5SJulian Pullen 
13587a8a68f5SJulian Pullen 	domain_controller_item = validate_DomainController(ctx, req);
13597a8a68f5SJulian Pullen 
13607a8a68f5SJulian Pullen 	if (domain_controller_item != NULL) {
13617a8a68f5SJulian Pullen 		domain_controller = ds_dup(domain_controller_item->value);
13627a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
13637a8a68f5SJulian Pullen 			*auto_discovered =
13647a8a68f5SJulian Pullen 			    (domain_controller_item->state == AD_STATE_AUTO);
13657a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
13667a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
13677a8a68f5SJulian Pullen 
13687a8a68f5SJulian Pullen 	return (domain_controller);
13697a8a68f5SJulian Pullen }
13707a8a68f5SJulian Pullen 
13717a8a68f5SJulian Pullen 
1372*b3700b07SGordon Ross /*
1373*b3700b07SGordon Ross  * Discover the Domain GUID
1374*b3700b07SGordon Ross  * This info comes from validate_DomainController()
1375*b3700b07SGordon Ross  */
1376*b3700b07SGordon Ross static ad_item_t *
validate_DomainGUID(ad_disc_t ctx)1377*b3700b07SGordon Ross validate_DomainGUID(ad_disc_t ctx)
1378*b3700b07SGordon Ross {
1379*b3700b07SGordon Ross 	ad_item_t *domain_controller_item;
1380*b3700b07SGordon Ross 
1381*b3700b07SGordon Ross 	if (is_fixed(&ctx->domain_guid))
1382*b3700b07SGordon Ross 		return (&ctx->domain_guid);
1383*b3700b07SGordon Ross 
1384*b3700b07SGordon Ross 	domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL);
1385*b3700b07SGordon Ross 	if (domain_controller_item == NULL)
1386*b3700b07SGordon Ross 		return (NULL);
1387*b3700b07SGordon Ross 
1388*b3700b07SGordon Ross 	if (!is_valid(&ctx->domain_guid))
1389*b3700b07SGordon Ross 		return (NULL);
1390*b3700b07SGordon Ross 
1391*b3700b07SGordon Ross 	return (&ctx->domain_guid);
1392*b3700b07SGordon Ross }
1393*b3700b07SGordon Ross 
1394*b3700b07SGordon Ross 
1395*b3700b07SGordon Ross uchar_t *
ad_disc_get_DomainGUID(ad_disc_t ctx,boolean_t * auto_discovered)1396*b3700b07SGordon Ross ad_disc_get_DomainGUID(ad_disc_t ctx, boolean_t *auto_discovered)
1397*b3700b07SGordon Ross {
1398*b3700b07SGordon Ross 	ad_item_t *domain_guid_item;
1399*b3700b07SGordon Ross 	uchar_t	*domain_guid = NULL;
1400*b3700b07SGordon Ross 
1401*b3700b07SGordon Ross 	domain_guid_item = validate_DomainGUID(ctx);
1402*b3700b07SGordon Ross 	if (domain_guid_item != NULL) {
1403*b3700b07SGordon Ross 		domain_guid = uuid_dup(domain_guid_item->value);
1404*b3700b07SGordon Ross 		if (auto_discovered != NULL)
1405*b3700b07SGordon Ross 			*auto_discovered =
1406*b3700b07SGordon Ross 			    (domain_guid_item->state == AD_STATE_AUTO);
1407*b3700b07SGordon Ross 	} else if (auto_discovered != NULL)
1408*b3700b07SGordon Ross 		*auto_discovered = B_FALSE;
1409*b3700b07SGordon Ross 
1410*b3700b07SGordon Ross 	return (domain_guid);
1411*b3700b07SGordon Ross }
1412*b3700b07SGordon Ross 
1413*b3700b07SGordon Ross 
1414*b3700b07SGordon Ross /*
1415*b3700b07SGordon Ross  * Discover site name (for multi-homed systems the first one found wins)
1416*b3700b07SGordon Ross  * This info comes from validate_DomainController()
1417*b3700b07SGordon Ross  */
14187a8a68f5SJulian Pullen static ad_item_t *
validate_SiteName(ad_disc_t ctx)14197a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx)
14207a8a68f5SJulian Pullen {
14217a8a68f5SJulian Pullen 	ad_item_t *domain_controller_item;
14227a8a68f5SJulian Pullen 
14237a8a68f5SJulian Pullen 	if (is_fixed(&ctx->site_name))
14247a8a68f5SJulian Pullen 		return (&ctx->site_name);
14257a8a68f5SJulian Pullen 
14267a8a68f5SJulian Pullen 	domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL);
14277a8a68f5SJulian Pullen 	if (domain_controller_item == NULL)
14287a8a68f5SJulian Pullen 		return (NULL);
14297a8a68f5SJulian Pullen 
1430*b3700b07SGordon Ross 	if (!is_valid(&ctx->site_name))
14317a8a68f5SJulian Pullen 		return (NULL);
14327a8a68f5SJulian Pullen 
14337a8a68f5SJulian Pullen 	return (&ctx->site_name);
14347a8a68f5SJulian Pullen }
14357a8a68f5SJulian Pullen 
14367a8a68f5SJulian Pullen 
14377a8a68f5SJulian Pullen char *
ad_disc_get_SiteName(ad_disc_t ctx,boolean_t * auto_discovered)14387a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered)
14397a8a68f5SJulian Pullen {
14407a8a68f5SJulian Pullen 	ad_item_t *site_name_item;
14417a8a68f5SJulian Pullen 	char	*site_name = NULL;
14427a8a68f5SJulian Pullen 
14437a8a68f5SJulian Pullen 	site_name_item = validate_SiteName(ctx);
14447a8a68f5SJulian Pullen 	if (site_name_item != NULL) {
14457a8a68f5SJulian Pullen 		site_name = strdup(site_name_item->value);
14467a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
14477a8a68f5SJulian Pullen 			*auto_discovered =
14487a8a68f5SJulian Pullen 			    (site_name_item->state == AD_STATE_AUTO);
14497a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
14507a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
14517a8a68f5SJulian Pullen 
14527a8a68f5SJulian Pullen 	return (site_name);
14537a8a68f5SJulian Pullen }
14547a8a68f5SJulian Pullen 
14557a8a68f5SJulian Pullen 
14567a8a68f5SJulian Pullen 
1457*b3700b07SGordon Ross /*
1458*b3700b07SGordon Ross  * Discover forest name
1459*b3700b07SGordon Ross  * This info comes from validate_DomainController()
1460*b3700b07SGordon Ross  */
14617a8a68f5SJulian Pullen static ad_item_t *
validate_ForestName(ad_disc_t ctx)14627a8a68f5SJulian Pullen validate_ForestName(ad_disc_t ctx)
14637a8a68f5SJulian Pullen {
14647a8a68f5SJulian Pullen 	ad_item_t *domain_controller_item;
14657a8a68f5SJulian Pullen 
14667a8a68f5SJulian Pullen 	if (is_fixed(&ctx->forest_name))
14677a8a68f5SJulian Pullen 		return (&ctx->forest_name);
1468*b3700b07SGordon Ross 
14697a8a68f5SJulian Pullen 	domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL);
14707a8a68f5SJulian Pullen 	if (domain_controller_item == NULL)
14717a8a68f5SJulian Pullen 		return (NULL);
14727a8a68f5SJulian Pullen 
1473*b3700b07SGordon Ross 	if (!is_valid(&ctx->forest_name))
14747a8a68f5SJulian Pullen 		return (NULL);
1475148c5f43SAlan Wright 
14767a8a68f5SJulian Pullen 	return (&ctx->forest_name);
14777a8a68f5SJulian Pullen }
14787a8a68f5SJulian Pullen 
14797a8a68f5SJulian Pullen 
14807a8a68f5SJulian Pullen char *
ad_disc_get_ForestName(ad_disc_t ctx,boolean_t * auto_discovered)14817a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered)
14827a8a68f5SJulian Pullen {
14837a8a68f5SJulian Pullen 	ad_item_t *forest_name_item;
14847a8a68f5SJulian Pullen 	char	*forest_name = NULL;
14857a8a68f5SJulian Pullen 
14867a8a68f5SJulian Pullen 	forest_name_item = validate_ForestName(ctx);
14877a8a68f5SJulian Pullen 
14887a8a68f5SJulian Pullen 	if (forest_name_item != NULL) {
14897a8a68f5SJulian Pullen 		forest_name = strdup(forest_name_item->value);
14907a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
14917a8a68f5SJulian Pullen 			*auto_discovered =
14927a8a68f5SJulian Pullen 			    (forest_name_item->state == AD_STATE_AUTO);
14937a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
14947a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
14957a8a68f5SJulian Pullen 
14967a8a68f5SJulian Pullen 	return (forest_name);
14977a8a68f5SJulian Pullen }
14987a8a68f5SJulian Pullen 
14997a8a68f5SJulian Pullen 
15007a8a68f5SJulian Pullen /* Discover global catalog servers */
15017a8a68f5SJulian Pullen static ad_item_t *
validate_GlobalCatalog(ad_disc_t ctx,enum ad_disc_req req)15027a8a68f5SJulian Pullen validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req)
15037a8a68f5SJulian Pullen {
1504*b3700b07SGordon Ross 	ad_disc_ds_t *gc = NULL;
1505*b3700b07SGordon Ross 	ad_disc_cds_t *cgc = NULL;
15067a8a68f5SJulian Pullen 	boolean_t validate_global = B_FALSE;
15077a8a68f5SJulian Pullen 	boolean_t validate_site = B_FALSE;
1508*b3700b07SGordon Ross 	ad_item_t *dc_item;
15097a8a68f5SJulian Pullen 	ad_item_t *forest_name_item;
15107a8a68f5SJulian Pullen 	ad_item_t *site_name_item;
1511*b3700b07SGordon Ross 	char *forest_name;
1512*b3700b07SGordon Ross 	char *site_name;
15137a8a68f5SJulian Pullen 
15147a8a68f5SJulian Pullen 	/* If the values is fixed there will not be a site specific version */
15157a8a68f5SJulian Pullen 	if (is_fixed(&ctx->global_catalog))
15167a8a68f5SJulian Pullen 		return (&ctx->global_catalog);
15177a8a68f5SJulian Pullen 
15187a8a68f5SJulian Pullen 	forest_name_item = validate_ForestName(ctx);
15197a8a68f5SJulian Pullen 	if (forest_name_item == NULL)
15207a8a68f5SJulian Pullen 		return (NULL);
1521*b3700b07SGordon Ross 	forest_name = (char *)forest_name_item->value;
15227a8a68f5SJulian Pullen 
15237a8a68f5SJulian Pullen 	if (req == AD_DISC_GLOBAL)
15247a8a68f5SJulian Pullen 		validate_global = B_TRUE;
15257a8a68f5SJulian Pullen 	else {
1526*b3700b07SGordon Ross 		if (is_fixed(&ctx->site_name))
15277a8a68f5SJulian Pullen 			validate_site = B_TRUE;
15287a8a68f5SJulian Pullen 		else if (req == AD_DISC_PREFER_SITE)
15297a8a68f5SJulian Pullen 			validate_global = B_TRUE;
15307a8a68f5SJulian Pullen 	}
15317a8a68f5SJulian Pullen 
15327a8a68f5SJulian Pullen 	if (validate_global) {
15337a8a68f5SJulian Pullen 		if (!is_valid(&ctx->global_catalog) ||
15347a8a68f5SJulian Pullen 		    is_changed(&ctx->global_catalog, PARAM1,
15357a8a68f5SJulian Pullen 		    forest_name_item)) {
1536*b3700b07SGordon Ross 
15377a8a68f5SJulian Pullen 			/*
1538*b3700b07SGordon Ross 			 * See if our DC is also a GC.
1539*b3700b07SGordon Ross 			 */
1540*b3700b07SGordon Ross 			dc_item = validate_DomainController(ctx, req);
1541*b3700b07SGordon Ross 			if (dc_item != NULL) {
1542*b3700b07SGordon Ross 				ad_disc_ds_t *ds = dc_item->value;
1543*b3700b07SGordon Ross 				if ((ds->flags & DS_GC_FLAG) != 0) {
1544*b3700b07SGordon Ross 					DEBUG1STATUS(ctx,
1545*b3700b07SGordon Ross 					    "DC is also a GC for %s",
1546*b3700b07SGordon Ross 					    forest_name);
1547*b3700b07SGordon Ross 					gc = ds_dup(ds);
1548*b3700b07SGordon Ross 					if (gc != NULL) {
1549*b3700b07SGordon Ross 						gc->port = GC_PORT;
1550*b3700b07SGordon Ross 						goto update_global;
1551*b3700b07SGordon Ross 					}
1552*b3700b07SGordon Ross 				}
1553*b3700b07SGordon Ross 			}
1554*b3700b07SGordon Ross 
1555*b3700b07SGordon Ross 			/*
1556*b3700b07SGordon Ross 			 * Lookup DNS SRV RR named:
15577a8a68f5SJulian Pullen 			 * _ldap._tcp.gc._msdcs.<ForestName>
15587a8a68f5SJulian Pullen 			 */
1559*b3700b07SGordon Ross 			DEBUG1STATUS(ctx, "DNS SRV query, forest=%s",
1560*b3700b07SGordon Ross 			    forest_name);
15617a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1562*b3700b07SGordon Ross 			cgc = srv_query(&ctx->res_state,
15637a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD GC_SRV_TAIL,
1564*b3700b07SGordon Ross 			    forest_name, NULL);
15657a8a68f5SJulian Pullen 
1566*b3700b07SGordon Ross 			if (cgc == NULL) {
1567*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no DNS response)");
15687a8a68f5SJulian Pullen 				return (NULL);
1569148c5f43SAlan Wright 			}
1570*b3700b07SGordon Ross 			log_cds(ctx, cgc);
1571148c5f43SAlan Wright 
1572*b3700b07SGordon Ross 			/*
1573*b3700b07SGordon Ross 			 * Filter out unresponsive servers, and
1574*b3700b07SGordon Ross 			 * save the domain info we get back.
1575*b3700b07SGordon Ross 			 */
1576*b3700b07SGordon Ross 			gc = ldap_ping(
1577*b3700b07SGordon Ross 			    NULL,
1578*b3700b07SGordon Ross 			    cgc,
1579*b3700b07SGordon Ross 			    forest_name,
1580*b3700b07SGordon Ross 			    DS_GC_FLAG);
1581*b3700b07SGordon Ross 			srv_free(cgc);
1582*b3700b07SGordon Ross 			cgc = NULL;
15837a8a68f5SJulian Pullen 
1584*b3700b07SGordon Ross 			if (gc == NULL) {
1585*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no LDAP response)");
1586*b3700b07SGordon Ross 				return (NULL);
1587*b3700b07SGordon Ross 			}
1588*b3700b07SGordon Ross 			log_ds(ctx, gc);
1589*b3700b07SGordon Ross 
1590*b3700b07SGordon Ross 		update_global:
1591*b3700b07SGordon Ross 			update_item(&ctx->global_catalog, gc,
1592*b3700b07SGordon Ross 			    AD_STATE_AUTO, gc->ttl);
15937a8a68f5SJulian Pullen 			update_version(&ctx->global_catalog, PARAM1,
15947a8a68f5SJulian Pullen 			    forest_name_item);
15957a8a68f5SJulian Pullen 		}
15967a8a68f5SJulian Pullen 		return (&ctx->global_catalog);
15977a8a68f5SJulian Pullen 	}
15987a8a68f5SJulian Pullen 
15997a8a68f5SJulian Pullen 	if (validate_site) {
1600*b3700b07SGordon Ross 		site_name_item = &ctx->site_name;
1601*b3700b07SGordon Ross 		site_name = (char *)site_name_item->value;
1602*b3700b07SGordon Ross 
16037a8a68f5SJulian Pullen 		if (!is_valid(&ctx->site_global_catalog) ||
16047a8a68f5SJulian Pullen 		    is_changed(&ctx->site_global_catalog, PARAM1,
16057a8a68f5SJulian Pullen 		    forest_name_item) ||
16067a8a68f5SJulian Pullen 		    is_changed(&ctx->site_global_catalog, PARAM2,
16077a8a68f5SJulian Pullen 		    site_name_item)) {
16087a8a68f5SJulian Pullen 			char rr_name[DNS_MAX_NAME];
16097a8a68f5SJulian Pullen 
16107a8a68f5SJulian Pullen 			/*
1611*b3700b07SGordon Ross 			 * See if our DC is also a GC.
1612*b3700b07SGordon Ross 			 */
1613*b3700b07SGordon Ross 			dc_item = validate_DomainController(ctx, req);
1614*b3700b07SGordon Ross 			if (dc_item != NULL) {
1615*b3700b07SGordon Ross 				ad_disc_ds_t *ds = dc_item->value;
1616*b3700b07SGordon Ross 				if ((ds->flags & DS_GC_FLAG) != 0) {
1617*b3700b07SGordon Ross 					DEBUG1STATUS(ctx,
1618*b3700b07SGordon Ross 					    "DC is also a GC for %s in %s",
1619*b3700b07SGordon Ross 					    forest_name, site_name);
1620*b3700b07SGordon Ross 					gc = ds_dup(ds);
1621*b3700b07SGordon Ross 					if (gc != NULL) {
1622*b3700b07SGordon Ross 						gc->port = GC_PORT;
1623*b3700b07SGordon Ross 						goto update_site;
1624*b3700b07SGordon Ross 					}
1625*b3700b07SGordon Ross 				}
1626*b3700b07SGordon Ross 			}
1627*b3700b07SGordon Ross 
1628*b3700b07SGordon Ross 			/*
16297a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named:
16307a8a68f5SJulian Pullen 			 * _ldap._tcp.<siteName>._sites.gc.
16317a8a68f5SJulian Pullen 			 *	_msdcs.<ForestName>
16327a8a68f5SJulian Pullen 			 */
1633*b3700b07SGordon Ross 			DEBUG1STATUS(ctx, "DNS SRV query, forest=%s, site=%s",
1634*b3700b07SGordon Ross 			    forest_name, site_name);
1635*b3700b07SGordon Ross 			(void) snprintf(rr_name, sizeof (rr_name),
16367a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL,
1637*b3700b07SGordon Ross 			    site_name);
16387a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1639*b3700b07SGordon Ross 			cgc = srv_query(&ctx->res_state, rr_name,
1640*b3700b07SGordon Ross 			    forest_name, NULL);
16417a8a68f5SJulian Pullen 
1642*b3700b07SGordon Ross 			if (cgc == NULL) {
1643*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no DNS response)");
16447a8a68f5SJulian Pullen 				return (NULL);
1645148c5f43SAlan Wright 			}
1646*b3700b07SGordon Ross 			log_cds(ctx, cgc);
1647148c5f43SAlan Wright 
1648*b3700b07SGordon Ross 			/*
1649*b3700b07SGordon Ross 			 * Filter out unresponsive servers, and
1650*b3700b07SGordon Ross 			 * save the domain info we get back.
1651*b3700b07SGordon Ross 			 */
1652*b3700b07SGordon Ross 			gc = ldap_ping(
1653*b3700b07SGordon Ross 			    NULL,
1654*b3700b07SGordon Ross 			    cgc,
1655*b3700b07SGordon Ross 			    forest_name,
1656*b3700b07SGordon Ross 			    DS_GC_FLAG);
1657*b3700b07SGordon Ross 			srv_free(cgc);
1658*b3700b07SGordon Ross 			cgc = NULL;
1659148c5f43SAlan Wright 
1660*b3700b07SGordon Ross 			if (gc == NULL) {
1661*b3700b07SGordon Ross 				DEBUG1STATUS(ctx, "(no LDAP response)");
1662*b3700b07SGordon Ross 				return (NULL);
1663*b3700b07SGordon Ross 			}
1664*b3700b07SGordon Ross 			log_ds(ctx, gc);
1665*b3700b07SGordon Ross 
1666*b3700b07SGordon Ross 		update_site:
1667*b3700b07SGordon Ross 			update_item(&ctx->site_global_catalog, gc,
1668*b3700b07SGordon Ross 			    AD_STATE_AUTO, gc->ttl);
16697a8a68f5SJulian Pullen 			update_version(&ctx->site_global_catalog, PARAM1,
16707a8a68f5SJulian Pullen 			    forest_name_item);
16717a8a68f5SJulian Pullen 			update_version(&ctx->site_global_catalog, PARAM2,
16727a8a68f5SJulian Pullen 			    site_name_item);
16737a8a68f5SJulian Pullen 		}
16747a8a68f5SJulian Pullen 		return (&ctx->site_global_catalog);
16757a8a68f5SJulian Pullen 	}
16767a8a68f5SJulian Pullen 	return (NULL);
16777a8a68f5SJulian Pullen }
16787a8a68f5SJulian Pullen 
16797a8a68f5SJulian Pullen 
1680*b3700b07SGordon Ross ad_disc_ds_t *
ad_disc_get_GlobalCatalog(ad_disc_t ctx,enum ad_disc_req req,boolean_t * auto_discovered)16817a8a68f5SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req,
16827a8a68f5SJulian Pullen 			boolean_t *auto_discovered)
16837a8a68f5SJulian Pullen {
1684*b3700b07SGordon Ross 	ad_disc_ds_t *global_catalog = NULL;
16857a8a68f5SJulian Pullen 	ad_item_t *global_catalog_item;
16867a8a68f5SJulian Pullen 
16877a8a68f5SJulian Pullen 	global_catalog_item = validate_GlobalCatalog(ctx, req);
16887a8a68f5SJulian Pullen 
16897a8a68f5SJulian Pullen 	if (global_catalog_item != NULL) {
16907a8a68f5SJulian Pullen 		global_catalog = ds_dup(global_catalog_item->value);
16917a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
16927a8a68f5SJulian Pullen 			*auto_discovered =
16937a8a68f5SJulian Pullen 			    (global_catalog_item->state == AD_STATE_AUTO);
16947a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
16957a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
16967a8a68f5SJulian Pullen 
16977a8a68f5SJulian Pullen 	return (global_catalog);
16987a8a68f5SJulian Pullen }
16997a8a68f5SJulian Pullen 
17007a8a68f5SJulian Pullen 
17017a8a68f5SJulian Pullen static ad_item_t *
validate_TrustedDomains(ad_disc_t ctx)17027a8a68f5SJulian Pullen validate_TrustedDomains(ad_disc_t ctx)
17037a8a68f5SJulian Pullen {
17047a8a68f5SJulian Pullen 	LDAP *ld = NULL;
17057a8a68f5SJulian Pullen 	ad_item_t *global_catalog_item;
17067a8a68f5SJulian Pullen 	ad_item_t *forest_name_item;
17077a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *trusted_domains;
17087a8a68f5SJulian Pullen 	char *dn = NULL;
17097a8a68f5SJulian Pullen 	char *forest_name_dn;
17107a8a68f5SJulian Pullen 	int len;
17117a8a68f5SJulian Pullen 	int num_parts;
17127a8a68f5SJulian Pullen 
17137a8a68f5SJulian Pullen 	if (is_fixed(&ctx->trusted_domains))
17147a8a68f5SJulian Pullen 		return (&ctx->trusted_domains);
17157a8a68f5SJulian Pullen 
17167a8a68f5SJulian Pullen 	global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL);
17177a8a68f5SJulian Pullen 	if (global_catalog_item == NULL)
17187a8a68f5SJulian Pullen 		return (NULL);
17197a8a68f5SJulian Pullen 
17207a8a68f5SJulian Pullen 	forest_name_item = validate_ForestName(ctx);
17217a8a68f5SJulian Pullen 	if (forest_name_item == NULL)
17227a8a68f5SJulian Pullen 		return (NULL);
17237a8a68f5SJulian Pullen 
17247a8a68f5SJulian Pullen 	if (!is_valid(&ctx->trusted_domains) ||
17257a8a68f5SJulian Pullen 	    is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) ||
17267a8a68f5SJulian Pullen 	    is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) {
17277a8a68f5SJulian Pullen 
17287a8a68f5SJulian Pullen 		forest_name_dn = ldap_dns_to_dn(forest_name_item->value,
17297a8a68f5SJulian Pullen 		    &num_parts);
17307a8a68f5SJulian Pullen 		if (forest_name_dn == NULL)
17317a8a68f5SJulian Pullen 			return (NULL);
17327a8a68f5SJulian Pullen 
17337a8a68f5SJulian Pullen 		len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1;
17347a8a68f5SJulian Pullen 		dn = malloc(len);
17357a8a68f5SJulian Pullen 		if (dn == NULL)  {
17367a8a68f5SJulian Pullen 			free(forest_name_dn);
17377a8a68f5SJulian Pullen 			return (NULL);
17387a8a68f5SJulian Pullen 		}
17397a8a68f5SJulian Pullen 		(void) snprintf(dn, len, "CN=System,%s", forest_name_dn);
17407a8a68f5SJulian Pullen 		free(forest_name_dn);
17417a8a68f5SJulian Pullen 
17427a8a68f5SJulian Pullen 		trusted_domains = ldap_lookup_trusted_domains(
17437a8a68f5SJulian Pullen 		    &ld, global_catalog_item->value, dn);
17447a8a68f5SJulian Pullen 
17457a8a68f5SJulian Pullen 		if (ld != NULL)
17467a8a68f5SJulian Pullen 			(void) ldap_unbind(ld);
17477a8a68f5SJulian Pullen 		free(dn);
17487a8a68f5SJulian Pullen 
17497a8a68f5SJulian Pullen 		if (trusted_domains == NULL)
17507a8a68f5SJulian Pullen 			return (NULL);
17517a8a68f5SJulian Pullen 
17527a8a68f5SJulian Pullen 		update_item(&ctx->trusted_domains, trusted_domains,
17537a8a68f5SJulian Pullen 		    AD_STATE_AUTO, 0);
17547a8a68f5SJulian Pullen 		update_version(&ctx->trusted_domains, PARAM1,
17557a8a68f5SJulian Pullen 		    global_catalog_item);
17567a8a68f5SJulian Pullen 		update_version(&ctx->trusted_domains, PARAM2,
17577a8a68f5SJulian Pullen 		    forest_name_item);
17587a8a68f5SJulian Pullen 	}
17597a8a68f5SJulian Pullen 
17607a8a68f5SJulian Pullen 	return (&ctx->trusted_domains);
17617a8a68f5SJulian Pullen }
17627a8a68f5SJulian Pullen 
17637a8a68f5SJulian Pullen 
17647a8a68f5SJulian Pullen ad_disc_trusteddomains_t *
ad_disc_get_TrustedDomains(ad_disc_t ctx,boolean_t * auto_discovered)17657a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered)
17667a8a68f5SJulian Pullen {
17677a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *trusted_domains = NULL;
17687a8a68f5SJulian Pullen 	ad_item_t *trusted_domains_item;
17697a8a68f5SJulian Pullen 
17707a8a68f5SJulian Pullen 	trusted_domains_item = validate_TrustedDomains(ctx);
17717a8a68f5SJulian Pullen 
17727a8a68f5SJulian Pullen 	if (trusted_domains_item != NULL) {
17737a8a68f5SJulian Pullen 		trusted_domains = td_dup(trusted_domains_item->value);
17747a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
17757a8a68f5SJulian Pullen 			*auto_discovered =
17767a8a68f5SJulian Pullen 			    (trusted_domains_item->state == AD_STATE_AUTO);
17777a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
17787a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
17797a8a68f5SJulian Pullen 
17807a8a68f5SJulian Pullen 	return (trusted_domains);
17817a8a68f5SJulian Pullen }
17827a8a68f5SJulian Pullen 
17837a8a68f5SJulian Pullen 
17847a8a68f5SJulian Pullen static ad_item_t *
validate_DomainsInForest(ad_disc_t ctx)17857a8a68f5SJulian Pullen validate_DomainsInForest(ad_disc_t ctx)
17867a8a68f5SJulian Pullen {
17877a8a68f5SJulian Pullen 	ad_item_t *global_catalog_item;
17887a8a68f5SJulian Pullen 	LDAP *ld = NULL;
17897a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *domains_in_forest;
17907a8a68f5SJulian Pullen 
17917a8a68f5SJulian Pullen 	if (is_fixed(&ctx->domains_in_forest))
17927a8a68f5SJulian Pullen 		return (&ctx->domains_in_forest);
17937a8a68f5SJulian Pullen 
17947a8a68f5SJulian Pullen 	global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL);
17957a8a68f5SJulian Pullen 	if (global_catalog_item == NULL)
17967a8a68f5SJulian Pullen 		return (NULL);
17977a8a68f5SJulian Pullen 
17987a8a68f5SJulian Pullen 	if (!is_valid(&ctx->domains_in_forest) ||
17997a8a68f5SJulian Pullen 	    is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) {
18007a8a68f5SJulian Pullen 
18017a8a68f5SJulian Pullen 		domains_in_forest = ldap_lookup_domains_in_forest(
18027a8a68f5SJulian Pullen 		    &ld, global_catalog_item->value);
18037a8a68f5SJulian Pullen 
18047a8a68f5SJulian Pullen 		if (ld != NULL)
18057a8a68f5SJulian Pullen 			(void) ldap_unbind(ld);
18067a8a68f5SJulian Pullen 
18077a8a68f5SJulian Pullen 		if (domains_in_forest == NULL)
18087a8a68f5SJulian Pullen 			return (NULL);
18097a8a68f5SJulian Pullen 
18107a8a68f5SJulian Pullen 		update_item(&ctx->domains_in_forest, domains_in_forest,
18117a8a68f5SJulian Pullen 		    AD_STATE_AUTO, 0);
18127a8a68f5SJulian Pullen 		update_version(&ctx->domains_in_forest, PARAM1,
18137a8a68f5SJulian Pullen 		    global_catalog_item);
18147a8a68f5SJulian Pullen 	}
18157a8a68f5SJulian Pullen 	return (&ctx->domains_in_forest);
18167a8a68f5SJulian Pullen }
18177a8a68f5SJulian Pullen 
18187a8a68f5SJulian Pullen 
18197a8a68f5SJulian Pullen ad_disc_domainsinforest_t *
ad_disc_get_DomainsInForest(ad_disc_t ctx,boolean_t * auto_discovered)18207a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered)
18217a8a68f5SJulian Pullen {
18227a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *domains_in_forest = NULL;
18237a8a68f5SJulian Pullen 	ad_item_t *domains_in_forest_item;
18247a8a68f5SJulian Pullen 
18257a8a68f5SJulian Pullen 	domains_in_forest_item = validate_DomainsInForest(ctx);
18267a8a68f5SJulian Pullen 
18277a8a68f5SJulian Pullen 	if (domains_in_forest_item != NULL) {
18287a8a68f5SJulian Pullen 		domains_in_forest = df_dup(domains_in_forest_item->value);
18297a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
18307a8a68f5SJulian Pullen 			*auto_discovered =
18317a8a68f5SJulian Pullen 			    (domains_in_forest_item->state == AD_STATE_AUTO);
18327a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
18337a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
18347a8a68f5SJulian Pullen 
18357a8a68f5SJulian Pullen 	return (domains_in_forest);
18367a8a68f5SJulian Pullen }
18377a8a68f5SJulian Pullen 
1838*b3700b07SGordon Ross static ad_item_t *
validate_PreferredDC(ad_disc_t ctx)1839*b3700b07SGordon Ross validate_PreferredDC(ad_disc_t ctx)
1840*b3700b07SGordon Ross {
1841*b3700b07SGordon Ross 	if (is_valid(&ctx->preferred_dc))
1842*b3700b07SGordon Ross 		return (&ctx->preferred_dc);
1843*b3700b07SGordon Ross 
1844*b3700b07SGordon Ross 	return (NULL);
1845*b3700b07SGordon Ross }
1846*b3700b07SGordon Ross 
1847*b3700b07SGordon Ross ad_disc_ds_t *
ad_disc_get_PreferredDC(ad_disc_t ctx,boolean_t * auto_discovered)1848*b3700b07SGordon Ross ad_disc_get_PreferredDC(ad_disc_t ctx, boolean_t *auto_discovered)
1849*b3700b07SGordon Ross {
1850*b3700b07SGordon Ross 	ad_disc_ds_t *preferred_dc = NULL;
1851*b3700b07SGordon Ross 	ad_item_t *preferred_dc_item;
1852*b3700b07SGordon Ross 
1853*b3700b07SGordon Ross 	preferred_dc_item = validate_PreferredDC(ctx);
1854*b3700b07SGordon Ross 
1855*b3700b07SGordon Ross 	if (preferred_dc_item != NULL) {
1856*b3700b07SGordon Ross 		preferred_dc = ds_dup(preferred_dc_item->value);
1857*b3700b07SGordon Ross 		if (auto_discovered != NULL)
1858*b3700b07SGordon Ross 			*auto_discovered =
1859*b3700b07SGordon Ross 			    (preferred_dc_item->state == AD_STATE_AUTO);
1860*b3700b07SGordon Ross 	} else if (auto_discovered != NULL)
1861*b3700b07SGordon Ross 		*auto_discovered = B_FALSE;
1862*b3700b07SGordon Ross 
1863*b3700b07SGordon Ross 	return (preferred_dc);
1864*b3700b07SGordon Ross }
18657a8a68f5SJulian Pullen 
18667a8a68f5SJulian Pullen 
18677a8a68f5SJulian Pullen 
18687a8a68f5SJulian Pullen int
ad_disc_set_DomainName(ad_disc_t ctx,const char * domainName)18697a8a68f5SJulian Pullen ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName)
18707a8a68f5SJulian Pullen {
18717a8a68f5SJulian Pullen 	char *domain_name = NULL;
18727a8a68f5SJulian Pullen 	if (domainName != NULL) {
18737a8a68f5SJulian Pullen 		domain_name = strdup(domainName);
18747a8a68f5SJulian Pullen 		if (domain_name == NULL)
18757a8a68f5SJulian Pullen 			return (-1);
18767a8a68f5SJulian Pullen 		update_item(&ctx->domain_name, domain_name,
18777a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
18787a8a68f5SJulian Pullen 	} else if (ctx->domain_name.state == AD_STATE_FIXED)
18797a8a68f5SJulian Pullen 		ctx->domain_name.state = AD_STATE_INVALID;
18807a8a68f5SJulian Pullen 	return (0);
18817a8a68f5SJulian Pullen }
18827a8a68f5SJulian Pullen 
1883*b3700b07SGordon Ross int
ad_disc_set_DomainGUID(ad_disc_t ctx,uchar_t * u)1884*b3700b07SGordon Ross ad_disc_set_DomainGUID(ad_disc_t ctx, uchar_t *u)
1885*b3700b07SGordon Ross {
1886*b3700b07SGordon Ross 	char *domain_guid = NULL;
1887*b3700b07SGordon Ross 	if (u != NULL) {
1888*b3700b07SGordon Ross 		domain_guid = uuid_dup(u);
1889*b3700b07SGordon Ross 		if (domain_guid == NULL)
1890*b3700b07SGordon Ross 			return (-1);
1891*b3700b07SGordon Ross 		update_item(&ctx->domain_guid, domain_guid,
1892*b3700b07SGordon Ross 		    AD_STATE_FIXED, 0);
1893*b3700b07SGordon Ross 	} else if (ctx->domain_guid.state == AD_STATE_FIXED)
1894*b3700b07SGordon Ross 		ctx->domain_guid.state = AD_STATE_INVALID;
1895*b3700b07SGordon Ross 	return (0);
1896*b3700b07SGordon Ross }
1897*b3700b07SGordon Ross 
1898*b3700b07SGordon Ross void
auto_set_DomainGUID(ad_disc_t ctx,uchar_t * u)1899*b3700b07SGordon Ross auto_set_DomainGUID(ad_disc_t ctx, uchar_t *u)
1900*b3700b07SGordon Ross {
1901*b3700b07SGordon Ross 	char *domain_guid = NULL;
1902*b3700b07SGordon Ross 
1903*b3700b07SGordon Ross 	if (is_fixed(&ctx->domain_guid))
1904*b3700b07SGordon Ross 		return;
1905*b3700b07SGordon Ross 
1906*b3700b07SGordon Ross 	domain_guid = uuid_dup(u);
1907*b3700b07SGordon Ross 	if (domain_guid == NULL)
1908*b3700b07SGordon Ross 		return;
1909*b3700b07SGordon Ross 	update_item(&ctx->domain_guid, domain_guid, AD_STATE_AUTO, 0);
1910*b3700b07SGordon Ross }
19117a8a68f5SJulian Pullen 
19127a8a68f5SJulian Pullen int
ad_disc_set_DomainController(ad_disc_t ctx,const ad_disc_ds_t * domainController)19137a8a68f5SJulian Pullen ad_disc_set_DomainController(ad_disc_t ctx,
1914*b3700b07SGordon Ross 				const ad_disc_ds_t *domainController)
19157a8a68f5SJulian Pullen {
1916*b3700b07SGordon Ross 	ad_disc_ds_t *domain_controller = NULL;
19177a8a68f5SJulian Pullen 	if (domainController != NULL) {
19187a8a68f5SJulian Pullen 		domain_controller = ds_dup(domainController);
19197a8a68f5SJulian Pullen 		if (domain_controller == NULL)
19207a8a68f5SJulian Pullen 			return (-1);
19217a8a68f5SJulian Pullen 		update_item(&ctx->domain_controller, domain_controller,
19227a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
19237a8a68f5SJulian Pullen 	} else if (ctx->domain_controller.state == AD_STATE_FIXED)
19247a8a68f5SJulian Pullen 		ctx->domain_controller.state = AD_STATE_INVALID;
19257a8a68f5SJulian Pullen 	return (0);
19267a8a68f5SJulian Pullen }
19277a8a68f5SJulian Pullen 
19287a8a68f5SJulian Pullen int
ad_disc_set_SiteName(ad_disc_t ctx,const char * siteName)19297a8a68f5SJulian Pullen ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName)
19307a8a68f5SJulian Pullen {
19317a8a68f5SJulian Pullen 	char *site_name = NULL;
19327a8a68f5SJulian Pullen 	if (siteName != NULL) {
19337a8a68f5SJulian Pullen 		site_name = strdup(siteName);
19347a8a68f5SJulian Pullen 		if (site_name == NULL)
19357a8a68f5SJulian Pullen 			return (-1);
19367a8a68f5SJulian Pullen 		update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0);
19377a8a68f5SJulian Pullen 	} else if (ctx->site_name.state == AD_STATE_FIXED)
19387a8a68f5SJulian Pullen 		ctx->site_name.state = AD_STATE_INVALID;
19397a8a68f5SJulian Pullen 	return (0);
19407a8a68f5SJulian Pullen }
19417a8a68f5SJulian Pullen 
1942*b3700b07SGordon Ross void
auto_set_SiteName(ad_disc_t ctx,char * siteName)1943*b3700b07SGordon Ross auto_set_SiteName(ad_disc_t ctx, char *siteName)
1944*b3700b07SGordon Ross {
1945*b3700b07SGordon Ross 	char *site_name = NULL;
1946*b3700b07SGordon Ross 
1947*b3700b07SGordon Ross 	if (is_fixed(&ctx->site_name))
1948*b3700b07SGordon Ross 		return;
1949*b3700b07SGordon Ross 
1950*b3700b07SGordon Ross 	site_name = strdup(siteName);
1951*b3700b07SGordon Ross 	if (site_name == NULL)
1952*b3700b07SGordon Ross 		return;
1953*b3700b07SGordon Ross 	update_item(&ctx->site_name, site_name, AD_STATE_AUTO, 0);
1954*b3700b07SGordon Ross }
1955*b3700b07SGordon Ross 
19567a8a68f5SJulian Pullen int
ad_disc_set_ForestName(ad_disc_t ctx,const char * forestName)19577a8a68f5SJulian Pullen ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName)
19587a8a68f5SJulian Pullen {
19597a8a68f5SJulian Pullen 	char *forest_name = NULL;
19607a8a68f5SJulian Pullen 	if (forestName != NULL) {
19617a8a68f5SJulian Pullen 		forest_name = strdup(forestName);
19627a8a68f5SJulian Pullen 		if (forest_name == NULL)
19637a8a68f5SJulian Pullen 			return (-1);
19647a8a68f5SJulian Pullen 		update_item(&ctx->forest_name, forest_name,
19657a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
19667a8a68f5SJulian Pullen 	} else if (ctx->forest_name.state == AD_STATE_FIXED)
19677a8a68f5SJulian Pullen 		ctx->forest_name.state = AD_STATE_INVALID;
19687a8a68f5SJulian Pullen 	return (0);
19697a8a68f5SJulian Pullen }
19707a8a68f5SJulian Pullen 
1971*b3700b07SGordon Ross void
auto_set_ForestName(ad_disc_t ctx,char * forestName)1972*b3700b07SGordon Ross auto_set_ForestName(ad_disc_t ctx, char *forestName)
1973*b3700b07SGordon Ross {
1974*b3700b07SGordon Ross 	char *forest_name = NULL;
1975*b3700b07SGordon Ross 
1976*b3700b07SGordon Ross 	if (is_fixed(&ctx->forest_name))
1977*b3700b07SGordon Ross 		return;
1978*b3700b07SGordon Ross 
1979*b3700b07SGordon Ross 	forest_name = strdup(forestName);
1980*b3700b07SGordon Ross 	if (forest_name == NULL)
1981*b3700b07SGordon Ross 		return;
1982*b3700b07SGordon Ross 	update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0);
1983*b3700b07SGordon Ross }
1984*b3700b07SGordon Ross 
19857a8a68f5SJulian Pullen int
ad_disc_set_GlobalCatalog(ad_disc_t ctx,const ad_disc_ds_t * globalCatalog)19867a8a68f5SJulian Pullen ad_disc_set_GlobalCatalog(ad_disc_t ctx,
1987*b3700b07SGordon Ross     const ad_disc_ds_t *globalCatalog)
19887a8a68f5SJulian Pullen {
1989*b3700b07SGordon Ross 	ad_disc_ds_t *global_catalog = NULL;
19907a8a68f5SJulian Pullen 	if (globalCatalog != NULL) {
19917a8a68f5SJulian Pullen 		global_catalog = ds_dup(globalCatalog);
19927a8a68f5SJulian Pullen 		if (global_catalog == NULL)
19937a8a68f5SJulian Pullen 			return (-1);
19947a8a68f5SJulian Pullen 		update_item(&ctx->global_catalog, global_catalog,
19957a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
19967a8a68f5SJulian Pullen 	} else if (ctx->global_catalog.state == AD_STATE_FIXED)
19977a8a68f5SJulian Pullen 		ctx->global_catalog.state = AD_STATE_INVALID;
19987a8a68f5SJulian Pullen 	return (0);
19997a8a68f5SJulian Pullen }
20007a8a68f5SJulian Pullen 
2001*b3700b07SGordon Ross int
ad_disc_set_PreferredDC(ad_disc_t ctx,const ad_disc_ds_t * pref_dc)2002*b3700b07SGordon Ross ad_disc_set_PreferredDC(ad_disc_t ctx, const ad_disc_ds_t *pref_dc)
2003*b3700b07SGordon Ross {
2004*b3700b07SGordon Ross 	ad_disc_ds_t *new_pref_dc = NULL;
2005*b3700b07SGordon Ross 	if (pref_dc != NULL) {
2006*b3700b07SGordon Ross 		new_pref_dc = ds_dup(pref_dc);
2007*b3700b07SGordon Ross 		if (new_pref_dc == NULL)
2008*b3700b07SGordon Ross 			return (-1);
2009*b3700b07SGordon Ross 		update_item(&ctx->preferred_dc, new_pref_dc,
2010*b3700b07SGordon Ross 		    AD_STATE_FIXED, 0);
2011*b3700b07SGordon Ross 	} else if (ctx->preferred_dc.state == AD_STATE_FIXED)
2012*b3700b07SGordon Ross 		ctx->preferred_dc.state = AD_STATE_INVALID;
2013*b3700b07SGordon Ross 	return (0);
2014*b3700b07SGordon Ross }
2015*b3700b07SGordon Ross 
2016*b3700b07SGordon Ross void
ad_disc_set_StatusFP(ad_disc_t ctx,struct __FILE_TAG * fp)2017*b3700b07SGordon Ross ad_disc_set_StatusFP(ad_disc_t ctx, struct __FILE_TAG *fp)
2018*b3700b07SGordon Ross {
2019*b3700b07SGordon Ross 	ctx->status_fp = fp;
2020*b3700b07SGordon Ross }
2021*b3700b07SGordon Ross 
20227a8a68f5SJulian Pullen 
20237a8a68f5SJulian Pullen int
ad_disc_unset(ad_disc_t ctx)20247a8a68f5SJulian Pullen ad_disc_unset(ad_disc_t ctx)
20257a8a68f5SJulian Pullen {
20267a8a68f5SJulian Pullen 	if (ctx->domain_name.state == AD_STATE_FIXED)
20277a8a68f5SJulian Pullen 		ctx->domain_name.state =  AD_STATE_INVALID;
20287a8a68f5SJulian Pullen 
20297a8a68f5SJulian Pullen 	if (ctx->domain_controller.state == AD_STATE_FIXED)
20307a8a68f5SJulian Pullen 		ctx->domain_controller.state =  AD_STATE_INVALID;
20317a8a68f5SJulian Pullen 
2032*b3700b07SGordon Ross 	if (ctx->preferred_dc.state == AD_STATE_FIXED)
2033*b3700b07SGordon Ross 		ctx->preferred_dc.state =  AD_STATE_INVALID;
2034*b3700b07SGordon Ross 
20357a8a68f5SJulian Pullen 	if (ctx->site_name.state == AD_STATE_FIXED)
20367a8a68f5SJulian Pullen 		ctx->site_name.state =  AD_STATE_INVALID;
20377a8a68f5SJulian Pullen 
20387a8a68f5SJulian Pullen 	if (ctx->forest_name.state == AD_STATE_FIXED)
20397a8a68f5SJulian Pullen 		ctx->forest_name.state =  AD_STATE_INVALID;
20407a8a68f5SJulian Pullen 
20417a8a68f5SJulian Pullen 	if (ctx->global_catalog.state == AD_STATE_FIXED)
20427a8a68f5SJulian Pullen 		ctx->global_catalog.state =  AD_STATE_INVALID;
20437a8a68f5SJulian Pullen 
20447a8a68f5SJulian Pullen 	return (0);
20457a8a68f5SJulian Pullen }
20467a8a68f5SJulian Pullen 
20477a8a68f5SJulian Pullen /*
20487a8a68f5SJulian Pullen  * ad_disc_get_TTL
20497a8a68f5SJulian Pullen  *
20507a8a68f5SJulian Pullen  * This routines the time to live for AD
20517a8a68f5SJulian Pullen  * auto discovered items.
20527a8a68f5SJulian Pullen  *
20537a8a68f5SJulian Pullen  *	Returns:
20547a8a68f5SJulian Pullen  *		-1 if there are no TTL items
20557a8a68f5SJulian Pullen  *		0  if there are expired items
20567a8a68f5SJulian Pullen  *		else the number of seconds
20577a8a68f5SJulian Pullen  *
20587a8a68f5SJulian Pullen  * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it
20597a8a68f5SJulian Pullen  * is positive -- min() greater than zero.
20607a8a68f5SJulian Pullen  */
20617a8a68f5SJulian Pullen #define	MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \
20627a8a68f5SJulian Pullen 		(-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x))))
20637a8a68f5SJulian Pullen int
ad_disc_get_TTL(ad_disc_t ctx)20647a8a68f5SJulian Pullen ad_disc_get_TTL(ad_disc_t ctx)
20657a8a68f5SJulian Pullen {
2066c5866007SKeyur Desai 	time_t expires;
20677a8a68f5SJulian Pullen 	int ttl;
20687a8a68f5SJulian Pullen 
2069c5866007SKeyur Desai 	expires = MIN_GT_ZERO(ctx->domain_controller.expires,
2070c5866007SKeyur Desai 	    ctx->global_catalog.expires);
2071c5866007SKeyur Desai 	expires = MIN_GT_ZERO(expires, ctx->site_domain_controller.expires);
2072c5866007SKeyur Desai 	expires = MIN_GT_ZERO(expires, ctx->site_global_catalog.expires);
20737a8a68f5SJulian Pullen 
2074c5866007SKeyur Desai 	if (expires == -1) {
20757a8a68f5SJulian Pullen 		return (-1);
2076c5866007SKeyur Desai 	}
2077c5866007SKeyur Desai 
2078c5866007SKeyur Desai 	if (ctx->expires_not_before != 0 &&
2079c5866007SKeyur Desai 	    expires < ctx->expires_not_before) {
2080c5866007SKeyur Desai 		expires = ctx->expires_not_before;
2081c5866007SKeyur Desai 	}
2082c5866007SKeyur Desai 
2083c5866007SKeyur Desai 	if (ctx->expires_not_after != 0 &&
2084c5866007SKeyur Desai 	    expires > ctx->expires_not_after) {
2085c5866007SKeyur Desai 		expires = ctx->expires_not_after;
2086c5866007SKeyur Desai 	}
2087c5866007SKeyur Desai 
2088c5866007SKeyur Desai 	ttl = expires - time(NULL);
2089c5866007SKeyur Desai 
2090c5866007SKeyur Desai 	if (ttl < 0) {
20917a8a68f5SJulian Pullen 		return (0);
2092c5866007SKeyur Desai 	}
20937a8a68f5SJulian Pullen 	return (ttl);
20947a8a68f5SJulian Pullen }
20957a8a68f5SJulian Pullen 
20967a8a68f5SJulian Pullen boolean_t
ad_disc_SubnetChanged(ad_disc_t ctx)20977a8a68f5SJulian Pullen ad_disc_SubnetChanged(ad_disc_t ctx)
20987a8a68f5SJulian Pullen {
20997a8a68f5SJulian Pullen 	ad_subnet_t *subnets;
21007a8a68f5SJulian Pullen 
21017a8a68f5SJulian Pullen 	if (ctx->subnets_changed || ctx->subnets == NULL)
21027a8a68f5SJulian Pullen 		return (B_TRUE);
21037a8a68f5SJulian Pullen 
21047a8a68f5SJulian Pullen 	if ((subnets = find_subnets()) != NULL) {
21057a8a68f5SJulian Pullen 		if (cmpsubnets(subnets, ctx->subnets) != 0)
21067a8a68f5SJulian Pullen 			ctx->subnets_changed = B_TRUE;
21077a8a68f5SJulian Pullen 		free(subnets);
21087a8a68f5SJulian Pullen 	}
21097a8a68f5SJulian Pullen 
21107a8a68f5SJulian Pullen 	return (ctx->subnets_changed);
21117a8a68f5SJulian Pullen }
2112