xref: /titanic_50/usr/src/lib/libadutils/common/addisc.c (revision 7a8a68f5e3efbaec1a375c2d50bd20b566631755)
1*7a8a68f5SJulian Pullen /*
2*7a8a68f5SJulian Pullen  * CDDL HEADER START
3*7a8a68f5SJulian Pullen  *
4*7a8a68f5SJulian Pullen  * The contents of this file are subject to the terms of the
5*7a8a68f5SJulian Pullen  * Common Development and Distribution License (the "License").
6*7a8a68f5SJulian Pullen  * You may not use this file except in compliance with the License.
7*7a8a68f5SJulian Pullen  *
8*7a8a68f5SJulian Pullen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7a8a68f5SJulian Pullen  * or http://www.opensolaris.org/os/licensing.
10*7a8a68f5SJulian Pullen  * See the License for the specific language governing permissions
11*7a8a68f5SJulian Pullen  * and limitations under the License.
12*7a8a68f5SJulian Pullen  *
13*7a8a68f5SJulian Pullen  * When distributing Covered Code, include this CDDL HEADER in each
14*7a8a68f5SJulian Pullen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7a8a68f5SJulian Pullen  * If applicable, add the following below this CDDL HEADER, with the
16*7a8a68f5SJulian Pullen  * fields enclosed by brackets "[]" replaced with your own identifying
17*7a8a68f5SJulian Pullen  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7a8a68f5SJulian Pullen  *
19*7a8a68f5SJulian Pullen  * CDDL HEADER END
20*7a8a68f5SJulian Pullen  */
21*7a8a68f5SJulian Pullen 
22*7a8a68f5SJulian Pullen /*
23*7a8a68f5SJulian Pullen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*7a8a68f5SJulian Pullen  * Use is subject to license terms.
25*7a8a68f5SJulian Pullen  */
26*7a8a68f5SJulian Pullen 
27*7a8a68f5SJulian Pullen /*
28*7a8a68f5SJulian Pullen  * Active Directory Auto-Discovery.
29*7a8a68f5SJulian Pullen  *
30*7a8a68f5SJulian Pullen  * This [project private] API allows the caller to provide whatever
31*7a8a68f5SJulian Pullen  * details it knows a priori (i.e., provided via configuration so as to
32*7a8a68f5SJulian Pullen  * override auto-discovery) and in any order.  Then the caller can ask
33*7a8a68f5SJulian Pullen  * for any of the auto-discoverable parameters in any order.
34*7a8a68f5SJulian Pullen  *
35*7a8a68f5SJulian Pullen  * But there is an actual order in which discovery must be done.  Given
36*7a8a68f5SJulian Pullen  * the discovery mechanism implemented here, that order is:
37*7a8a68f5SJulian Pullen  *
38*7a8a68f5SJulian Pullen  *  - the domain name joined must be discovered first
39*7a8a68f5SJulian Pullen  *  - then the domain controllers
40*7a8a68f5SJulian Pullen  *  - then the forest name and site name
41*7a8a68f5SJulian Pullen  *  - then the global catalog servers, and site-specific domain
42*7a8a68f5SJulian Pullen  *    controllers and global catalog servers.
43*7a8a68f5SJulian Pullen  *
44*7a8a68f5SJulian Pullen  * The API does not require it be called in the same order because there
45*7a8a68f5SJulian Pullen  * may be other discovery mechanisms in the future, and exposing
46*7a8a68f5SJulian Pullen  * ordering requirements of the current mechanism now can create trouble
47*7a8a68f5SJulian Pullen  * down the line.  Also, this makes the API easier to use now, which
48*7a8a68f5SJulian Pullen  * means less work to do some day when we make this a public API.
49*7a8a68f5SJulian Pullen  *
50*7a8a68f5SJulian Pullen  * Domain discovery is done by res_nsearch() of the DNS SRV RR name for
51*7a8a68f5SJulian Pullen  * domain controllers.  As long as the joined domain appears in the DNS
52*7a8a68f5SJulian Pullen  * resolver's search list then we'll find it.
53*7a8a68f5SJulian Pullen  *
54*7a8a68f5SJulian Pullen  * Domain controller discovery is a matter of formatting the DNS SRV RR
55*7a8a68f5SJulian Pullen  * FQDN for domain controllers and doing a lookup for them.  Knowledge
56*7a8a68f5SJulian Pullen  * of the domain name is not fundamentally required, but we separate the
57*7a8a68f5SJulian Pullen  * two processes, which in practice can lead to one more DNS lookup than
58*7a8a68f5SJulian Pullen  * is strictly required.
59*7a8a68f5SJulian Pullen  *
60*7a8a68f5SJulian Pullen  * Forest and site name discovery require an LDAP search of the AD
61*7a8a68f5SJulian Pullen  * "configuration partition" at a domain controller for the joined
62*7a8a68f5SJulian Pullen  * domain.  Forest and site name discovery depend on knowing the joined
63*7a8a68f5SJulian Pullen  * domain name and domain controllers for that domain.
64*7a8a68f5SJulian Pullen  *
65*7a8a68f5SJulian Pullen  * Global catalog server discovery requires knowledge of the forest
66*7a8a68f5SJulian Pullen  * name in order to format the DNS SRV RR FQDN to lookup.  Site-specific
67*7a8a68f5SJulian Pullen  * domain controller discovery depends on knowing the site name (and,
68*7a8a68f5SJulian Pullen  * therefore, joined domain, ...).  Site-specific global catalog server
69*7a8a68f5SJulian Pullen  * discovery depends on knowledge of the forest and site names, which
70*7a8a68f5SJulian Pullen  * depend on...
71*7a8a68f5SJulian Pullen  *
72*7a8a68f5SJulian Pullen  * All the work of discovering particular items is done by functions
73*7a8a68f5SJulian Pullen  * named validate_<item>().  Each such function calls validate_<item>()
74*7a8a68f5SJulian Pullen  * for any items that it depends on.
75*7a8a68f5SJulian Pullen  *
76*7a8a68f5SJulian Pullen  * This API is not thread-safe.
77*7a8a68f5SJulian Pullen  */
78*7a8a68f5SJulian Pullen 
79*7a8a68f5SJulian Pullen 
80*7a8a68f5SJulian Pullen #include <stdio.h>
81*7a8a68f5SJulian Pullen #include <string.h>
82*7a8a68f5SJulian Pullen #include <strings.h>
83*7a8a68f5SJulian Pullen #include <unistd.h>
84*7a8a68f5SJulian Pullen #include <assert.h>
85*7a8a68f5SJulian Pullen #include <stdlib.h>
86*7a8a68f5SJulian Pullen #include <net/if.h>
87*7a8a68f5SJulian Pullen #include <net/if.h>
88*7a8a68f5SJulian Pullen #include <sys/types.h>
89*7a8a68f5SJulian Pullen #include <sys/socket.h>
90*7a8a68f5SJulian Pullen #include <sys/sockio.h>
91*7a8a68f5SJulian Pullen #include <netinet/in.h>
92*7a8a68f5SJulian Pullen #include <netinet/in.h>
93*7a8a68f5SJulian Pullen #include <arpa/inet.h>
94*7a8a68f5SJulian Pullen #include <arpa/nameser.h>
95*7a8a68f5SJulian Pullen #include <resolv.h>
96*7a8a68f5SJulian Pullen #include <netdb.h>
97*7a8a68f5SJulian Pullen #include <ctype.h>
98*7a8a68f5SJulian Pullen #include <errno.h>
99*7a8a68f5SJulian Pullen #include <ldap.h>
100*7a8a68f5SJulian Pullen #include <sasl/sasl.h>
101*7a8a68f5SJulian Pullen #include <sys/u8_textprep.h>
102*7a8a68f5SJulian Pullen #include <syslog.h>
103*7a8a68f5SJulian Pullen #include "adutils_impl.h"
104*7a8a68f5SJulian Pullen #include "addisc.h"
105*7a8a68f5SJulian Pullen 
106*7a8a68f5SJulian Pullen 
107*7a8a68f5SJulian Pullen enum ad_item_state {
108*7a8a68f5SJulian Pullen 		AD_STATE_INVALID = 0,	/* The value is not valid */
109*7a8a68f5SJulian Pullen 		AD_STATE_FIXED,		/* The value was fixed by caller */
110*7a8a68f5SJulian Pullen 		AD_STATE_AUTO		/* The value is auto discovered */
111*7a8a68f5SJulian Pullen 		};
112*7a8a68f5SJulian Pullen 
113*7a8a68f5SJulian Pullen enum ad_data_type {
114*7a8a68f5SJulian Pullen 		AD_STRING = 123,
115*7a8a68f5SJulian Pullen 		AD_DIRECTORY,
116*7a8a68f5SJulian Pullen 		AD_DOMAINS_IN_FOREST,
117*7a8a68f5SJulian Pullen 		AD_TRUSTED_DOMAINS
118*7a8a68f5SJulian Pullen 		};
119*7a8a68f5SJulian Pullen 
120*7a8a68f5SJulian Pullen 
121*7a8a68f5SJulian Pullen typedef struct ad_subnet {
122*7a8a68f5SJulian Pullen 	char subnet[24];
123*7a8a68f5SJulian Pullen } ad_subnet_t;
124*7a8a68f5SJulian Pullen 
125*7a8a68f5SJulian Pullen 
126*7a8a68f5SJulian Pullen typedef struct ad_item {
127*7a8a68f5SJulian Pullen 	enum ad_item_state	state;
128*7a8a68f5SJulian Pullen 	enum ad_data_type	type;
129*7a8a68f5SJulian Pullen 	void 			*value;
130*7a8a68f5SJulian Pullen 	time_t 			ttl;
131*7a8a68f5SJulian Pullen 	unsigned int 		version;	/* Version is only changed */
132*7a8a68f5SJulian Pullen 						/* if the value changes */
133*7a8a68f5SJulian Pullen #define	PARAM1		0
134*7a8a68f5SJulian Pullen #define	PARAM2		1
135*7a8a68f5SJulian Pullen 	int 		param_version[2];
136*7a8a68f5SJulian Pullen 					/* These holds the version of */
137*7a8a68f5SJulian Pullen 					/* dependents so that a dependent */
138*7a8a68f5SJulian Pullen 					/* change can be detected */
139*7a8a68f5SJulian Pullen } ad_item_t;
140*7a8a68f5SJulian Pullen 
141*7a8a68f5SJulian Pullen typedef struct ad_disc {
142*7a8a68f5SJulian Pullen 	struct __res_state res_state;
143*7a8a68f5SJulian Pullen 	int		res_ninitted;
144*7a8a68f5SJulian Pullen 	ad_subnet_t	*subnets;
145*7a8a68f5SJulian Pullen 	boolean_t	subnets_changed;
146*7a8a68f5SJulian Pullen 	time_t		subnets_last_check;
147*7a8a68f5SJulian Pullen 	ad_item_t	domain_name;		/* DNS hostname string */
148*7a8a68f5SJulian Pullen 	ad_item_t	domain_controller;	/* Directory hostname and */
149*7a8a68f5SJulian Pullen 						/* port array */
150*7a8a68f5SJulian Pullen 	ad_item_t	site_name;		/* String */
151*7a8a68f5SJulian Pullen 	ad_item_t	forest_name;		/* DNS forestname string */
152*7a8a68f5SJulian Pullen 	ad_item_t	global_catalog;		/* Directory hostname and */
153*7a8a68f5SJulian Pullen 						/* port array */
154*7a8a68f5SJulian Pullen 	ad_item_t	domains_in_forest;	/* DNS domainname and SID */
155*7a8a68f5SJulian Pullen 						/* array */
156*7a8a68f5SJulian Pullen 	ad_item_t	trusted_domains;	/* DNS domainname and trust */
157*7a8a68f5SJulian Pullen 						/* direction array */
158*7a8a68f5SJulian Pullen 	/* Site specfic versions */
159*7a8a68f5SJulian Pullen 	ad_item_t	site_domain_controller;	/* Directory hostname and */
160*7a8a68f5SJulian Pullen 						/* port array */
161*7a8a68f5SJulian Pullen 	ad_item_t	site_global_catalog;	/* Directory hostname and */
162*7a8a68f5SJulian Pullen 						/* port array */
163*7a8a68f5SJulian Pullen } ad_disc;
164*7a8a68f5SJulian Pullen 
165*7a8a68f5SJulian Pullen 
166*7a8a68f5SJulian Pullen #define	DNS_MAX_NAME	NS_MAXDNAME
167*7a8a68f5SJulian Pullen 
168*7a8a68f5SJulian Pullen 
169*7a8a68f5SJulian Pullen /* SRV RR names for various queries */
170*7a8a68f5SJulian Pullen #define	LDAP_SRV_HEAD		"_ldap._tcp."
171*7a8a68f5SJulian Pullen #define	SITE_SRV_MIDDLE		"%s._sites."
172*7a8a68f5SJulian Pullen #define	GC_SRV_TAIL		"gc._msdcs"
173*7a8a68f5SJulian Pullen #define	DC_SRV_TAIL		"dc._msdcs"
174*7a8a68f5SJulian Pullen #define	ALL_GC_SRV_TAIL		"_gc._tcp"
175*7a8a68f5SJulian Pullen #define	PDC_SRV			 "_ldap._tcp.pdc._msdcs.%s"
176*7a8a68f5SJulian Pullen 
177*7a8a68f5SJulian Pullen /* A RR name for all GCs -- last resort this works */
178*7a8a68f5SJulian Pullen #define	GC_ALL_A_NAME_FSTR "gc._msdcs.%s."
179*7a8a68f5SJulian Pullen 
180*7a8a68f5SJulian Pullen 
181*7a8a68f5SJulian Pullen /*
182*7a8a68f5SJulian Pullen  * We try res_ninit() whenever we don't have one.  res_ninit() fails if
183*7a8a68f5SJulian Pullen  * idmapd is running before the network is up!
184*7a8a68f5SJulian Pullen  */
185*7a8a68f5SJulian Pullen #define	DO_RES_NINIT(ctx)   if (!(ctx)->res_ninitted) \
186*7a8a68f5SJulian Pullen 		(ctx)->res_ninitted = (res_ninit(&ctx->res_state) != -1)
187*7a8a68f5SJulian Pullen 
188*7a8a68f5SJulian Pullen #define	is_fixed(item)					\
189*7a8a68f5SJulian Pullen 	((item)->state == AD_STATE_FIXED)
190*7a8a68f5SJulian Pullen 
191*7a8a68f5SJulian Pullen #define	is_changed(item, num, param) 			\
192*7a8a68f5SJulian Pullen 	((item)->param_version[num] != (param)->version)
193*7a8a68f5SJulian Pullen 
194*7a8a68f5SJulian Pullen /*LINTLIBRARY*/
195*7a8a68f5SJulian Pullen 
196*7a8a68f5SJulian Pullen /*
197*7a8a68f5SJulian Pullen  * Function definitions
198*7a8a68f5SJulian Pullen  */
199*7a8a68f5SJulian Pullen static ad_item_t *
200*7a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx);
201*7a8a68f5SJulian Pullen 
202*7a8a68f5SJulian Pullen 
203*7a8a68f5SJulian Pullen 
204*7a8a68f5SJulian Pullen static void
205*7a8a68f5SJulian Pullen update_version(ad_item_t *item, int  num, ad_item_t *param)
206*7a8a68f5SJulian Pullen {
207*7a8a68f5SJulian Pullen 	item->param_version[num] = param->version;
208*7a8a68f5SJulian Pullen }
209*7a8a68f5SJulian Pullen 
210*7a8a68f5SJulian Pullen 
211*7a8a68f5SJulian Pullen 
212*7a8a68f5SJulian Pullen static boolean_t
213*7a8a68f5SJulian Pullen is_valid(ad_item_t *item)
214*7a8a68f5SJulian Pullen {
215*7a8a68f5SJulian Pullen 	if (item->value != NULL) {
216*7a8a68f5SJulian Pullen 		if (item->state == AD_STATE_FIXED)
217*7a8a68f5SJulian Pullen 			return (B_TRUE);
218*7a8a68f5SJulian Pullen 		if (item->state == AD_STATE_AUTO &&
219*7a8a68f5SJulian Pullen 		    (item->ttl == 0 || item->ttl > time(NULL)))
220*7a8a68f5SJulian Pullen 			return (B_TRUE);
221*7a8a68f5SJulian Pullen 	}
222*7a8a68f5SJulian Pullen 	return (B_FALSE);
223*7a8a68f5SJulian Pullen }
224*7a8a68f5SJulian Pullen 
225*7a8a68f5SJulian Pullen 
226*7a8a68f5SJulian Pullen static void
227*7a8a68f5SJulian Pullen update_item(ad_item_t *item, void *value, enum ad_item_state state,
228*7a8a68f5SJulian Pullen 		uint32_t ttl)
229*7a8a68f5SJulian Pullen {
230*7a8a68f5SJulian Pullen 	if (item->value != NULL && value != NULL) {
231*7a8a68f5SJulian Pullen 		if ((item->type == AD_STRING &&
232*7a8a68f5SJulian Pullen 		    strcmp(item->value, value) != 0) ||
233*7a8a68f5SJulian Pullen 		    (item->type == AD_DIRECTORY &&
234*7a8a68f5SJulian Pullen 		    ad_disc_compare_ds(item->value, value) != 0)||
235*7a8a68f5SJulian Pullen 		    (item->type == AD_DOMAINS_IN_FOREST &&
236*7a8a68f5SJulian Pullen 		    ad_disc_compare_domainsinforest(item->value, value) != 0) ||
237*7a8a68f5SJulian Pullen 		    (item->type == AD_TRUSTED_DOMAINS &&
238*7a8a68f5SJulian Pullen 		    ad_disc_compare_trusteddomains(item->value, value) != 0))
239*7a8a68f5SJulian Pullen 			item->version++;
240*7a8a68f5SJulian Pullen 	} else if (item->value != value)
241*7a8a68f5SJulian Pullen 		item->version++;
242*7a8a68f5SJulian Pullen 
243*7a8a68f5SJulian Pullen 	if (item->value != NULL)
244*7a8a68f5SJulian Pullen 		free(item->value);
245*7a8a68f5SJulian Pullen 
246*7a8a68f5SJulian Pullen 	item->value = value;
247*7a8a68f5SJulian Pullen 	item->state = state;
248*7a8a68f5SJulian Pullen 
249*7a8a68f5SJulian Pullen 	if (ttl == 0)
250*7a8a68f5SJulian Pullen 		item->ttl = 0;
251*7a8a68f5SJulian Pullen 	else
252*7a8a68f5SJulian Pullen 		item->ttl = time(NULL) + ttl;
253*7a8a68f5SJulian Pullen }
254*7a8a68f5SJulian Pullen 
255*7a8a68f5SJulian Pullen 
256*7a8a68f5SJulian Pullen /* Compare DS lists */
257*7a8a68f5SJulian Pullen int
258*7a8a68f5SJulian Pullen ad_disc_compare_ds(idmap_ad_disc_ds_t *ds1, idmap_ad_disc_ds_t *ds2)
259*7a8a68f5SJulian Pullen {
260*7a8a68f5SJulian Pullen 	int		i, j;
261*7a8a68f5SJulian Pullen 	int		num_ds1;
262*7a8a68f5SJulian Pullen 	int		num_ds2;
263*7a8a68f5SJulian Pullen 	boolean_t	match;
264*7a8a68f5SJulian Pullen 
265*7a8a68f5SJulian Pullen 	for (i = 0; ds1[i].host[0] != '\0'; i++)
266*7a8a68f5SJulian Pullen 		continue;
267*7a8a68f5SJulian Pullen 	num_ds1 = i;
268*7a8a68f5SJulian Pullen 	for (j = 0; ds2[j].host[0] != '\0'; j++)
269*7a8a68f5SJulian Pullen 		continue;
270*7a8a68f5SJulian Pullen 	num_ds2 = j;
271*7a8a68f5SJulian Pullen 	if (num_ds1 != num_ds2)
272*7a8a68f5SJulian Pullen 		return (1);
273*7a8a68f5SJulian Pullen 
274*7a8a68f5SJulian Pullen 	for (i = 0; i < num_ds1; i++) {
275*7a8a68f5SJulian Pullen 		match = B_FALSE;
276*7a8a68f5SJulian Pullen 		for (j = 0; j < num_ds2; j++) {
277*7a8a68f5SJulian Pullen 			if (strcmp(ds1[i].host, ds2[i].host) == 0 &&
278*7a8a68f5SJulian Pullen 			    ds1[i].port == ds2[i].port) {
279*7a8a68f5SJulian Pullen 				match = B_TRUE;
280*7a8a68f5SJulian Pullen 				break;
281*7a8a68f5SJulian Pullen 			}
282*7a8a68f5SJulian Pullen 		}
283*7a8a68f5SJulian Pullen 		if (!match)
284*7a8a68f5SJulian Pullen 			return (1);
285*7a8a68f5SJulian Pullen 	}
286*7a8a68f5SJulian Pullen 	return (0);
287*7a8a68f5SJulian Pullen }
288*7a8a68f5SJulian Pullen 
289*7a8a68f5SJulian Pullen 
290*7a8a68f5SJulian Pullen /* Copy a list of DSs */
291*7a8a68f5SJulian Pullen static idmap_ad_disc_ds_t *
292*7a8a68f5SJulian Pullen ds_dup(const idmap_ad_disc_ds_t *srv)
293*7a8a68f5SJulian Pullen {
294*7a8a68f5SJulian Pullen 	int	i;
295*7a8a68f5SJulian Pullen 	int	size;
296*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *new = NULL;
297*7a8a68f5SJulian Pullen 
298*7a8a68f5SJulian Pullen 	for (i = 0; srv[i].host[0] != '\0'; i++)
299*7a8a68f5SJulian Pullen 		continue;
300*7a8a68f5SJulian Pullen 
301*7a8a68f5SJulian Pullen 	size = (i + 1) * sizeof (idmap_ad_disc_ds_t);
302*7a8a68f5SJulian Pullen 	new = malloc(size);
303*7a8a68f5SJulian Pullen 	if (new != NULL)
304*7a8a68f5SJulian Pullen 		memcpy(new, srv, size);
305*7a8a68f5SJulian Pullen 	return (new);
306*7a8a68f5SJulian Pullen }
307*7a8a68f5SJulian Pullen 
308*7a8a68f5SJulian Pullen 
309*7a8a68f5SJulian Pullen int
310*7a8a68f5SJulian Pullen ad_disc_compare_trusteddomains(ad_disc_trusteddomains_t *td1,
311*7a8a68f5SJulian Pullen 			ad_disc_trusteddomains_t *td2)
312*7a8a68f5SJulian Pullen {
313*7a8a68f5SJulian Pullen 	int		i, j;
314*7a8a68f5SJulian Pullen 	int		num_td1;
315*7a8a68f5SJulian Pullen 	int		num_td2;
316*7a8a68f5SJulian Pullen 	boolean_t	match;
317*7a8a68f5SJulian Pullen 	int 		err;
318*7a8a68f5SJulian Pullen 
319*7a8a68f5SJulian Pullen 	for (i = 0; td1[i].domain[0] != '\0'; i++)
320*7a8a68f5SJulian Pullen 		continue;
321*7a8a68f5SJulian Pullen 	num_td1 = i;
322*7a8a68f5SJulian Pullen 
323*7a8a68f5SJulian Pullen 	for (j = 0; td2[j].domain[0] != '\0'; j++)
324*7a8a68f5SJulian Pullen 		continue;
325*7a8a68f5SJulian Pullen 	num_td2 = j;
326*7a8a68f5SJulian Pullen 
327*7a8a68f5SJulian Pullen 	if (num_td1 != num_td2)
328*7a8a68f5SJulian Pullen 		return (1);
329*7a8a68f5SJulian Pullen 
330*7a8a68f5SJulian Pullen 	for (i = 0; i < num_td1; i++) {
331*7a8a68f5SJulian Pullen 		match = B_FALSE;
332*7a8a68f5SJulian Pullen 		for (j = 0; j < num_td2; j++) {
333*7a8a68f5SJulian Pullen 			if (u8_strcmp(td1[i].domain, td2[i].domain, 0,
334*7a8a68f5SJulian Pullen 			    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
335*7a8a68f5SJulian Pullen 			    err == 0) {
336*7a8a68f5SJulian Pullen 				match = B_TRUE;
337*7a8a68f5SJulian Pullen 				break;
338*7a8a68f5SJulian Pullen 			}
339*7a8a68f5SJulian Pullen 		}
340*7a8a68f5SJulian Pullen 		if (!match)
341*7a8a68f5SJulian Pullen 			return (1);
342*7a8a68f5SJulian Pullen 	}
343*7a8a68f5SJulian Pullen 	return (0);
344*7a8a68f5SJulian Pullen }
345*7a8a68f5SJulian Pullen 
346*7a8a68f5SJulian Pullen 
347*7a8a68f5SJulian Pullen 
348*7a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */
349*7a8a68f5SJulian Pullen static ad_disc_trusteddomains_t *
350*7a8a68f5SJulian Pullen td_dup(const ad_disc_trusteddomains_t *td)
351*7a8a68f5SJulian Pullen {
352*7a8a68f5SJulian Pullen 	int	i;
353*7a8a68f5SJulian Pullen 	int	size;
354*7a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *new = NULL;
355*7a8a68f5SJulian Pullen 
356*7a8a68f5SJulian Pullen 	for (i = 0; td[i].domain[0] != '\0'; i++)
357*7a8a68f5SJulian Pullen 		continue;
358*7a8a68f5SJulian Pullen 
359*7a8a68f5SJulian Pullen 	size = (i + 1) * sizeof (ad_disc_trusteddomains_t);
360*7a8a68f5SJulian Pullen 	new = malloc(size);
361*7a8a68f5SJulian Pullen 	if (new != NULL)
362*7a8a68f5SJulian Pullen 		memcpy(new, td, size);
363*7a8a68f5SJulian Pullen 	return (new);
364*7a8a68f5SJulian Pullen }
365*7a8a68f5SJulian Pullen 
366*7a8a68f5SJulian Pullen 
367*7a8a68f5SJulian Pullen 
368*7a8a68f5SJulian Pullen int
369*7a8a68f5SJulian Pullen ad_disc_compare_domainsinforest(ad_disc_domainsinforest_t *df1,
370*7a8a68f5SJulian Pullen 			ad_disc_domainsinforest_t *df2)
371*7a8a68f5SJulian Pullen {
372*7a8a68f5SJulian Pullen 	int		i, j;
373*7a8a68f5SJulian Pullen 	int		num_df1;
374*7a8a68f5SJulian Pullen 	int		num_df2;
375*7a8a68f5SJulian Pullen 	boolean_t	match;
376*7a8a68f5SJulian Pullen 	int		err;
377*7a8a68f5SJulian Pullen 
378*7a8a68f5SJulian Pullen 	for (i = 0; df1[i].domain[0] != '\0'; i++)
379*7a8a68f5SJulian Pullen 		continue;
380*7a8a68f5SJulian Pullen 	num_df1 = i;
381*7a8a68f5SJulian Pullen 
382*7a8a68f5SJulian Pullen 	for (j = 0; df2[j].domain[0] != '\0'; j++)
383*7a8a68f5SJulian Pullen 		continue;
384*7a8a68f5SJulian Pullen 	num_df2 = j;
385*7a8a68f5SJulian Pullen 
386*7a8a68f5SJulian Pullen 	if (num_df1 != num_df2)
387*7a8a68f5SJulian Pullen 		return (1);
388*7a8a68f5SJulian Pullen 
389*7a8a68f5SJulian Pullen 	for (i = 0; i < num_df1; i++) {
390*7a8a68f5SJulian Pullen 		match = B_FALSE;
391*7a8a68f5SJulian Pullen 		for (j = 0; j < num_df2; j++) {
392*7a8a68f5SJulian Pullen 			if (u8_strcmp(df1[i].domain, df2[i].domain, 0,
393*7a8a68f5SJulian Pullen 			    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
394*7a8a68f5SJulian Pullen 			    err == 0 &&
395*7a8a68f5SJulian Pullen 			    strcmp(df1[i].sid, df2[i].sid) == 0) {
396*7a8a68f5SJulian Pullen 				match = B_TRUE;
397*7a8a68f5SJulian Pullen 				break;
398*7a8a68f5SJulian Pullen 			}
399*7a8a68f5SJulian Pullen 		}
400*7a8a68f5SJulian Pullen 		if (!match)
401*7a8a68f5SJulian Pullen 			return (1);
402*7a8a68f5SJulian Pullen 	}
403*7a8a68f5SJulian Pullen 	return (0);
404*7a8a68f5SJulian Pullen }
405*7a8a68f5SJulian Pullen 
406*7a8a68f5SJulian Pullen 
407*7a8a68f5SJulian Pullen 
408*7a8a68f5SJulian Pullen /* Copy a list of Trusted Domains */
409*7a8a68f5SJulian Pullen static ad_disc_domainsinforest_t *
410*7a8a68f5SJulian Pullen df_dup(const ad_disc_domainsinforest_t *df)
411*7a8a68f5SJulian Pullen {
412*7a8a68f5SJulian Pullen 	int	i;
413*7a8a68f5SJulian Pullen 	int	size;
414*7a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *new = NULL;
415*7a8a68f5SJulian Pullen 
416*7a8a68f5SJulian Pullen 	for (i = 0; df[i].domain[0] != '\0'; i++)
417*7a8a68f5SJulian Pullen 		continue;
418*7a8a68f5SJulian Pullen 
419*7a8a68f5SJulian Pullen 	size = (i + 1) * sizeof (ad_disc_domainsinforest_t);
420*7a8a68f5SJulian Pullen 	new = malloc(size);
421*7a8a68f5SJulian Pullen 	if (new != NULL)
422*7a8a68f5SJulian Pullen 		memcpy(new, df, size);
423*7a8a68f5SJulian Pullen 	return (new);
424*7a8a68f5SJulian Pullen }
425*7a8a68f5SJulian Pullen 
426*7a8a68f5SJulian Pullen 
427*7a8a68f5SJulian Pullen 
428*7a8a68f5SJulian Pullen 
429*7a8a68f5SJulian Pullen 
430*7a8a68f5SJulian Pullen /*
431*7a8a68f5SJulian Pullen  * Returns an array of IPv4 address/prefix length
432*7a8a68f5SJulian Pullen  * The last subnet is NULL
433*7a8a68f5SJulian Pullen  */
434*7a8a68f5SJulian Pullen static ad_subnet_t *
435*7a8a68f5SJulian Pullen find_subnets()
436*7a8a68f5SJulian Pullen {
437*7a8a68f5SJulian Pullen 	int		sock, n, i;
438*7a8a68f5SJulian Pullen 	struct lifconf	lifc;
439*7a8a68f5SJulian Pullen 	struct lifreq	lifr, *lifrp;
440*7a8a68f5SJulian Pullen 	struct lifnum	lifn;
441*7a8a68f5SJulian Pullen 	uint32_t	prefix_len;
442*7a8a68f5SJulian Pullen 	char		*s;
443*7a8a68f5SJulian Pullen 	ad_subnet_t	*results;
444*7a8a68f5SJulian Pullen 
445*7a8a68f5SJulian Pullen 	lifrp = &lifr;
446*7a8a68f5SJulian Pullen 
447*7a8a68f5SJulian Pullen 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
448*7a8a68f5SJulian Pullen 		logger(LOG_ERR, "Failed to open IPv4 socket for "
449*7a8a68f5SJulian Pullen 		    "listing network interfaces (%s)", strerror(errno));
450*7a8a68f5SJulian Pullen 		return (NULL);
451*7a8a68f5SJulian Pullen 	}
452*7a8a68f5SJulian Pullen 
453*7a8a68f5SJulian Pullen 	lifn.lifn_family = AF_INET;
454*7a8a68f5SJulian Pullen 	lifn.lifn_flags = 0;
455*7a8a68f5SJulian Pullen 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
456*7a8a68f5SJulian Pullen 		logger(LOG_ERR,
457*7a8a68f5SJulian Pullen 		    "Failed to find the number of network interfaces (%s)",
458*7a8a68f5SJulian Pullen 		    strerror(errno));
459*7a8a68f5SJulian Pullen 		close(sock);
460*7a8a68f5SJulian Pullen 		return (NULL);
461*7a8a68f5SJulian Pullen 	}
462*7a8a68f5SJulian Pullen 
463*7a8a68f5SJulian Pullen 	if (lifn.lifn_count < 1) {
464*7a8a68f5SJulian Pullen 		logger(LOG_ERR, "No IPv4 network interfaces found");
465*7a8a68f5SJulian Pullen 		close(sock);
466*7a8a68f5SJulian Pullen 		return (NULL);
467*7a8a68f5SJulian Pullen 	}
468*7a8a68f5SJulian Pullen 
469*7a8a68f5SJulian Pullen 	lifc.lifc_family = AF_INET;
470*7a8a68f5SJulian Pullen 	lifc.lifc_flags = 0;
471*7a8a68f5SJulian Pullen 	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
472*7a8a68f5SJulian Pullen 	lifc.lifc_buf = malloc(lifc.lifc_len);
473*7a8a68f5SJulian Pullen 
474*7a8a68f5SJulian Pullen 	if (lifc.lifc_buf == NULL) {
475*7a8a68f5SJulian Pullen 		logger(LOG_ERR, "Out of memory");
476*7a8a68f5SJulian Pullen 		close(sock);
477*7a8a68f5SJulian Pullen 		return (NULL);
478*7a8a68f5SJulian Pullen 	}
479*7a8a68f5SJulian Pullen 
480*7a8a68f5SJulian Pullen 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
481*7a8a68f5SJulian Pullen 		logger(LOG_ERR, "Failed to list network interfaces (%s)",
482*7a8a68f5SJulian Pullen 		    strerror(errno));
483*7a8a68f5SJulian Pullen 		free(lifc.lifc_buf);
484*7a8a68f5SJulian Pullen 		close(sock);
485*7a8a68f5SJulian Pullen 		return (NULL);
486*7a8a68f5SJulian Pullen 	}
487*7a8a68f5SJulian Pullen 
488*7a8a68f5SJulian Pullen 	n = lifc.lifc_len / (int)sizeof (struct lifreq);
489*7a8a68f5SJulian Pullen 
490*7a8a68f5SJulian Pullen 	if ((results = calloc(n + 1, sizeof (ad_subnet_t))) == NULL) {
491*7a8a68f5SJulian Pullen 		free(lifc.lifc_buf);
492*7a8a68f5SJulian Pullen 		close(sock);
493*7a8a68f5SJulian Pullen 		return (NULL);
494*7a8a68f5SJulian Pullen 	}
495*7a8a68f5SJulian Pullen 
496*7a8a68f5SJulian Pullen 	for (i = 0, lifrp = lifc.lifc_req; i < n; i++, lifrp++) {
497*7a8a68f5SJulian Pullen 		if (ioctl(sock, SIOCGLIFFLAGS, lifrp) < 0)
498*7a8a68f5SJulian Pullen 			continue;
499*7a8a68f5SJulian Pullen 
500*7a8a68f5SJulian Pullen 		if ((lifrp->lifr_flags & IFF_UP) == 0)
501*7a8a68f5SJulian Pullen 			continue;
502*7a8a68f5SJulian Pullen 
503*7a8a68f5SJulian Pullen 		if (ioctl(sock, SIOCGLIFSUBNET, lifrp) < 0)
504*7a8a68f5SJulian Pullen 			continue;
505*7a8a68f5SJulian Pullen 
506*7a8a68f5SJulian Pullen 		prefix_len = lifrp->lifr_addrlen;
507*7a8a68f5SJulian Pullen 
508*7a8a68f5SJulian Pullen 		s = inet_ntoa(((struct sockaddr_in *)
509*7a8a68f5SJulian Pullen 		    &lifrp->lifr_addr)->sin_addr);
510*7a8a68f5SJulian Pullen 
511*7a8a68f5SJulian Pullen 		(void) snprintf(results[i].subnet, sizeof (ad_subnet_t),
512*7a8a68f5SJulian Pullen 		    "%s/%d", s, prefix_len);
513*7a8a68f5SJulian Pullen 	}
514*7a8a68f5SJulian Pullen 
515*7a8a68f5SJulian Pullen 	free(lifc.lifc_buf);
516*7a8a68f5SJulian Pullen 	close(sock);
517*7a8a68f5SJulian Pullen 
518*7a8a68f5SJulian Pullen 	return (results);
519*7a8a68f5SJulian Pullen }
520*7a8a68f5SJulian Pullen 
521*7a8a68f5SJulian Pullen static int
522*7a8a68f5SJulian Pullen cmpsubnets(ad_subnet_t *subnets1, ad_subnet_t *subnets2)
523*7a8a68f5SJulian Pullen {
524*7a8a68f5SJulian Pullen 	int num_subnets1;
525*7a8a68f5SJulian Pullen 	int num_subnets2;
526*7a8a68f5SJulian Pullen 	boolean_t matched;
527*7a8a68f5SJulian Pullen 	int i, j;
528*7a8a68f5SJulian Pullen 
529*7a8a68f5SJulian Pullen 	for (i = 0; subnets1[i].subnet[0] != '\0'; i++)
530*7a8a68f5SJulian Pullen 		continue;
531*7a8a68f5SJulian Pullen 	num_subnets1 = i;
532*7a8a68f5SJulian Pullen 
533*7a8a68f5SJulian Pullen 	for (i = 0; subnets2[i].subnet[0] != '\0'; i++)
534*7a8a68f5SJulian Pullen 		continue;
535*7a8a68f5SJulian Pullen 	num_subnets2 = i;
536*7a8a68f5SJulian Pullen 
537*7a8a68f5SJulian Pullen 	if (num_subnets1 != num_subnets2)
538*7a8a68f5SJulian Pullen 		return (1);
539*7a8a68f5SJulian Pullen 
540*7a8a68f5SJulian Pullen 	for (i = 0;  i < num_subnets1; i++) {
541*7a8a68f5SJulian Pullen 		matched = B_FALSE;
542*7a8a68f5SJulian Pullen 		for (j = 0; j < num_subnets2; j++) {
543*7a8a68f5SJulian Pullen 			if (strcmp(subnets1[i].subnet,
544*7a8a68f5SJulian Pullen 			    subnets2[j].subnet) == 0) {
545*7a8a68f5SJulian Pullen 				matched = B_TRUE;
546*7a8a68f5SJulian Pullen 				break;
547*7a8a68f5SJulian Pullen 			}
548*7a8a68f5SJulian Pullen 		}
549*7a8a68f5SJulian Pullen 		if (!matched)
550*7a8a68f5SJulian Pullen 			return (1);
551*7a8a68f5SJulian Pullen 	}
552*7a8a68f5SJulian Pullen 	return (0);
553*7a8a68f5SJulian Pullen }
554*7a8a68f5SJulian Pullen 
555*7a8a68f5SJulian Pullen 
556*7a8a68f5SJulian Pullen 
557*7a8a68f5SJulian Pullen 
558*7a8a68f5SJulian Pullen /* Convert a DN's DC components into a DNS domainname */
559*7a8a68f5SJulian Pullen char *
560*7a8a68f5SJulian Pullen DN_to_DNS(const char *dn_name)
561*7a8a68f5SJulian Pullen {
562*7a8a68f5SJulian Pullen 	char	dns[DNS_MAX_NAME];
563*7a8a68f5SJulian Pullen 	char	*dns_name;
564*7a8a68f5SJulian Pullen 	int	i, j;
565*7a8a68f5SJulian Pullen 	int	num = 0;
566*7a8a68f5SJulian Pullen 
567*7a8a68f5SJulian Pullen 	j = 0;
568*7a8a68f5SJulian Pullen 	i = 0;
569*7a8a68f5SJulian Pullen 
570*7a8a68f5SJulian Pullen 	if (dn_name == NULL)
571*7a8a68f5SJulian Pullen 		return (NULL);
572*7a8a68f5SJulian Pullen 	/*
573*7a8a68f5SJulian Pullen 	 * Find all DC=<value> and form DNS name of the
574*7a8a68f5SJulian Pullen 	 * form <value1>.<value2>...
575*7a8a68f5SJulian Pullen 	 */
576*7a8a68f5SJulian Pullen 	while (dn_name[i] != '\0') {
577*7a8a68f5SJulian Pullen 		if (strncasecmp(&dn_name[i], "DC=", 3) == 0) {
578*7a8a68f5SJulian Pullen 			i += 3;
579*7a8a68f5SJulian Pullen 			if (dn_name[i] != '\0' && num > 0)
580*7a8a68f5SJulian Pullen 				dns[j++] = '.';
581*7a8a68f5SJulian Pullen 			while (dn_name[i] != '\0' &&
582*7a8a68f5SJulian Pullen 			    dn_name[i] != ',' && dn_name[i] != '+')
583*7a8a68f5SJulian Pullen 				dns[j++] = dn_name[i++];
584*7a8a68f5SJulian Pullen 			num++;
585*7a8a68f5SJulian Pullen 		} else {
586*7a8a68f5SJulian Pullen 			/* Skip attr=value as it is not DC= */
587*7a8a68f5SJulian Pullen 			while (dn_name[i] != '\0' &&
588*7a8a68f5SJulian Pullen 			    dn_name[i] != ',' && dn_name[i] != '+')
589*7a8a68f5SJulian Pullen 				i++;
590*7a8a68f5SJulian Pullen 		}
591*7a8a68f5SJulian Pullen 		/* Skip over separator ','  or '+' */
592*7a8a68f5SJulian Pullen 		if (dn_name[i] != '\0') i++;
593*7a8a68f5SJulian Pullen 	}
594*7a8a68f5SJulian Pullen 	dns[j] = '\0';
595*7a8a68f5SJulian Pullen 	dns_name = malloc(j + 1);
596*7a8a68f5SJulian Pullen 	if (dns_name != NULL)
597*7a8a68f5SJulian Pullen 		(void) strlcpy(dns_name, dns, j + 1);
598*7a8a68f5SJulian Pullen 	return (dns_name);
599*7a8a68f5SJulian Pullen }
600*7a8a68f5SJulian Pullen 
601*7a8a68f5SJulian Pullen 
602*7a8a68f5SJulian Pullen /* Format the DN of an AD LDAP subnet object for some subnet */
603*7a8a68f5SJulian Pullen static char *
604*7a8a68f5SJulian Pullen subnet_to_DN(const char *subnet, const char *baseDN)
605*7a8a68f5SJulian Pullen {
606*7a8a68f5SJulian Pullen 	char *result;
607*7a8a68f5SJulian Pullen 	int len;
608*7a8a68f5SJulian Pullen 
609*7a8a68f5SJulian Pullen 	len = snprintf(NULL, 0,
610*7a8a68f5SJulian Pullen 	    "CN=%s,CN=Subnets,CN=Sites,%s",
611*7a8a68f5SJulian Pullen 	    subnet, baseDN) + 1;
612*7a8a68f5SJulian Pullen 
613*7a8a68f5SJulian Pullen 	result = malloc(len);
614*7a8a68f5SJulian Pullen 	if (result != NULL)
615*7a8a68f5SJulian Pullen 		(void) snprintf(result, len,
616*7a8a68f5SJulian Pullen 		    "CN=%s,CN=Subnets,CN=Sites,%s",
617*7a8a68f5SJulian Pullen 		    subnet, baseDN);
618*7a8a68f5SJulian Pullen 	return (result);
619*7a8a68f5SJulian Pullen }
620*7a8a68f5SJulian Pullen 
621*7a8a68f5SJulian Pullen 
622*7a8a68f5SJulian Pullen /* Make a list of subnet object DNs from a list of subnets */
623*7a8a68f5SJulian Pullen static char **
624*7a8a68f5SJulian Pullen subnets_to_DNs(ad_subnet_t *subnets, const char *base_dn)
625*7a8a68f5SJulian Pullen {
626*7a8a68f5SJulian Pullen 	char **results;
627*7a8a68f5SJulian Pullen 	int i, j;
628*7a8a68f5SJulian Pullen 
629*7a8a68f5SJulian Pullen 	for (i = 0; subnets[i].subnet[0] != '\0'; i++)
630*7a8a68f5SJulian Pullen 		continue;
631*7a8a68f5SJulian Pullen 
632*7a8a68f5SJulian Pullen 	results = calloc(i + 1, sizeof (char *));
633*7a8a68f5SJulian Pullen 	if (results == NULL)
634*7a8a68f5SJulian Pullen 		return (NULL);
635*7a8a68f5SJulian Pullen 
636*7a8a68f5SJulian Pullen 	for (i = 0; subnets[i].subnet[0] != '\0'; i++) {
637*7a8a68f5SJulian Pullen 		if ((results[i] = subnet_to_DN(subnets[i].subnet, base_dn))
638*7a8a68f5SJulian Pullen 		    == NULL) {
639*7a8a68f5SJulian Pullen 			for (j = 0; j < i; j++)
640*7a8a68f5SJulian Pullen 				free(results[j]);
641*7a8a68f5SJulian Pullen 			free(results);
642*7a8a68f5SJulian Pullen 			return (NULL);
643*7a8a68f5SJulian Pullen 		}
644*7a8a68f5SJulian Pullen 	}
645*7a8a68f5SJulian Pullen 
646*7a8a68f5SJulian Pullen 	return (results);
647*7a8a68f5SJulian Pullen }
648*7a8a68f5SJulian Pullen 
649*7a8a68f5SJulian Pullen 
650*7a8a68f5SJulian Pullen /* Compare SRC RRs; used with qsort() */
651*7a8a68f5SJulian Pullen static int
652*7a8a68f5SJulian Pullen srvcmp(idmap_ad_disc_ds_t *s1, idmap_ad_disc_ds_t *s2)
653*7a8a68f5SJulian Pullen {
654*7a8a68f5SJulian Pullen 	if (s1->priority < s2->priority)
655*7a8a68f5SJulian Pullen 		return (1);
656*7a8a68f5SJulian Pullen 	else if (s1->priority > s2->priority)
657*7a8a68f5SJulian Pullen 		return (-1);
658*7a8a68f5SJulian Pullen 
659*7a8a68f5SJulian Pullen 	if (s1->weight < s2->weight)
660*7a8a68f5SJulian Pullen 		return (1);
661*7a8a68f5SJulian Pullen 	else if (s1->weight > s2->weight)
662*7a8a68f5SJulian Pullen 		return (-1);
663*7a8a68f5SJulian Pullen 
664*7a8a68f5SJulian Pullen 	return (0);
665*7a8a68f5SJulian Pullen }
666*7a8a68f5SJulian Pullen 
667*7a8a68f5SJulian Pullen 
668*7a8a68f5SJulian Pullen /*
669*7a8a68f5SJulian Pullen  * Query or search the SRV RRs for a given name.
670*7a8a68f5SJulian Pullen  *
671*7a8a68f5SJulian Pullen  * If name == NULL then search (as in res_nsearch(3RESOLV), honoring any
672*7a8a68f5SJulian Pullen  * search list/option), else query (as in res_nquery(3RESOLV)).
673*7a8a68f5SJulian Pullen  *
674*7a8a68f5SJulian Pullen  * The output TTL will be the one of the SRV RR with the lowest TTL.
675*7a8a68f5SJulian Pullen  */
676*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *
677*7a8a68f5SJulian Pullen srv_query(res_state state, const char *svc_name, const char *dname,
678*7a8a68f5SJulian Pullen 		char **rrname, uint32_t *ttl)
679*7a8a68f5SJulian Pullen {
680*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *srv;
681*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *srv_res;
682*7a8a68f5SJulian Pullen 	union {
683*7a8a68f5SJulian Pullen 		HEADER hdr;
684*7a8a68f5SJulian Pullen 		uchar_t buf[NS_MAXMSG];
685*7a8a68f5SJulian Pullen 	} msg;
686*7a8a68f5SJulian Pullen 	int len, cnt, qdcount, ancount;
687*7a8a68f5SJulian Pullen 	uchar_t *ptr, *eom;
688*7a8a68f5SJulian Pullen 	uchar_t *end;
689*7a8a68f5SJulian Pullen 	uint16_t type;
690*7a8a68f5SJulian Pullen 	/* LINTED  E_FUNC_SET_NOT_USED */
691*7a8a68f5SJulian Pullen 	uint16_t class;
692*7a8a68f5SJulian Pullen 	uint32_t rttl;
693*7a8a68f5SJulian Pullen 	uint16_t size;
694*7a8a68f5SJulian Pullen 	char namebuf[NS_MAXDNAME];
695*7a8a68f5SJulian Pullen 
696*7a8a68f5SJulian Pullen 	if (state == NULL)
697*7a8a68f5SJulian Pullen 		return (NULL);
698*7a8a68f5SJulian Pullen 
699*7a8a68f5SJulian Pullen 	/* Set negative result TTL */
700*7a8a68f5SJulian Pullen 	*ttl = 5 * 60;
701*7a8a68f5SJulian Pullen 
702*7a8a68f5SJulian Pullen 	/* 1. query necessary resource records */
703*7a8a68f5SJulian Pullen 
704*7a8a68f5SJulian Pullen 	/* Search, querydomain or query */
705*7a8a68f5SJulian Pullen 	if (rrname != NULL) {
706*7a8a68f5SJulian Pullen 		*rrname = NULL;
707*7a8a68f5SJulian Pullen 		len = res_nsearch(state, svc_name, C_IN, T_SRV,
708*7a8a68f5SJulian Pullen 		    msg.buf, sizeof (msg.buf));
709*7a8a68f5SJulian Pullen 		logger(LOG_DEBUG, "Searching DNS for SRV RRs named '%s'",
710*7a8a68f5SJulian Pullen 		    svc_name);
711*7a8a68f5SJulian Pullen 		if (len < 0) {
712*7a8a68f5SJulian Pullen 			logger(LOG_DEBUG, "DNS search for '%s' failed (%s)",
713*7a8a68f5SJulian Pullen 			    svc_name, hstrerror(state->res_h_errno));
714*7a8a68f5SJulian Pullen 			return (NULL);
715*7a8a68f5SJulian Pullen 		}
716*7a8a68f5SJulian Pullen 	} else if (dname != NULL) {
717*7a8a68f5SJulian Pullen 		len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV,
718*7a8a68f5SJulian Pullen 		    msg.buf, sizeof (msg.buf));
719*7a8a68f5SJulian Pullen 		logger(LOG_DEBUG,
720*7a8a68f5SJulian Pullen 		    "Querying DNS for SRV RRs named '%s' for '%s' ",
721*7a8a68f5SJulian Pullen 		    svc_name, dname);
722*7a8a68f5SJulian Pullen 
723*7a8a68f5SJulian Pullen 		if (len < 0) {
724*7a8a68f5SJulian Pullen 			logger(LOG_DEBUG,
725*7a8a68f5SJulian Pullen 			    "DNS query for '%s' for '%s' failed (%s)",
726*7a8a68f5SJulian Pullen 			    svc_name, dname, hstrerror(state->res_h_errno));
727*7a8a68f5SJulian Pullen 			return (NULL);
728*7a8a68f5SJulian Pullen 		}
729*7a8a68f5SJulian Pullen 	}
730*7a8a68f5SJulian Pullen 
731*7a8a68f5SJulian Pullen 	if (len > sizeof (msg.buf)) {
732*7a8a68f5SJulian Pullen 		logger(LOG_ERR, "DNS query %ib message doesn't fit"
733*7a8a68f5SJulian Pullen 		    " into %ib buffer",
734*7a8a68f5SJulian Pullen 		    len, sizeof (msg.buf));
735*7a8a68f5SJulian Pullen 		return (NULL);
736*7a8a68f5SJulian Pullen 	}
737*7a8a68f5SJulian Pullen 
738*7a8a68f5SJulian Pullen 	/* 2. parse the reply, skip header and question sections */
739*7a8a68f5SJulian Pullen 
740*7a8a68f5SJulian Pullen 	ptr = msg.buf + sizeof (msg.hdr);
741*7a8a68f5SJulian Pullen 	eom = msg.buf + len;
742*7a8a68f5SJulian Pullen 	qdcount = ntohs(msg.hdr.qdcount);
743*7a8a68f5SJulian Pullen 	ancount = ntohs(msg.hdr.ancount);
744*7a8a68f5SJulian Pullen 
745*7a8a68f5SJulian Pullen 	for (cnt = qdcount; cnt > 0; --cnt) {
746*7a8a68f5SJulian Pullen 		if ((len = dn_skipname(ptr, eom)) < 0) {
747*7a8a68f5SJulian Pullen 			logger(LOG_ERR, "DNS query invalid message format");
748*7a8a68f5SJulian Pullen 			return (NULL);
749*7a8a68f5SJulian Pullen 		}
750*7a8a68f5SJulian Pullen 		ptr += len + QFIXEDSZ;
751*7a8a68f5SJulian Pullen 	}
752*7a8a68f5SJulian Pullen 
753*7a8a68f5SJulian Pullen 	/* 3. walk through the answer section */
754*7a8a68f5SJulian Pullen 
755*7a8a68f5SJulian Pullen 	srv_res = calloc(ancount + 1, sizeof (idmap_ad_disc_ds_t));
756*7a8a68f5SJulian Pullen 	*ttl = (uint32_t)-1;
757*7a8a68f5SJulian Pullen 
758*7a8a68f5SJulian Pullen 	for (srv = srv_res, cnt = ancount;
759*7a8a68f5SJulian Pullen 	    cnt > 0; --cnt, srv++) {
760*7a8a68f5SJulian Pullen 
761*7a8a68f5SJulian Pullen 		len = dn_expand(msg.buf, eom, ptr, namebuf,
762*7a8a68f5SJulian Pullen 		    sizeof (namebuf));
763*7a8a68f5SJulian Pullen 		if (len < 0) {
764*7a8a68f5SJulian Pullen 			logger(LOG_ERR, "DNS query invalid message format");
765*7a8a68f5SJulian Pullen 			return (NULL);
766*7a8a68f5SJulian Pullen 		}
767*7a8a68f5SJulian Pullen 		if (rrname != NULL && *rrname == NULL)
768*7a8a68f5SJulian Pullen 			*rrname = strdup(namebuf);
769*7a8a68f5SJulian Pullen 		ptr += len;
770*7a8a68f5SJulian Pullen 		NS_GET16(type, ptr);
771*7a8a68f5SJulian Pullen 		NS_GET16(class, ptr);
772*7a8a68f5SJulian Pullen 		NS_GET32(rttl, ptr);
773*7a8a68f5SJulian Pullen 		NS_GET16(size, ptr);
774*7a8a68f5SJulian Pullen 		if ((end = ptr + size) > eom) {
775*7a8a68f5SJulian Pullen 			logger(LOG_ERR, "DNS query invalid message format");
776*7a8a68f5SJulian Pullen 			return (NULL);
777*7a8a68f5SJulian Pullen 		}
778*7a8a68f5SJulian Pullen 
779*7a8a68f5SJulian Pullen 		if (type != T_SRV) {
780*7a8a68f5SJulian Pullen 			ptr = end;
781*7a8a68f5SJulian Pullen 			continue;
782*7a8a68f5SJulian Pullen 		}
783*7a8a68f5SJulian Pullen 
784*7a8a68f5SJulian Pullen 		NS_GET16(srv->priority, ptr);
785*7a8a68f5SJulian Pullen 		NS_GET16(srv->weight, ptr);
786*7a8a68f5SJulian Pullen 		NS_GET16(srv->port, ptr);
787*7a8a68f5SJulian Pullen 		len = dn_expand(msg.buf, eom, ptr, srv->host,
788*7a8a68f5SJulian Pullen 		    sizeof (srv->host));
789*7a8a68f5SJulian Pullen 		if (len < 0) {
790*7a8a68f5SJulian Pullen 			logger(LOG_ERR, "DNS query invalid SRV record");
791*7a8a68f5SJulian Pullen 			return (NULL);
792*7a8a68f5SJulian Pullen 		}
793*7a8a68f5SJulian Pullen 
794*7a8a68f5SJulian Pullen 		if (rttl < *ttl)
795*7a8a68f5SJulian Pullen 			*ttl = rttl;
796*7a8a68f5SJulian Pullen 
797*7a8a68f5SJulian Pullen 		logger(LOG_DEBUG, "Found %s %d IN SRV [%d][%d] %s:%d",
798*7a8a68f5SJulian Pullen 		    namebuf, rttl, srv->priority, srv->weight, srv->host,
799*7a8a68f5SJulian Pullen 		    srv->port);
800*7a8a68f5SJulian Pullen 
801*7a8a68f5SJulian Pullen 		/* 3. move ptr to the end of current record */
802*7a8a68f5SJulian Pullen 
803*7a8a68f5SJulian Pullen 		ptr = end;
804*7a8a68f5SJulian Pullen 	}
805*7a8a68f5SJulian Pullen 
806*7a8a68f5SJulian Pullen 	if (ancount > 1)
807*7a8a68f5SJulian Pullen 		qsort(srv_res, ancount, sizeof (*srv_res),
808*7a8a68f5SJulian Pullen 		    (int (*)(const void *, const void *))srvcmp);
809*7a8a68f5SJulian Pullen 
810*7a8a68f5SJulian Pullen 	return (srv_res);
811*7a8a68f5SJulian Pullen }
812*7a8a68f5SJulian Pullen 
813*7a8a68f5SJulian Pullen 
814*7a8a68f5SJulian Pullen /*
815*7a8a68f5SJulian Pullen  * A utility function to bind to a Directory server
816*7a8a68f5SJulian Pullen  */
817*7a8a68f5SJulian Pullen 
818*7a8a68f5SJulian Pullen static LDAP*
819*7a8a68f5SJulian Pullen ldap_lookup_init(idmap_ad_disc_ds_t *ds)
820*7a8a68f5SJulian Pullen {
821*7a8a68f5SJulian Pullen 	int 	i;
822*7a8a68f5SJulian Pullen 	int	rc, ldversion;
823*7a8a68f5SJulian Pullen 	int	zero = 0;
824*7a8a68f5SJulian Pullen 	int 	timeoutms = 5 * 1000;
825*7a8a68f5SJulian Pullen 	char 	*saslmech = "GSSAPI";
826*7a8a68f5SJulian Pullen 	uint32_t saslflags = LDAP_SASL_INTERACTIVE;
827*7a8a68f5SJulian Pullen 	LDAP 	*ld = NULL;
828*7a8a68f5SJulian Pullen 
829*7a8a68f5SJulian Pullen 	for (i = 0; ds[i].host[0] != '\0'; i++) {
830*7a8a68f5SJulian Pullen 		ld = ldap_init(ds[i].host, ds[i].port);
831*7a8a68f5SJulian Pullen 		if (ld == NULL) {
832*7a8a68f5SJulian Pullen 			logger(LOG_DEBUG, "Couldn't connect to "
833*7a8a68f5SJulian Pullen 			    "AD DC %s:%d (%s)",
834*7a8a68f5SJulian Pullen 			    ds[i].host, ds[i].port,
835*7a8a68f5SJulian Pullen 			    strerror(errno));
836*7a8a68f5SJulian Pullen 			continue;
837*7a8a68f5SJulian Pullen 		}
838*7a8a68f5SJulian Pullen 
839*7a8a68f5SJulian Pullen 		ldversion = LDAP_VERSION3;
840*7a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
841*7a8a68f5SJulian Pullen 		    &ldversion);
842*7a8a68f5SJulian Pullen 
843*7a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS,
844*7a8a68f5SJulian Pullen 		    LDAP_OPT_OFF);
845*7a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &zero);
846*7a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &zero);
847*7a8a68f5SJulian Pullen 		/* setup TCP/IP connect timeout */
848*7a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT,
849*7a8a68f5SJulian Pullen 		    &timeoutms);
850*7a8a68f5SJulian Pullen 		(void) ldap_set_option(ld, LDAP_OPT_RESTART,
851*7a8a68f5SJulian Pullen 		    LDAP_OPT_ON);
852*7a8a68f5SJulian Pullen 
853*7a8a68f5SJulian Pullen 		rc = ldap_sasl_interactive_bind_s(ld, "" /* binddn */,
854*7a8a68f5SJulian Pullen 		    saslmech, NULL, NULL, saslflags, &saslcallback,
855*7a8a68f5SJulian Pullen 		    NULL /* defaults */);
856*7a8a68f5SJulian Pullen 		if (rc == LDAP_SUCCESS)
857*7a8a68f5SJulian Pullen 			break;
858*7a8a68f5SJulian Pullen 
859*7a8a68f5SJulian Pullen 		logger(LOG_INFO, "LDAP SASL bind to %s:%d failed (%s)",
860*7a8a68f5SJulian Pullen 		    ds[i].host, ds[i].port, ldap_err2string(rc));
861*7a8a68f5SJulian Pullen 		(void) ldap_unbind(ld);
862*7a8a68f5SJulian Pullen 		ld = NULL;
863*7a8a68f5SJulian Pullen 	}
864*7a8a68f5SJulian Pullen 	return (ld);
865*7a8a68f5SJulian Pullen }
866*7a8a68f5SJulian Pullen 
867*7a8a68f5SJulian Pullen 
868*7a8a68f5SJulian Pullen 
869*7a8a68f5SJulian Pullen /*
870*7a8a68f5SJulian Pullen  * A utility function to get the value of some attribute of one of one
871*7a8a68f5SJulian Pullen  * or more AD LDAP objects named by the dn_list; first found one wins.
872*7a8a68f5SJulian Pullen  */
873*7a8a68f5SJulian Pullen static char *
874*7a8a68f5SJulian Pullen ldap_lookup_entry_attr(LDAP **ld, idmap_ad_disc_ds_t *domainControllers,
875*7a8a68f5SJulian Pullen 			char **dn_list, char *attr)
876*7a8a68f5SJulian Pullen {
877*7a8a68f5SJulian Pullen 	int 	i;
878*7a8a68f5SJulian Pullen 	int	rc;
879*7a8a68f5SJulian Pullen 	int	scope = LDAP_SCOPE_BASE;
880*7a8a68f5SJulian Pullen 	char	*attrs[2];
881*7a8a68f5SJulian Pullen 	LDAPMessage *results = NULL;
882*7a8a68f5SJulian Pullen 	LDAPMessage *entry;
883*7a8a68f5SJulian Pullen 	char	**values = NULL;
884*7a8a68f5SJulian Pullen 	char	*val = NULL;
885*7a8a68f5SJulian Pullen 
886*7a8a68f5SJulian Pullen 	attrs[0] = attr;
887*7a8a68f5SJulian Pullen 	attrs[1] = NULL;
888*7a8a68f5SJulian Pullen 
889*7a8a68f5SJulian Pullen 	if (*ld == NULL)
890*7a8a68f5SJulian Pullen 		*ld = ldap_lookup_init(domainControllers);
891*7a8a68f5SJulian Pullen 
892*7a8a68f5SJulian Pullen 	if (*ld == NULL)
893*7a8a68f5SJulian Pullen 		return (NULL);
894*7a8a68f5SJulian Pullen 
895*7a8a68f5SJulian Pullen 	for (i = 0; dn_list[i] != NULL; i++) {
896*7a8a68f5SJulian Pullen 		rc = ldap_search_s(*ld, dn_list[i], scope,
897*7a8a68f5SJulian Pullen 		    "(objectclass=*)", attrs, 0, &results);
898*7a8a68f5SJulian Pullen 		if (rc == LDAP_SUCCESS) {
899*7a8a68f5SJulian Pullen 			for (entry = ldap_first_entry(*ld, results);
900*7a8a68f5SJulian Pullen 			    entry != NULL && values == NULL;
901*7a8a68f5SJulian Pullen 			    entry = ldap_next_entry(*ld, entry)) {
902*7a8a68f5SJulian Pullen 				values = ldap_get_values(
903*7a8a68f5SJulian Pullen 				    *ld, entry, attr);
904*7a8a68f5SJulian Pullen 			}
905*7a8a68f5SJulian Pullen 
906*7a8a68f5SJulian Pullen 			if (values != NULL) {
907*7a8a68f5SJulian Pullen 				(void) ldap_msgfree(results);
908*7a8a68f5SJulian Pullen 				val = strdup(values[0]);
909*7a8a68f5SJulian Pullen 				ldap_value_free(values);
910*7a8a68f5SJulian Pullen 				return (val);
911*7a8a68f5SJulian Pullen 			}
912*7a8a68f5SJulian Pullen 		}
913*7a8a68f5SJulian Pullen 		if (results != NULL) {
914*7a8a68f5SJulian Pullen 			(void) ldap_msgfree(results);
915*7a8a68f5SJulian Pullen 			results = NULL;
916*7a8a68f5SJulian Pullen 		}
917*7a8a68f5SJulian Pullen 	}
918*7a8a68f5SJulian Pullen 
919*7a8a68f5SJulian Pullen 	return (NULL);
920*7a8a68f5SJulian Pullen }
921*7a8a68f5SJulian Pullen 
922*7a8a68f5SJulian Pullen 
923*7a8a68f5SJulian Pullen /*
924*7a8a68f5SJulian Pullen  * Lookup the trusted domains in the global catalog.
925*7a8a68f5SJulian Pullen  *
926*7a8a68f5SJulian Pullen  * Returns:
927*7a8a68f5SJulian Pullen  *	array of trusted domains which is terminated by
928*7a8a68f5SJulian Pullen  *		an empty trusted domain.
929*7a8a68f5SJulian Pullen  *	NULL an error occured
930*7a8a68f5SJulian Pullen  */
931*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *
932*7a8a68f5SJulian Pullen ldap_lookup_trusted_domains(LDAP **ld, idmap_ad_disc_ds_t *globalCatalog,
933*7a8a68f5SJulian Pullen 			char *base_dn)
934*7a8a68f5SJulian Pullen {
935*7a8a68f5SJulian Pullen 	int		scope = LDAP_SCOPE_SUBTREE;
936*7a8a68f5SJulian Pullen 	char		*attrs[3];
937*7a8a68f5SJulian Pullen 	int		rc;
938*7a8a68f5SJulian Pullen 	LDAPMessage	*results = NULL;
939*7a8a68f5SJulian Pullen 	LDAPMessage	*entry;
940*7a8a68f5SJulian Pullen 	char		*filter;
941*7a8a68f5SJulian Pullen 	char		**partner = NULL;
942*7a8a68f5SJulian Pullen 	char		**direction = NULL;
943*7a8a68f5SJulian Pullen 	int		num = 0;
944*7a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *trusted_domains = NULL;
945*7a8a68f5SJulian Pullen 
946*7a8a68f5SJulian Pullen 
947*7a8a68f5SJulian Pullen 	if (*ld == NULL)
948*7a8a68f5SJulian Pullen 		*ld = ldap_lookup_init(globalCatalog);
949*7a8a68f5SJulian Pullen 
950*7a8a68f5SJulian Pullen 	if (*ld == NULL)
951*7a8a68f5SJulian Pullen 		return (NULL);
952*7a8a68f5SJulian Pullen 
953*7a8a68f5SJulian Pullen 	attrs[0] = "trustPartner";
954*7a8a68f5SJulian Pullen 	attrs[1] = "trustDirection";
955*7a8a68f5SJulian Pullen 	attrs[2] = NULL;
956*7a8a68f5SJulian Pullen 
957*7a8a68f5SJulian Pullen 	/* trustDirection values - inbound = 1 and bidirectional = 3 */
958*7a8a68f5SJulian Pullen 	filter = "(&(objectclass=trustedDomain)"
959*7a8a68f5SJulian Pullen 	    "(|(trustDirection=3)(trustDirection=1)))";
960*7a8a68f5SJulian Pullen 
961*7a8a68f5SJulian Pullen 	rc = ldap_search_s(*ld, base_dn, scope, filter, attrs, 0, &results);
962*7a8a68f5SJulian Pullen 	if (rc == LDAP_SUCCESS) {
963*7a8a68f5SJulian Pullen 		for (entry = ldap_first_entry(*ld, results);
964*7a8a68f5SJulian Pullen 		    entry != NULL; entry = ldap_next_entry(*ld, entry)) {
965*7a8a68f5SJulian Pullen 			partner = ldap_get_values(*ld, entry, "trustPartner");
966*7a8a68f5SJulian Pullen 			direction = ldap_get_values(
967*7a8a68f5SJulian Pullen 			    *ld, entry, "trustDirection");
968*7a8a68f5SJulian Pullen 
969*7a8a68f5SJulian Pullen 			if (partner != NULL && direction != NULL) {
970*7a8a68f5SJulian Pullen 				num++;
971*7a8a68f5SJulian Pullen 				trusted_domains = realloc(trusted_domains,
972*7a8a68f5SJulian Pullen 				    (num + 1) *
973*7a8a68f5SJulian Pullen 				    sizeof (ad_disc_trusteddomains_t));
974*7a8a68f5SJulian Pullen 				if (trusted_domains == NULL) {
975*7a8a68f5SJulian Pullen 					ldap_value_free(partner);
976*7a8a68f5SJulian Pullen 					ldap_value_free(direction);
977*7a8a68f5SJulian Pullen 					ldap_msgfree(results);
978*7a8a68f5SJulian Pullen 					return (NULL);
979*7a8a68f5SJulian Pullen 				}
980*7a8a68f5SJulian Pullen 				/* Last element should be zero */
981*7a8a68f5SJulian Pullen 				memset(&trusted_domains[num], 0,
982*7a8a68f5SJulian Pullen 				    sizeof (ad_disc_trusteddomains_t));
983*7a8a68f5SJulian Pullen 				strcpy(trusted_domains[num - 1].domain,
984*7a8a68f5SJulian Pullen 				    partner[0]);
985*7a8a68f5SJulian Pullen 				trusted_domains[num - 1].direction =
986*7a8a68f5SJulian Pullen 				    atoi(direction[0]);
987*7a8a68f5SJulian Pullen 			}
988*7a8a68f5SJulian Pullen 			if (partner != NULL)
989*7a8a68f5SJulian Pullen 				ldap_value_free(partner);
990*7a8a68f5SJulian Pullen 			if (direction != NULL)
991*7a8a68f5SJulian Pullen 				ldap_value_free(direction);
992*7a8a68f5SJulian Pullen 		}
993*7a8a68f5SJulian Pullen 	} else if (rc == LDAP_NO_RESULTS_RETURNED) {
994*7a8a68f5SJulian Pullen 		/* This is not an error - return empty trusted domain */
995*7a8a68f5SJulian Pullen 		trusted_domains = calloc(1, sizeof (ad_disc_trusteddomains_t));
996*7a8a68f5SJulian Pullen 	}
997*7a8a68f5SJulian Pullen 	if (results != NULL)
998*7a8a68f5SJulian Pullen 		ldap_msgfree(results);
999*7a8a68f5SJulian Pullen 
1000*7a8a68f5SJulian Pullen 	return (trusted_domains);
1001*7a8a68f5SJulian Pullen }
1002*7a8a68f5SJulian Pullen 
1003*7a8a68f5SJulian Pullen 
1004*7a8a68f5SJulian Pullen /*
1005*7a8a68f5SJulian Pullen  * This functions finds all the domains in a forest.
1006*7a8a68f5SJulian Pullen  * It first finds all the naming contexts by finding the
1007*7a8a68f5SJulian Pullen  * root DSE attribute namingContext. For each naming context
1008*7a8a68f5SJulian Pullen  * it performes an entry search looking for Domain object class
1009*7a8a68f5SJulian Pullen  * returning the attribute objectSid.
1010*7a8a68f5SJulian Pullen  */
1011*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *
1012*7a8a68f5SJulian Pullen ldap_lookup_domains_in_forest(LDAP **ld, idmap_ad_disc_ds_t *globalCatalogs)
1013*7a8a68f5SJulian Pullen {
1014*7a8a68f5SJulian Pullen 	int		scope = LDAP_SCOPE_BASE;
1015*7a8a68f5SJulian Pullen 	char		*attrs[2];
1016*7a8a68f5SJulian Pullen 	char		*root_attrs[2];
1017*7a8a68f5SJulian Pullen 	int		rc;
1018*7a8a68f5SJulian Pullen 	LDAPMessage	*result = NULL;
1019*7a8a68f5SJulian Pullen 	LDAPMessage	*entry;
1020*7a8a68f5SJulian Pullen 	char		*filter;
1021*7a8a68f5SJulian Pullen 	char		**nc = NULL;
1022*7a8a68f5SJulian Pullen 	struct berval	**sid_ber;
1023*7a8a68f5SJulian Pullen 	int		num = 0;
1024*7a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *domains = NULL;
1025*7a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *tmp;
1026*7a8a68f5SJulian Pullen 	int		i;
1027*7a8a68f5SJulian Pullen 	char 		*name;
1028*7a8a68f5SJulian Pullen 	adutils_sid_t	sid;
1029*7a8a68f5SJulian Pullen 	char		*sid_str;
1030*7a8a68f5SJulian Pullen 
1031*7a8a68f5SJulian Pullen 
1032*7a8a68f5SJulian Pullen 	if (*ld == NULL)
1033*7a8a68f5SJulian Pullen 		*ld = ldap_lookup_init(globalCatalogs);
1034*7a8a68f5SJulian Pullen 
1035*7a8a68f5SJulian Pullen 	if (*ld == NULL)
1036*7a8a68f5SJulian Pullen 		return (NULL);
1037*7a8a68f5SJulian Pullen 
1038*7a8a68f5SJulian Pullen 	root_attrs[0] = "namingContexts";
1039*7a8a68f5SJulian Pullen 	root_attrs[1] = NULL;
1040*7a8a68f5SJulian Pullen 
1041*7a8a68f5SJulian Pullen 	attrs[0] = "objectSid";
1042*7a8a68f5SJulian Pullen 	attrs[1] = NULL;
1043*7a8a68f5SJulian Pullen 
1044*7a8a68f5SJulian Pullen 	filter = "(objectclass=Domain)";
1045*7a8a68f5SJulian Pullen 
1046*7a8a68f5SJulian Pullen 	/* Find naming contexts */
1047*7a8a68f5SJulian Pullen 	rc = ldap_search_s(*ld, LDAP_ROOT_DSE, scope, "(objectClass=*)",
1048*7a8a68f5SJulian Pullen 	    root_attrs, 0, &result);
1049*7a8a68f5SJulian Pullen 	if (rc == LDAP_SUCCESS) {
1050*7a8a68f5SJulian Pullen 		entry = ldap_first_entry(*ld, result);
1051*7a8a68f5SJulian Pullen 		if (entry != NULL) {
1052*7a8a68f5SJulian Pullen 			nc = ldap_get_values(*ld, entry, "namingContexts");
1053*7a8a68f5SJulian Pullen 		}
1054*7a8a68f5SJulian Pullen 	}
1055*7a8a68f5SJulian Pullen 	if (result != NULL)
1056*7a8a68f5SJulian Pullen 		ldap_msgfree(result);
1057*7a8a68f5SJulian Pullen 	if (nc == NULL)
1058*7a8a68f5SJulian Pullen 		return (NULL);
1059*7a8a68f5SJulian Pullen 
1060*7a8a68f5SJulian Pullen 	/* Find domains */
1061*7a8a68f5SJulian Pullen 	for (i = 0; nc[i] != NULL; i++) {
1062*7a8a68f5SJulian Pullen 		rc = ldap_search_s(*ld, nc[i], scope, filter, attrs, 0,
1063*7a8a68f5SJulian Pullen 		    &result);
1064*7a8a68f5SJulian Pullen 		if (rc == LDAP_SUCCESS) {
1065*7a8a68f5SJulian Pullen 			entry = ldap_first_entry(*ld, result);
1066*7a8a68f5SJulian Pullen 			if (entry != NULL) {
1067*7a8a68f5SJulian Pullen 				sid_ber = ldap_get_values_len(*ld, entry,
1068*7a8a68f5SJulian Pullen 				    "objectSid");
1069*7a8a68f5SJulian Pullen 				if (sid_ber != NULL) {
1070*7a8a68f5SJulian Pullen 					num++;
1071*7a8a68f5SJulian Pullen 					tmp = realloc(domains,
1072*7a8a68f5SJulian Pullen 					    (num + 1) *
1073*7a8a68f5SJulian Pullen 					    sizeof (ad_disc_domainsinforest_t));
1074*7a8a68f5SJulian Pullen 					if (tmp == NULL) {
1075*7a8a68f5SJulian Pullen 						if (domains != NULL)
1076*7a8a68f5SJulian Pullen 							free(domains);
1077*7a8a68f5SJulian Pullen 						ldap_value_free_len(sid_ber);
1078*7a8a68f5SJulian Pullen 						ldap_msgfree(result);
1079*7a8a68f5SJulian Pullen 						ldap_value_free(nc);
1080*7a8a68f5SJulian Pullen 						return (NULL);
1081*7a8a68f5SJulian Pullen 					}
1082*7a8a68f5SJulian Pullen 					domains = tmp;
1083*7a8a68f5SJulian Pullen 					memset(&domains[num], 0,
1084*7a8a68f5SJulian Pullen 					    sizeof (ad_disc_domainsinforest_t));
1085*7a8a68f5SJulian Pullen 
1086*7a8a68f5SJulian Pullen 					if (adutils_getsid(sid_ber[0], &sid)
1087*7a8a68f5SJulian Pullen 					    < 0) {
1088*7a8a68f5SJulian Pullen 						free(domains);
1089*7a8a68f5SJulian Pullen 						ldap_value_free_len(sid_ber);
1090*7a8a68f5SJulian Pullen 						ldap_msgfree(result);
1091*7a8a68f5SJulian Pullen 						ldap_value_free(nc);
1092*7a8a68f5SJulian Pullen 						return (NULL);
1093*7a8a68f5SJulian Pullen 					}
1094*7a8a68f5SJulian Pullen 					if ((sid_str = adutils_sid2txt(&sid))
1095*7a8a68f5SJulian Pullen 					    == NULL) {
1096*7a8a68f5SJulian Pullen 						free(domains);
1097*7a8a68f5SJulian Pullen 						ldap_value_free_len(sid_ber);
1098*7a8a68f5SJulian Pullen 						ldap_msgfree(result);
1099*7a8a68f5SJulian Pullen 						ldap_value_free(nc);
1100*7a8a68f5SJulian Pullen 						return (NULL);
1101*7a8a68f5SJulian Pullen 					}
1102*7a8a68f5SJulian Pullen 
1103*7a8a68f5SJulian Pullen 					ldap_value_free_len(sid_ber);
1104*7a8a68f5SJulian Pullen 					strcpy(domains[num - 1].sid, sid_str);
1105*7a8a68f5SJulian Pullen 					free(sid_str);
1106*7a8a68f5SJulian Pullen 
1107*7a8a68f5SJulian Pullen 					name = DN_to_DNS(nc[i]);
1108*7a8a68f5SJulian Pullen 					if (name == NULL) {
1109*7a8a68f5SJulian Pullen 						free(domains);
1110*7a8a68f5SJulian Pullen 						ldap_msgfree(result);
1111*7a8a68f5SJulian Pullen 						ldap_value_free(nc);
1112*7a8a68f5SJulian Pullen 						return (NULL);
1113*7a8a68f5SJulian Pullen 					}
1114*7a8a68f5SJulian Pullen 					strcpy(domains[num - 1].domain, name);
1115*7a8a68f5SJulian Pullen 					free(name);
1116*7a8a68f5SJulian Pullen 				}
1117*7a8a68f5SJulian Pullen 			}
1118*7a8a68f5SJulian Pullen 		}
1119*7a8a68f5SJulian Pullen 		if (result != NULL)
1120*7a8a68f5SJulian Pullen 			ldap_msgfree(result);
1121*7a8a68f5SJulian Pullen 	}
1122*7a8a68f5SJulian Pullen 	ldap_value_free(nc);
1123*7a8a68f5SJulian Pullen 
1124*7a8a68f5SJulian Pullen 	return (domains);
1125*7a8a68f5SJulian Pullen }
1126*7a8a68f5SJulian Pullen 
1127*7a8a68f5SJulian Pullen 
1128*7a8a68f5SJulian Pullen ad_disc_t
1129*7a8a68f5SJulian Pullen ad_disc_init(void)
1130*7a8a68f5SJulian Pullen {
1131*7a8a68f5SJulian Pullen 	struct ad_disc *ctx;
1132*7a8a68f5SJulian Pullen 	ctx = calloc(1, sizeof (struct ad_disc));
1133*7a8a68f5SJulian Pullen 	if (ctx != NULL)
1134*7a8a68f5SJulian Pullen 		DO_RES_NINIT(ctx);
1135*7a8a68f5SJulian Pullen 
1136*7a8a68f5SJulian Pullen 	ctx->domain_name.type = AD_STRING;
1137*7a8a68f5SJulian Pullen 	ctx->domain_controller.type = AD_DIRECTORY;
1138*7a8a68f5SJulian Pullen 	ctx->site_name.type = AD_STRING;
1139*7a8a68f5SJulian Pullen 	ctx->forest_name.type = AD_STRING;
1140*7a8a68f5SJulian Pullen 	ctx->global_catalog.type = AD_DIRECTORY;
1141*7a8a68f5SJulian Pullen 	ctx->domains_in_forest.type = AD_DOMAINS_IN_FOREST;
1142*7a8a68f5SJulian Pullen 	ctx->trusted_domains.type = AD_TRUSTED_DOMAINS;
1143*7a8a68f5SJulian Pullen 	/* Site specific versions */
1144*7a8a68f5SJulian Pullen 	ctx->site_domain_controller.type = AD_DIRECTORY;
1145*7a8a68f5SJulian Pullen 	ctx->site_global_catalog.type = AD_DIRECTORY;
1146*7a8a68f5SJulian Pullen 	return (ctx);
1147*7a8a68f5SJulian Pullen }
1148*7a8a68f5SJulian Pullen 
1149*7a8a68f5SJulian Pullen 
1150*7a8a68f5SJulian Pullen void
1151*7a8a68f5SJulian Pullen ad_disc_fini(ad_disc_t ctx)
1152*7a8a68f5SJulian Pullen {
1153*7a8a68f5SJulian Pullen 	if (ctx == NULL)
1154*7a8a68f5SJulian Pullen 		return;
1155*7a8a68f5SJulian Pullen 
1156*7a8a68f5SJulian Pullen 	if (ctx->res_ninitted)
1157*7a8a68f5SJulian Pullen 		res_ndestroy(&ctx->res_state);
1158*7a8a68f5SJulian Pullen 
1159*7a8a68f5SJulian Pullen 	if (ctx->subnets != NULL)
1160*7a8a68f5SJulian Pullen 		free(ctx->subnets);
1161*7a8a68f5SJulian Pullen 
1162*7a8a68f5SJulian Pullen 	if (ctx->domain_name.value != NULL)
1163*7a8a68f5SJulian Pullen 		free(ctx->domain_name.value);
1164*7a8a68f5SJulian Pullen 
1165*7a8a68f5SJulian Pullen 	if (ctx->domain_controller.value != NULL)
1166*7a8a68f5SJulian Pullen 		free(ctx->domain_controller.value);
1167*7a8a68f5SJulian Pullen 
1168*7a8a68f5SJulian Pullen 	if (ctx->site_name.value != NULL)
1169*7a8a68f5SJulian Pullen 		free(ctx->site_name.value);
1170*7a8a68f5SJulian Pullen 
1171*7a8a68f5SJulian Pullen 	if (ctx->forest_name.value != NULL)
1172*7a8a68f5SJulian Pullen 		free(ctx->forest_name.value);
1173*7a8a68f5SJulian Pullen 
1174*7a8a68f5SJulian Pullen 	if (ctx->global_catalog.value != NULL)
1175*7a8a68f5SJulian Pullen 		free(ctx->global_catalog.value);
1176*7a8a68f5SJulian Pullen 
1177*7a8a68f5SJulian Pullen 	if (ctx->domains_in_forest.value != NULL)
1178*7a8a68f5SJulian Pullen 		free(ctx->domains_in_forest.value);
1179*7a8a68f5SJulian Pullen 
1180*7a8a68f5SJulian Pullen 	if (ctx->trusted_domains.value != NULL)
1181*7a8a68f5SJulian Pullen 		free(ctx->trusted_domains.value);
1182*7a8a68f5SJulian Pullen 
1183*7a8a68f5SJulian Pullen 	/* Site specific versions */
1184*7a8a68f5SJulian Pullen 	if (ctx->site_domain_controller.value != NULL)
1185*7a8a68f5SJulian Pullen 		free(ctx->site_domain_controller.value);
1186*7a8a68f5SJulian Pullen 
1187*7a8a68f5SJulian Pullen 	if (ctx->site_global_catalog.value != NULL)
1188*7a8a68f5SJulian Pullen 		free(ctx->site_global_catalog.value);
1189*7a8a68f5SJulian Pullen 
1190*7a8a68f5SJulian Pullen 	free(ctx);
1191*7a8a68f5SJulian Pullen }
1192*7a8a68f5SJulian Pullen 
1193*7a8a68f5SJulian Pullen void
1194*7a8a68f5SJulian Pullen ad_disc_refresh(ad_disc_t ctx)
1195*7a8a68f5SJulian Pullen {
1196*7a8a68f5SJulian Pullen 	if (ctx->res_ninitted)
1197*7a8a68f5SJulian Pullen 		res_ndestroy(&ctx->res_state);
1198*7a8a68f5SJulian Pullen 	(void) memset(&ctx->res_state, 0, sizeof (ctx->res_state));
1199*7a8a68f5SJulian Pullen 	ctx->res_ninitted = res_ninit(&ctx->res_state) != -1;
1200*7a8a68f5SJulian Pullen 
1201*7a8a68f5SJulian Pullen 	if (ctx->domain_name.state == AD_STATE_AUTO)
1202*7a8a68f5SJulian Pullen 		ctx->domain_name.state = AD_STATE_INVALID;
1203*7a8a68f5SJulian Pullen 
1204*7a8a68f5SJulian Pullen 	if (ctx->domain_controller.state == AD_STATE_AUTO)
1205*7a8a68f5SJulian Pullen 		ctx->domain_controller.state  = AD_STATE_INVALID;
1206*7a8a68f5SJulian Pullen 
1207*7a8a68f5SJulian Pullen 	if (ctx->site_name.state == AD_STATE_AUTO)
1208*7a8a68f5SJulian Pullen 		ctx->site_name.state = AD_STATE_INVALID;
1209*7a8a68f5SJulian Pullen 
1210*7a8a68f5SJulian Pullen 	if (ctx->forest_name.state == AD_STATE_AUTO)
1211*7a8a68f5SJulian Pullen 		ctx->forest_name.state = AD_STATE_INVALID;
1212*7a8a68f5SJulian Pullen 
1213*7a8a68f5SJulian Pullen 	if (ctx->global_catalog.state == AD_STATE_AUTO)
1214*7a8a68f5SJulian Pullen 		ctx->global_catalog.state = AD_STATE_INVALID;
1215*7a8a68f5SJulian Pullen 
1216*7a8a68f5SJulian Pullen 	if (ctx->domains_in_forest.state == AD_STATE_AUTO)
1217*7a8a68f5SJulian Pullen 		ctx->domains_in_forest.state  = AD_STATE_INVALID;
1218*7a8a68f5SJulian Pullen 
1219*7a8a68f5SJulian Pullen 	if (ctx->trusted_domains.state == AD_STATE_AUTO)
1220*7a8a68f5SJulian Pullen 		ctx->trusted_domains.state  = AD_STATE_INVALID;
1221*7a8a68f5SJulian Pullen 
1222*7a8a68f5SJulian Pullen 	if (ctx->site_domain_controller.state == AD_STATE_AUTO)
1223*7a8a68f5SJulian Pullen 		ctx->site_domain_controller.state  = AD_STATE_INVALID;
1224*7a8a68f5SJulian Pullen 
1225*7a8a68f5SJulian Pullen 	if (ctx->site_global_catalog.state == AD_STATE_AUTO)
1226*7a8a68f5SJulian Pullen 		ctx->site_global_catalog.state = AD_STATE_INVALID;
1227*7a8a68f5SJulian Pullen }
1228*7a8a68f5SJulian Pullen 
1229*7a8a68f5SJulian Pullen 
1230*7a8a68f5SJulian Pullen 
1231*7a8a68f5SJulian Pullen /* Discover joined Active Directory domainName */
1232*7a8a68f5SJulian Pullen static ad_item_t *
1233*7a8a68f5SJulian Pullen validate_DomainName(ad_disc_t ctx)
1234*7a8a68f5SJulian Pullen {
1235*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *domain_controller = NULL;
1236*7a8a68f5SJulian Pullen 	char *dname, *srvname;
1237*7a8a68f5SJulian Pullen 	uint32_t ttl = 0;
1238*7a8a68f5SJulian Pullen 
1239*7a8a68f5SJulian Pullen 	if (is_valid(&ctx->domain_name))
1240*7a8a68f5SJulian Pullen 		return (&ctx->domain_name);
1241*7a8a68f5SJulian Pullen 
1242*7a8a68f5SJulian Pullen 
1243*7a8a68f5SJulian Pullen 	/* Try to find our domain by searching for DCs for it */
1244*7a8a68f5SJulian Pullen 	DO_RES_NINIT(ctx);
1245*7a8a68f5SJulian Pullen 	domain_controller = srv_query(&ctx->res_state, LDAP_SRV_HEAD
1246*7a8a68f5SJulian Pullen 	    DC_SRV_TAIL, ctx->domain_name.value, &srvname, &ttl);
1247*7a8a68f5SJulian Pullen 
1248*7a8a68f5SJulian Pullen 	/*
1249*7a8a68f5SJulian Pullen 	 * If we can't find DCs by via res_nsearch() then there's no
1250*7a8a68f5SJulian Pullen 	 * point in trying anything else to discover the AD domain name.
1251*7a8a68f5SJulian Pullen 	 */
1252*7a8a68f5SJulian Pullen 	if (domain_controller == NULL)
1253*7a8a68f5SJulian Pullen 		return (NULL);
1254*7a8a68f5SJulian Pullen 
1255*7a8a68f5SJulian Pullen 	free(domain_controller);
1256*7a8a68f5SJulian Pullen 	/*
1257*7a8a68f5SJulian Pullen 	 * We have the FQDN of the SRV RR name, so now we extract the
1258*7a8a68f5SJulian Pullen 	 * domainname suffix from it.
1259*7a8a68f5SJulian Pullen 	 */
1260*7a8a68f5SJulian Pullen 	dname = strdup(srvname + strlen(LDAP_SRV_HEAD DC_SRV_TAIL) +
1261*7a8a68f5SJulian Pullen 	    1 /* for the dot between RR name and domainname */);
1262*7a8a68f5SJulian Pullen 
1263*7a8a68f5SJulian Pullen 	free(srvname);
1264*7a8a68f5SJulian Pullen 
1265*7a8a68f5SJulian Pullen 	if (dname == NULL) {
1266*7a8a68f5SJulian Pullen 		logger(LOG_ERR, "Out of memory");
1267*7a8a68f5SJulian Pullen 		return (NULL);
1268*7a8a68f5SJulian Pullen 	}
1269*7a8a68f5SJulian Pullen 
1270*7a8a68f5SJulian Pullen 	/* Eat any trailing dot */
1271*7a8a68f5SJulian Pullen 	if (*(dname + strlen(dname)) == '.')
1272*7a8a68f5SJulian Pullen 		*(dname + strlen(dname)) = '\0';
1273*7a8a68f5SJulian Pullen 
1274*7a8a68f5SJulian Pullen 	update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl);
1275*7a8a68f5SJulian Pullen 
1276*7a8a68f5SJulian Pullen 	return (&ctx->domain_name);
1277*7a8a68f5SJulian Pullen }
1278*7a8a68f5SJulian Pullen 
1279*7a8a68f5SJulian Pullen 
1280*7a8a68f5SJulian Pullen char *
1281*7a8a68f5SJulian Pullen ad_disc_get_DomainName(ad_disc_t ctx, boolean_t *auto_discovered)
1282*7a8a68f5SJulian Pullen {
1283*7a8a68f5SJulian Pullen 	char *domain_name = NULL;
1284*7a8a68f5SJulian Pullen 	ad_item_t *domain_name_item;
1285*7a8a68f5SJulian Pullen 
1286*7a8a68f5SJulian Pullen 	domain_name_item = validate_DomainName(ctx);
1287*7a8a68f5SJulian Pullen 
1288*7a8a68f5SJulian Pullen 	if (domain_name_item) {
1289*7a8a68f5SJulian Pullen 		domain_name = strdup(domain_name_item->value);
1290*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1291*7a8a68f5SJulian Pullen 			*auto_discovered =
1292*7a8a68f5SJulian Pullen 			    (domain_name_item->state == AD_STATE_AUTO);
1293*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1294*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1295*7a8a68f5SJulian Pullen 
1296*7a8a68f5SJulian Pullen 	return (domain_name);
1297*7a8a68f5SJulian Pullen }
1298*7a8a68f5SJulian Pullen 
1299*7a8a68f5SJulian Pullen 
1300*7a8a68f5SJulian Pullen /* Discover domain controllers */
1301*7a8a68f5SJulian Pullen static ad_item_t *
1302*7a8a68f5SJulian Pullen validate_DomainController(ad_disc_t ctx, enum ad_disc_req req)
1303*7a8a68f5SJulian Pullen {
1304*7a8a68f5SJulian Pullen 	uint32_t ttl = 0;
1305*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *domain_controller = NULL;
1306*7a8a68f5SJulian Pullen 	boolean_t validate_global = B_FALSE;
1307*7a8a68f5SJulian Pullen 	boolean_t validate_site = B_FALSE;
1308*7a8a68f5SJulian Pullen 	ad_item_t *domain_name_item;
1309*7a8a68f5SJulian Pullen 	ad_item_t *site_name_item = NULL;
1310*7a8a68f5SJulian Pullen 
1311*7a8a68f5SJulian Pullen 	/* If the values is fixed there will not be a site specific version */
1312*7a8a68f5SJulian Pullen 	if (is_fixed(&ctx->domain_controller))
1313*7a8a68f5SJulian Pullen 		return (&ctx->domain_controller);
1314*7a8a68f5SJulian Pullen 
1315*7a8a68f5SJulian Pullen 	domain_name_item = validate_DomainName(ctx);
1316*7a8a68f5SJulian Pullen 	if (domain_name_item == NULL)
1317*7a8a68f5SJulian Pullen 		return (NULL);
1318*7a8a68f5SJulian Pullen 
1319*7a8a68f5SJulian Pullen 	if (req == AD_DISC_GLOBAL)
1320*7a8a68f5SJulian Pullen 		validate_global = B_TRUE;
1321*7a8a68f5SJulian Pullen 	else {
1322*7a8a68f5SJulian Pullen 		site_name_item = validate_SiteName(ctx);
1323*7a8a68f5SJulian Pullen 		if (site_name_item != NULL)
1324*7a8a68f5SJulian Pullen 			validate_site = B_TRUE;
1325*7a8a68f5SJulian Pullen 		else if (req == AD_DISC_PREFER_SITE)
1326*7a8a68f5SJulian Pullen 			validate_global = B_TRUE;
1327*7a8a68f5SJulian Pullen 	}
1328*7a8a68f5SJulian Pullen 
1329*7a8a68f5SJulian Pullen 	if (validate_global) {
1330*7a8a68f5SJulian Pullen 		if (!is_valid(&ctx->domain_controller) ||
1331*7a8a68f5SJulian Pullen 		    is_changed(&ctx->domain_controller, PARAM1,
1332*7a8a68f5SJulian Pullen 		    domain_name_item)) {
1333*7a8a68f5SJulian Pullen 			/*
1334*7a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named
1335*7a8a68f5SJulian Pullen 			 * _ldap._tcp.dc._msdcs.<DomainName>
1336*7a8a68f5SJulian Pullen 			 */
1337*7a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1338*7a8a68f5SJulian Pullen 			domain_controller = srv_query(&ctx->res_state,
1339*7a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD DC_SRV_TAIL,
1340*7a8a68f5SJulian Pullen 			    domain_name_item->value, NULL, &ttl);
1341*7a8a68f5SJulian Pullen 
1342*7a8a68f5SJulian Pullen 			if (domain_controller == NULL)
1343*7a8a68f5SJulian Pullen 				return (NULL);
1344*7a8a68f5SJulian Pullen 
1345*7a8a68f5SJulian Pullen 			update_item(&ctx->domain_controller, domain_controller,
1346*7a8a68f5SJulian Pullen 			    AD_STATE_AUTO, ttl);
1347*7a8a68f5SJulian Pullen 			update_version(&ctx->domain_controller, PARAM1,
1348*7a8a68f5SJulian Pullen 			    domain_name_item);
1349*7a8a68f5SJulian Pullen 		}
1350*7a8a68f5SJulian Pullen 		return (&ctx->domain_controller);
1351*7a8a68f5SJulian Pullen 	}
1352*7a8a68f5SJulian Pullen 
1353*7a8a68f5SJulian Pullen 	if (validate_site) {
1354*7a8a68f5SJulian Pullen 		if (!is_valid(&ctx->site_domain_controller) ||
1355*7a8a68f5SJulian Pullen 		    is_changed(&ctx->site_domain_controller, PARAM1,
1356*7a8a68f5SJulian Pullen 		    domain_name_item) ||
1357*7a8a68f5SJulian Pullen 		    is_changed(&ctx->site_domain_controller, PARAM2,
1358*7a8a68f5SJulian Pullen 		    site_name_item)) {
1359*7a8a68f5SJulian Pullen 			char rr_name[DNS_MAX_NAME];
1360*7a8a68f5SJulian Pullen 			/*
1361*7a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named
1362*7a8a68f5SJulian Pullen 			 * _ldap._tcp.<SiteName>._sites.dc._msdcs.<DomainName>
1363*7a8a68f5SJulian Pullen 			 */
1364*7a8a68f5SJulian Pullen 			(void) snprintf(rr_name, sizeof (rr_name),
1365*7a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD SITE_SRV_MIDDLE DC_SRV_TAIL,
1366*7a8a68f5SJulian Pullen 			    site_name_item->value);
1367*7a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1368*7a8a68f5SJulian Pullen 			domain_controller = srv_query(&ctx->res_state, rr_name,
1369*7a8a68f5SJulian Pullen 			    domain_name_item->value, NULL, &ttl);
1370*7a8a68f5SJulian Pullen 			if (domain_controller == NULL)
1371*7a8a68f5SJulian Pullen 				return (NULL);
1372*7a8a68f5SJulian Pullen 
1373*7a8a68f5SJulian Pullen 			update_item(&ctx->site_domain_controller,
1374*7a8a68f5SJulian Pullen 			    domain_controller, AD_STATE_AUTO, ttl);
1375*7a8a68f5SJulian Pullen 			update_version(&ctx->site_domain_controller, PARAM1,
1376*7a8a68f5SJulian Pullen 			    domain_name_item);
1377*7a8a68f5SJulian Pullen 			update_version(&ctx->site_domain_controller, PARAM2,
1378*7a8a68f5SJulian Pullen 			    site_name_item);
1379*7a8a68f5SJulian Pullen 		}
1380*7a8a68f5SJulian Pullen 		return (&ctx->site_domain_controller);
1381*7a8a68f5SJulian Pullen 	}
1382*7a8a68f5SJulian Pullen 	return (NULL);
1383*7a8a68f5SJulian Pullen }
1384*7a8a68f5SJulian Pullen 
1385*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *
1386*7a8a68f5SJulian Pullen ad_disc_get_DomainController(ad_disc_t ctx, enum ad_disc_req req,
1387*7a8a68f5SJulian Pullen 			boolean_t *auto_discovered)
1388*7a8a68f5SJulian Pullen {
1389*7a8a68f5SJulian Pullen 	ad_item_t *domain_controller_item;
1390*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *domain_controller = NULL;
1391*7a8a68f5SJulian Pullen 
1392*7a8a68f5SJulian Pullen 	domain_controller_item = validate_DomainController(ctx, req);
1393*7a8a68f5SJulian Pullen 
1394*7a8a68f5SJulian Pullen 	if (domain_controller_item != NULL) {
1395*7a8a68f5SJulian Pullen 		domain_controller = ds_dup(domain_controller_item->value);
1396*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1397*7a8a68f5SJulian Pullen 			*auto_discovered =
1398*7a8a68f5SJulian Pullen 			    (domain_controller_item->state == AD_STATE_AUTO);
1399*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1400*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1401*7a8a68f5SJulian Pullen 
1402*7a8a68f5SJulian Pullen 	return (domain_controller);
1403*7a8a68f5SJulian Pullen }
1404*7a8a68f5SJulian Pullen 
1405*7a8a68f5SJulian Pullen 
1406*7a8a68f5SJulian Pullen /* Discover site name (for multi-homed systems the first one found wins) */
1407*7a8a68f5SJulian Pullen static ad_item_t *
1408*7a8a68f5SJulian Pullen validate_SiteName(ad_disc_t ctx)
1409*7a8a68f5SJulian Pullen {
1410*7a8a68f5SJulian Pullen 	LDAP *ld = NULL;
1411*7a8a68f5SJulian Pullen 	ad_subnet_t *subnets = NULL;
1412*7a8a68f5SJulian Pullen 	char **dn_subnets = NULL;
1413*7a8a68f5SJulian Pullen 	char *dn_root[2];
1414*7a8a68f5SJulian Pullen 	char *config_naming_context = NULL;
1415*7a8a68f5SJulian Pullen 	char *site_object = NULL;
1416*7a8a68f5SJulian Pullen 	char *site_name = NULL;
1417*7a8a68f5SJulian Pullen 	char *forest_name;
1418*7a8a68f5SJulian Pullen 	int len;
1419*7a8a68f5SJulian Pullen 	int i;
1420*7a8a68f5SJulian Pullen 	boolean_t update_required = B_FALSE;
1421*7a8a68f5SJulian Pullen 	ad_item_t *domain_controller_item;
1422*7a8a68f5SJulian Pullen 
1423*7a8a68f5SJulian Pullen 	if (is_fixed(&ctx->site_name))
1424*7a8a68f5SJulian Pullen 		return (&ctx->site_name);
1425*7a8a68f5SJulian Pullen 
1426*7a8a68f5SJulian Pullen 	/* Can't rely on site-specific DCs */
1427*7a8a68f5SJulian Pullen 	domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL);
1428*7a8a68f5SJulian Pullen 	if (domain_controller_item == NULL)
1429*7a8a68f5SJulian Pullen 		return (NULL);
1430*7a8a68f5SJulian Pullen 
1431*7a8a68f5SJulian Pullen 	if (!is_valid(&ctx->site_name) ||
1432*7a8a68f5SJulian Pullen 	    is_changed(&ctx->site_name, PARAM1, &ctx->domain_controller) ||
1433*7a8a68f5SJulian Pullen 	    ctx->subnets == NULL || ctx->subnets_changed) {
1434*7a8a68f5SJulian Pullen 		subnets = find_subnets();
1435*7a8a68f5SJulian Pullen 		ctx->subnets_last_check = time(NULL);
1436*7a8a68f5SJulian Pullen 		update_required = B_TRUE;
1437*7a8a68f5SJulian Pullen 	} else if (ctx->subnets_last_check + 60 < time(NULL)) {
1438*7a8a68f5SJulian Pullen 		subnets = find_subnets();
1439*7a8a68f5SJulian Pullen 		ctx->subnets_last_check = time(NULL);
1440*7a8a68f5SJulian Pullen 		if (cmpsubnets(ctx->subnets, subnets) != 0)
1441*7a8a68f5SJulian Pullen 			update_required = B_TRUE;
1442*7a8a68f5SJulian Pullen 	}
1443*7a8a68f5SJulian Pullen 
1444*7a8a68f5SJulian Pullen 	if (!update_required) {
1445*7a8a68f5SJulian Pullen 		free(subnets);
1446*7a8a68f5SJulian Pullen 		return (&ctx->site_name);
1447*7a8a68f5SJulian Pullen 	}
1448*7a8a68f5SJulian Pullen 
1449*7a8a68f5SJulian Pullen 	if (subnets == NULL)
1450*7a8a68f5SJulian Pullen 		return (NULL);
1451*7a8a68f5SJulian Pullen 
1452*7a8a68f5SJulian Pullen 	dn_root[0] = "";
1453*7a8a68f5SJulian Pullen 	dn_root[1] = NULL;
1454*7a8a68f5SJulian Pullen 
1455*7a8a68f5SJulian Pullen 	config_naming_context = ldap_lookup_entry_attr(
1456*7a8a68f5SJulian Pullen 	    &ld, ctx->domain_controller.value,
1457*7a8a68f5SJulian Pullen 	    dn_root, "configurationNamingContext");
1458*7a8a68f5SJulian Pullen 	if (config_naming_context == NULL)
1459*7a8a68f5SJulian Pullen 		goto out;
1460*7a8a68f5SJulian Pullen 	/*
1461*7a8a68f5SJulian Pullen 	 * configurationNamingContext also provides the Forest
1462*7a8a68f5SJulian Pullen 	 * Name.
1463*7a8a68f5SJulian Pullen 	 */
1464*7a8a68f5SJulian Pullen 	if (!is_fixed(&ctx->forest_name)) {
1465*7a8a68f5SJulian Pullen 		/*
1466*7a8a68f5SJulian Pullen 		 * The configurationNamingContext should be of
1467*7a8a68f5SJulian Pullen 		 * form:
1468*7a8a68f5SJulian Pullen 		 * CN=Configuration,<DNforestName>
1469*7a8a68f5SJulian Pullen 		 * Remove the first part and convert to DNS form
1470*7a8a68f5SJulian Pullen 		 * (replace ",DC=" with ".")
1471*7a8a68f5SJulian Pullen 		 */
1472*7a8a68f5SJulian Pullen 		char *str = "CN=Configuration,";
1473*7a8a68f5SJulian Pullen 		int len = strlen(str);
1474*7a8a68f5SJulian Pullen 		if (strncasecmp(config_naming_context, str, len) == 0) {
1475*7a8a68f5SJulian Pullen 			forest_name = DN_to_DNS(config_naming_context + len);
1476*7a8a68f5SJulian Pullen 			update_item(&ctx->forest_name, forest_name,
1477*7a8a68f5SJulian Pullen 			    AD_STATE_AUTO, 0);
1478*7a8a68f5SJulian Pullen 		}
1479*7a8a68f5SJulian Pullen 	}
1480*7a8a68f5SJulian Pullen 
1481*7a8a68f5SJulian Pullen 	dn_subnets = subnets_to_DNs(subnets, config_naming_context);
1482*7a8a68f5SJulian Pullen 	if (dn_subnets == NULL)
1483*7a8a68f5SJulian Pullen 		goto out;
1484*7a8a68f5SJulian Pullen 
1485*7a8a68f5SJulian Pullen 	site_object = ldap_lookup_entry_attr(
1486*7a8a68f5SJulian Pullen 	    &ld, domain_controller_item->value,
1487*7a8a68f5SJulian Pullen 	    dn_subnets, "siteobject");
1488*7a8a68f5SJulian Pullen 	if (site_object != NULL) {
1489*7a8a68f5SJulian Pullen 		/*
1490*7a8a68f5SJulian Pullen 		 * The site object should be of the form
1491*7a8a68f5SJulian Pullen 		 * CN=<site>,CN=Sites,CN=Configuration,
1492*7a8a68f5SJulian Pullen 		 *		<DN Domain>
1493*7a8a68f5SJulian Pullen 		 */
1494*7a8a68f5SJulian Pullen 		if (strncasecmp(site_object, "CN=", 3) == 0) {
1495*7a8a68f5SJulian Pullen 			for (len = 0; site_object[len + 3] != ','; len++)
1496*7a8a68f5SJulian Pullen 					;
1497*7a8a68f5SJulian Pullen 			site_name = malloc(len + 1);
1498*7a8a68f5SJulian Pullen 			(void) strncpy(site_name, &site_object[3], len);
1499*7a8a68f5SJulian Pullen 			site_name[len] = '\0';
1500*7a8a68f5SJulian Pullen 			update_item(&ctx->site_name, site_name,
1501*7a8a68f5SJulian Pullen 			    AD_STATE_AUTO, 0);
1502*7a8a68f5SJulian Pullen 		}
1503*7a8a68f5SJulian Pullen 	}
1504*7a8a68f5SJulian Pullen 
1505*7a8a68f5SJulian Pullen 	if (ctx->subnets != NULL) {
1506*7a8a68f5SJulian Pullen 		free(ctx->subnets);
1507*7a8a68f5SJulian Pullen 		ctx->subnets = NULL;
1508*7a8a68f5SJulian Pullen 	}
1509*7a8a68f5SJulian Pullen 	ctx->subnets = subnets;
1510*7a8a68f5SJulian Pullen 	subnets = NULL;
1511*7a8a68f5SJulian Pullen 	ctx->subnets_changed = B_FALSE;
1512*7a8a68f5SJulian Pullen 
1513*7a8a68f5SJulian Pullen out:
1514*7a8a68f5SJulian Pullen 	if (ld != NULL)
1515*7a8a68f5SJulian Pullen 		(void) ldap_unbind(ld);
1516*7a8a68f5SJulian Pullen 
1517*7a8a68f5SJulian Pullen 	if (dn_subnets != NULL) {
1518*7a8a68f5SJulian Pullen 		for (i = 0; dn_subnets[i] != NULL; i++)
1519*7a8a68f5SJulian Pullen 			free(dn_subnets[i]);
1520*7a8a68f5SJulian Pullen 		free(dn_subnets);
1521*7a8a68f5SJulian Pullen 	}
1522*7a8a68f5SJulian Pullen 	if (config_naming_context != NULL)
1523*7a8a68f5SJulian Pullen 		free(config_naming_context);
1524*7a8a68f5SJulian Pullen 	if (site_object != NULL)
1525*7a8a68f5SJulian Pullen 		free(site_object);
1526*7a8a68f5SJulian Pullen 
1527*7a8a68f5SJulian Pullen 	free(subnets);
1528*7a8a68f5SJulian Pullen 	if (site_name == NULL)
1529*7a8a68f5SJulian Pullen 		return (NULL);
1530*7a8a68f5SJulian Pullen 	return (&ctx->site_name);
1531*7a8a68f5SJulian Pullen 
1532*7a8a68f5SJulian Pullen }
1533*7a8a68f5SJulian Pullen 
1534*7a8a68f5SJulian Pullen 
1535*7a8a68f5SJulian Pullen char *
1536*7a8a68f5SJulian Pullen ad_disc_get_SiteName(ad_disc_t ctx, boolean_t *auto_discovered)
1537*7a8a68f5SJulian Pullen {
1538*7a8a68f5SJulian Pullen 	ad_item_t *site_name_item;
1539*7a8a68f5SJulian Pullen 	char	*site_name = NULL;
1540*7a8a68f5SJulian Pullen 
1541*7a8a68f5SJulian Pullen 	site_name_item = validate_SiteName(ctx);
1542*7a8a68f5SJulian Pullen 	if (site_name_item != NULL) {
1543*7a8a68f5SJulian Pullen 		site_name = strdup(site_name_item->value);
1544*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1545*7a8a68f5SJulian Pullen 			*auto_discovered =
1546*7a8a68f5SJulian Pullen 			    (site_name_item->state == AD_STATE_AUTO);
1547*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1548*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1549*7a8a68f5SJulian Pullen 
1550*7a8a68f5SJulian Pullen 	return (site_name);
1551*7a8a68f5SJulian Pullen }
1552*7a8a68f5SJulian Pullen 
1553*7a8a68f5SJulian Pullen 
1554*7a8a68f5SJulian Pullen 
1555*7a8a68f5SJulian Pullen /* Discover forest name */
1556*7a8a68f5SJulian Pullen static ad_item_t *
1557*7a8a68f5SJulian Pullen validate_ForestName(ad_disc_t ctx)
1558*7a8a68f5SJulian Pullen {
1559*7a8a68f5SJulian Pullen 	LDAP	*ld = NULL;
1560*7a8a68f5SJulian Pullen 	char	*config_naming_context;
1561*7a8a68f5SJulian Pullen 	char	*forest_name = NULL;
1562*7a8a68f5SJulian Pullen 	char	*dn_list[2];
1563*7a8a68f5SJulian Pullen 	ad_item_t *domain_controller_item;
1564*7a8a68f5SJulian Pullen 
1565*7a8a68f5SJulian Pullen 	if (is_fixed(&ctx->forest_name))
1566*7a8a68f5SJulian Pullen 		return (&ctx->forest_name);
1567*7a8a68f5SJulian Pullen 	/*
1568*7a8a68f5SJulian Pullen 	 * We may not have a site name yet, so we won't rely on
1569*7a8a68f5SJulian Pullen 	 * site-specific DCs.  (But maybe we could replace
1570*7a8a68f5SJulian Pullen 	 * validate_ForestName() with validate_siteName()?)
1571*7a8a68f5SJulian Pullen 	 */
1572*7a8a68f5SJulian Pullen 	domain_controller_item = validate_DomainController(ctx, AD_DISC_GLOBAL);
1573*7a8a68f5SJulian Pullen 	if (domain_controller_item == NULL)
1574*7a8a68f5SJulian Pullen 		return (NULL);
1575*7a8a68f5SJulian Pullen 
1576*7a8a68f5SJulian Pullen 	if (!is_valid(&ctx->forest_name) ||
1577*7a8a68f5SJulian Pullen 	    is_changed(&ctx->forest_name, PARAM1, domain_controller_item)) {
1578*7a8a68f5SJulian Pullen 
1579*7a8a68f5SJulian Pullen 		dn_list[0] = "";
1580*7a8a68f5SJulian Pullen 		dn_list[1] = NULL;
1581*7a8a68f5SJulian Pullen 		config_naming_context = ldap_lookup_entry_attr(
1582*7a8a68f5SJulian Pullen 		    &ld, ctx->domain_controller.value,
1583*7a8a68f5SJulian Pullen 		    dn_list, "configurationNamingContext");
1584*7a8a68f5SJulian Pullen 		if (config_naming_context != NULL) {
1585*7a8a68f5SJulian Pullen 			/*
1586*7a8a68f5SJulian Pullen 			 * The configurationNamingContext should be of
1587*7a8a68f5SJulian Pullen 			 * form:
1588*7a8a68f5SJulian Pullen 			 * CN=Configuration,<DNforestName>
1589*7a8a68f5SJulian Pullen 			 * Remove the first part and convert to DNS form
1590*7a8a68f5SJulian Pullen 			 * (replace ",DC=" with ".")
1591*7a8a68f5SJulian Pullen 			 */
1592*7a8a68f5SJulian Pullen 			char *str = "CN=Configuration,";
1593*7a8a68f5SJulian Pullen 			int len = strlen(str);
1594*7a8a68f5SJulian Pullen 			if (strncasecmp(config_naming_context, str, len) == 0) {
1595*7a8a68f5SJulian Pullen 				forest_name = DN_to_DNS(
1596*7a8a68f5SJulian Pullen 				    config_naming_context + len);
1597*7a8a68f5SJulian Pullen 			}
1598*7a8a68f5SJulian Pullen 			free(config_naming_context);
1599*7a8a68f5SJulian Pullen 		}
1600*7a8a68f5SJulian Pullen 		if (ld != NULL)
1601*7a8a68f5SJulian Pullen 			(void) ldap_unbind(ld);
1602*7a8a68f5SJulian Pullen 
1603*7a8a68f5SJulian Pullen 		if (forest_name == NULL)
1604*7a8a68f5SJulian Pullen 			return (NULL);
1605*7a8a68f5SJulian Pullen 
1606*7a8a68f5SJulian Pullen 		update_item(&ctx->forest_name, forest_name, AD_STATE_AUTO, 0);
1607*7a8a68f5SJulian Pullen 		update_version(&ctx->forest_name, PARAM1,
1608*7a8a68f5SJulian Pullen 		    domain_controller_item);
1609*7a8a68f5SJulian Pullen 	}
1610*7a8a68f5SJulian Pullen 	return (&ctx->forest_name);
1611*7a8a68f5SJulian Pullen }
1612*7a8a68f5SJulian Pullen 
1613*7a8a68f5SJulian Pullen 
1614*7a8a68f5SJulian Pullen char *
1615*7a8a68f5SJulian Pullen ad_disc_get_ForestName(ad_disc_t ctx, boolean_t *auto_discovered)
1616*7a8a68f5SJulian Pullen {
1617*7a8a68f5SJulian Pullen 	ad_item_t *forest_name_item;
1618*7a8a68f5SJulian Pullen 	char	*forest_name = NULL;
1619*7a8a68f5SJulian Pullen 
1620*7a8a68f5SJulian Pullen 	forest_name_item = validate_ForestName(ctx);
1621*7a8a68f5SJulian Pullen 
1622*7a8a68f5SJulian Pullen 	if (forest_name_item != NULL) {
1623*7a8a68f5SJulian Pullen 		forest_name = strdup(forest_name_item->value);
1624*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1625*7a8a68f5SJulian Pullen 			*auto_discovered =
1626*7a8a68f5SJulian Pullen 			    (forest_name_item->state == AD_STATE_AUTO);
1627*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1628*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1629*7a8a68f5SJulian Pullen 
1630*7a8a68f5SJulian Pullen 	return (forest_name);
1631*7a8a68f5SJulian Pullen }
1632*7a8a68f5SJulian Pullen 
1633*7a8a68f5SJulian Pullen 
1634*7a8a68f5SJulian Pullen /* Discover global catalog servers */
1635*7a8a68f5SJulian Pullen static ad_item_t *
1636*7a8a68f5SJulian Pullen validate_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req)
1637*7a8a68f5SJulian Pullen {
1638*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *global_catalog = NULL;
1639*7a8a68f5SJulian Pullen 	uint32_t ttl = 0;
1640*7a8a68f5SJulian Pullen 	boolean_t validate_global = B_FALSE;
1641*7a8a68f5SJulian Pullen 	boolean_t validate_site = B_FALSE;
1642*7a8a68f5SJulian Pullen 	ad_item_t *forest_name_item;
1643*7a8a68f5SJulian Pullen 	ad_item_t *site_name_item;
1644*7a8a68f5SJulian Pullen 
1645*7a8a68f5SJulian Pullen 	/* If the values is fixed there will not be a site specific version */
1646*7a8a68f5SJulian Pullen 	if (is_fixed(&ctx->global_catalog))
1647*7a8a68f5SJulian Pullen 		return (&ctx->global_catalog);
1648*7a8a68f5SJulian Pullen 
1649*7a8a68f5SJulian Pullen 	forest_name_item = validate_ForestName(ctx);
1650*7a8a68f5SJulian Pullen 	if (forest_name_item == NULL)
1651*7a8a68f5SJulian Pullen 		return (NULL);
1652*7a8a68f5SJulian Pullen 
1653*7a8a68f5SJulian Pullen 	if (req == AD_DISC_GLOBAL)
1654*7a8a68f5SJulian Pullen 		validate_global = B_TRUE;
1655*7a8a68f5SJulian Pullen 	else {
1656*7a8a68f5SJulian Pullen 		site_name_item = validate_SiteName(ctx);
1657*7a8a68f5SJulian Pullen 		if (site_name_item != NULL)
1658*7a8a68f5SJulian Pullen 			validate_site = B_TRUE;
1659*7a8a68f5SJulian Pullen 		else if (req == AD_DISC_PREFER_SITE)
1660*7a8a68f5SJulian Pullen 			validate_global = B_TRUE;
1661*7a8a68f5SJulian Pullen 	}
1662*7a8a68f5SJulian Pullen 
1663*7a8a68f5SJulian Pullen 	if (validate_global) {
1664*7a8a68f5SJulian Pullen 		if (!is_valid(&ctx->global_catalog) ||
1665*7a8a68f5SJulian Pullen 		    is_changed(&ctx->global_catalog, PARAM1,
1666*7a8a68f5SJulian Pullen 		    forest_name_item)) {
1667*7a8a68f5SJulian Pullen 			/*
1668*7a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named
1669*7a8a68f5SJulian Pullen 			 * _ldap._tcp.gc._msdcs.<ForestName>
1670*7a8a68f5SJulian Pullen 			 */
1671*7a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1672*7a8a68f5SJulian Pullen 			global_catalog =
1673*7a8a68f5SJulian Pullen 			    srv_query(&ctx->res_state,
1674*7a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD GC_SRV_TAIL,
1675*7a8a68f5SJulian Pullen 			    ctx->forest_name.value, NULL, &ttl);
1676*7a8a68f5SJulian Pullen 
1677*7a8a68f5SJulian Pullen 			if (global_catalog == NULL)
1678*7a8a68f5SJulian Pullen 				return (NULL);
1679*7a8a68f5SJulian Pullen 
1680*7a8a68f5SJulian Pullen 			update_item(&ctx->global_catalog, global_catalog,
1681*7a8a68f5SJulian Pullen 			    AD_STATE_AUTO, ttl);
1682*7a8a68f5SJulian Pullen 			update_version(&ctx->global_catalog, PARAM1,
1683*7a8a68f5SJulian Pullen 			    forest_name_item);
1684*7a8a68f5SJulian Pullen 		}
1685*7a8a68f5SJulian Pullen 		return (&ctx->global_catalog);
1686*7a8a68f5SJulian Pullen 	}
1687*7a8a68f5SJulian Pullen 
1688*7a8a68f5SJulian Pullen 	if (validate_site) {
1689*7a8a68f5SJulian Pullen 		if (!is_valid(&ctx->site_global_catalog) ||
1690*7a8a68f5SJulian Pullen 		    is_changed(&ctx->site_global_catalog, PARAM1,
1691*7a8a68f5SJulian Pullen 		    forest_name_item) ||
1692*7a8a68f5SJulian Pullen 		    is_changed(&ctx->site_global_catalog, PARAM2,
1693*7a8a68f5SJulian Pullen 		    site_name_item)) {
1694*7a8a68f5SJulian Pullen 			char 	rr_name[DNS_MAX_NAME];
1695*7a8a68f5SJulian Pullen 
1696*7a8a68f5SJulian Pullen 			/*
1697*7a8a68f5SJulian Pullen 			 * Lookup DNS SRV RR named:
1698*7a8a68f5SJulian Pullen 			 * _ldap._tcp.<siteName>._sites.gc.
1699*7a8a68f5SJulian Pullen 			 *	_msdcs.<ForestName>
1700*7a8a68f5SJulian Pullen 			 */
1701*7a8a68f5SJulian Pullen 			(void) snprintf(rr_name,
1702*7a8a68f5SJulian Pullen 			    sizeof (rr_name),
1703*7a8a68f5SJulian Pullen 			    LDAP_SRV_HEAD SITE_SRV_MIDDLE GC_SRV_TAIL,
1704*7a8a68f5SJulian Pullen 			    ctx->site_name.value);
1705*7a8a68f5SJulian Pullen 			DO_RES_NINIT(ctx);
1706*7a8a68f5SJulian Pullen 			global_catalog = srv_query(&ctx->res_state, rr_name,
1707*7a8a68f5SJulian Pullen 			    ctx->forest_name.value, NULL, &ttl);
1708*7a8a68f5SJulian Pullen 
1709*7a8a68f5SJulian Pullen 			if (global_catalog == NULL)
1710*7a8a68f5SJulian Pullen 				return (NULL);
1711*7a8a68f5SJulian Pullen 			update_item(&ctx->site_global_catalog, global_catalog,
1712*7a8a68f5SJulian Pullen 			    AD_STATE_AUTO, ttl);
1713*7a8a68f5SJulian Pullen 			update_version(&ctx->site_global_catalog, PARAM1,
1714*7a8a68f5SJulian Pullen 			    forest_name_item);
1715*7a8a68f5SJulian Pullen 			update_version(&ctx->site_global_catalog, PARAM2,
1716*7a8a68f5SJulian Pullen 			    site_name_item);
1717*7a8a68f5SJulian Pullen 		}
1718*7a8a68f5SJulian Pullen 		return (&ctx->site_global_catalog);
1719*7a8a68f5SJulian Pullen 	}
1720*7a8a68f5SJulian Pullen 	return (NULL);
1721*7a8a68f5SJulian Pullen }
1722*7a8a68f5SJulian Pullen 
1723*7a8a68f5SJulian Pullen 
1724*7a8a68f5SJulian Pullen idmap_ad_disc_ds_t *
1725*7a8a68f5SJulian Pullen ad_disc_get_GlobalCatalog(ad_disc_t ctx, enum ad_disc_req req,
1726*7a8a68f5SJulian Pullen 			boolean_t *auto_discovered)
1727*7a8a68f5SJulian Pullen {
1728*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *global_catalog = NULL;
1729*7a8a68f5SJulian Pullen 	ad_item_t *global_catalog_item;
1730*7a8a68f5SJulian Pullen 
1731*7a8a68f5SJulian Pullen 	global_catalog_item = validate_GlobalCatalog(ctx, req);
1732*7a8a68f5SJulian Pullen 
1733*7a8a68f5SJulian Pullen 	if (global_catalog_item != NULL) {
1734*7a8a68f5SJulian Pullen 		global_catalog = ds_dup(global_catalog_item->value);
1735*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1736*7a8a68f5SJulian Pullen 			*auto_discovered =
1737*7a8a68f5SJulian Pullen 			    (global_catalog_item->state == AD_STATE_AUTO);
1738*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1739*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1740*7a8a68f5SJulian Pullen 
1741*7a8a68f5SJulian Pullen 	return (global_catalog);
1742*7a8a68f5SJulian Pullen }
1743*7a8a68f5SJulian Pullen 
1744*7a8a68f5SJulian Pullen 
1745*7a8a68f5SJulian Pullen static ad_item_t *
1746*7a8a68f5SJulian Pullen validate_TrustedDomains(ad_disc_t ctx)
1747*7a8a68f5SJulian Pullen {
1748*7a8a68f5SJulian Pullen 	LDAP *ld = NULL;
1749*7a8a68f5SJulian Pullen 	ad_item_t *global_catalog_item;
1750*7a8a68f5SJulian Pullen 	ad_item_t *forest_name_item;
1751*7a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *trusted_domains;
1752*7a8a68f5SJulian Pullen 	char *dn = NULL;
1753*7a8a68f5SJulian Pullen 	char *forest_name_dn;
1754*7a8a68f5SJulian Pullen 	int len;
1755*7a8a68f5SJulian Pullen 	int num_parts;
1756*7a8a68f5SJulian Pullen 
1757*7a8a68f5SJulian Pullen 	if (is_fixed(&ctx->trusted_domains))
1758*7a8a68f5SJulian Pullen 		return (&ctx->trusted_domains);
1759*7a8a68f5SJulian Pullen 
1760*7a8a68f5SJulian Pullen 	global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL);
1761*7a8a68f5SJulian Pullen 	if (global_catalog_item == NULL)
1762*7a8a68f5SJulian Pullen 		return (NULL);
1763*7a8a68f5SJulian Pullen 
1764*7a8a68f5SJulian Pullen 	forest_name_item = validate_ForestName(ctx);
1765*7a8a68f5SJulian Pullen 	if (forest_name_item == NULL)
1766*7a8a68f5SJulian Pullen 		return (NULL);
1767*7a8a68f5SJulian Pullen 
1768*7a8a68f5SJulian Pullen 	if (!is_valid(&ctx->trusted_domains) ||
1769*7a8a68f5SJulian Pullen 	    is_changed(&ctx->trusted_domains, PARAM1, global_catalog_item) ||
1770*7a8a68f5SJulian Pullen 	    is_changed(&ctx->trusted_domains, PARAM2, forest_name_item)) {
1771*7a8a68f5SJulian Pullen 
1772*7a8a68f5SJulian Pullen 		forest_name_dn = ldap_dns_to_dn(forest_name_item->value,
1773*7a8a68f5SJulian Pullen 		    &num_parts);
1774*7a8a68f5SJulian Pullen 		if (forest_name_dn == NULL)
1775*7a8a68f5SJulian Pullen 			return (NULL);
1776*7a8a68f5SJulian Pullen 
1777*7a8a68f5SJulian Pullen 		len = snprintf(NULL, 0, "CN=System,%s", forest_name_dn) + 1;
1778*7a8a68f5SJulian Pullen 		dn = malloc(len);
1779*7a8a68f5SJulian Pullen 		if (dn == NULL)  {
1780*7a8a68f5SJulian Pullen 			free(forest_name_dn);
1781*7a8a68f5SJulian Pullen 			return (NULL);
1782*7a8a68f5SJulian Pullen 		}
1783*7a8a68f5SJulian Pullen 		(void) snprintf(dn, len, "CN=System,%s", forest_name_dn);
1784*7a8a68f5SJulian Pullen 		free(forest_name_dn);
1785*7a8a68f5SJulian Pullen 
1786*7a8a68f5SJulian Pullen 		trusted_domains = ldap_lookup_trusted_domains(
1787*7a8a68f5SJulian Pullen 		    &ld, global_catalog_item->value, dn);
1788*7a8a68f5SJulian Pullen 
1789*7a8a68f5SJulian Pullen 		if (ld != NULL)
1790*7a8a68f5SJulian Pullen 			(void) ldap_unbind(ld);
1791*7a8a68f5SJulian Pullen 		free(dn);
1792*7a8a68f5SJulian Pullen 
1793*7a8a68f5SJulian Pullen 		if (trusted_domains == NULL)
1794*7a8a68f5SJulian Pullen 			return (NULL);
1795*7a8a68f5SJulian Pullen 
1796*7a8a68f5SJulian Pullen 		update_item(&ctx->trusted_domains, trusted_domains,
1797*7a8a68f5SJulian Pullen 		    AD_STATE_AUTO, 0);
1798*7a8a68f5SJulian Pullen 		update_version(&ctx->trusted_domains, PARAM1,
1799*7a8a68f5SJulian Pullen 		    global_catalog_item);
1800*7a8a68f5SJulian Pullen 		update_version(&ctx->trusted_domains, PARAM2,
1801*7a8a68f5SJulian Pullen 		    forest_name_item);
1802*7a8a68f5SJulian Pullen 	}
1803*7a8a68f5SJulian Pullen 
1804*7a8a68f5SJulian Pullen 	return (&ctx->trusted_domains);
1805*7a8a68f5SJulian Pullen }
1806*7a8a68f5SJulian Pullen 
1807*7a8a68f5SJulian Pullen 
1808*7a8a68f5SJulian Pullen ad_disc_trusteddomains_t *
1809*7a8a68f5SJulian Pullen ad_disc_get_TrustedDomains(ad_disc_t ctx, boolean_t *auto_discovered)
1810*7a8a68f5SJulian Pullen {
1811*7a8a68f5SJulian Pullen 	ad_disc_trusteddomains_t *trusted_domains = NULL;
1812*7a8a68f5SJulian Pullen 	ad_item_t *trusted_domains_item;
1813*7a8a68f5SJulian Pullen 
1814*7a8a68f5SJulian Pullen 	trusted_domains_item = validate_TrustedDomains(ctx);
1815*7a8a68f5SJulian Pullen 
1816*7a8a68f5SJulian Pullen 	if (trusted_domains_item != NULL) {
1817*7a8a68f5SJulian Pullen 		trusted_domains = td_dup(trusted_domains_item->value);
1818*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1819*7a8a68f5SJulian Pullen 			*auto_discovered =
1820*7a8a68f5SJulian Pullen 			    (trusted_domains_item->state == AD_STATE_AUTO);
1821*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1822*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1823*7a8a68f5SJulian Pullen 
1824*7a8a68f5SJulian Pullen 	return (trusted_domains);
1825*7a8a68f5SJulian Pullen }
1826*7a8a68f5SJulian Pullen 
1827*7a8a68f5SJulian Pullen 
1828*7a8a68f5SJulian Pullen static ad_item_t *
1829*7a8a68f5SJulian Pullen validate_DomainsInForest(ad_disc_t ctx)
1830*7a8a68f5SJulian Pullen {
1831*7a8a68f5SJulian Pullen 	ad_item_t *global_catalog_item;
1832*7a8a68f5SJulian Pullen 	LDAP *ld = NULL;
1833*7a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *domains_in_forest;
1834*7a8a68f5SJulian Pullen 
1835*7a8a68f5SJulian Pullen 	if (is_fixed(&ctx->domains_in_forest))
1836*7a8a68f5SJulian Pullen 		return (&ctx->domains_in_forest);
1837*7a8a68f5SJulian Pullen 
1838*7a8a68f5SJulian Pullen 	global_catalog_item = validate_GlobalCatalog(ctx, AD_DISC_GLOBAL);
1839*7a8a68f5SJulian Pullen 	if (global_catalog_item == NULL)
1840*7a8a68f5SJulian Pullen 		return (NULL);
1841*7a8a68f5SJulian Pullen 
1842*7a8a68f5SJulian Pullen 	if (!is_valid(&ctx->domains_in_forest) ||
1843*7a8a68f5SJulian Pullen 	    is_changed(&ctx->domains_in_forest, PARAM1, global_catalog_item)) {
1844*7a8a68f5SJulian Pullen 
1845*7a8a68f5SJulian Pullen 		domains_in_forest = ldap_lookup_domains_in_forest(
1846*7a8a68f5SJulian Pullen 		    &ld, global_catalog_item->value);
1847*7a8a68f5SJulian Pullen 
1848*7a8a68f5SJulian Pullen 		if (ld != NULL)
1849*7a8a68f5SJulian Pullen 			(void) ldap_unbind(ld);
1850*7a8a68f5SJulian Pullen 
1851*7a8a68f5SJulian Pullen 		if (domains_in_forest == NULL)
1852*7a8a68f5SJulian Pullen 			return (NULL);
1853*7a8a68f5SJulian Pullen 
1854*7a8a68f5SJulian Pullen 		update_item(&ctx->domains_in_forest, domains_in_forest,
1855*7a8a68f5SJulian Pullen 		    AD_STATE_AUTO, 0);
1856*7a8a68f5SJulian Pullen 		update_version(&ctx->domains_in_forest, PARAM1,
1857*7a8a68f5SJulian Pullen 		    global_catalog_item);
1858*7a8a68f5SJulian Pullen 	}
1859*7a8a68f5SJulian Pullen 	return (&ctx->domains_in_forest);
1860*7a8a68f5SJulian Pullen }
1861*7a8a68f5SJulian Pullen 
1862*7a8a68f5SJulian Pullen 
1863*7a8a68f5SJulian Pullen ad_disc_domainsinforest_t *
1864*7a8a68f5SJulian Pullen ad_disc_get_DomainsInForest(ad_disc_t ctx, boolean_t *auto_discovered)
1865*7a8a68f5SJulian Pullen {
1866*7a8a68f5SJulian Pullen 	ad_disc_domainsinforest_t *domains_in_forest = NULL;
1867*7a8a68f5SJulian Pullen 	ad_item_t *domains_in_forest_item;
1868*7a8a68f5SJulian Pullen 
1869*7a8a68f5SJulian Pullen 	domains_in_forest_item = validate_DomainsInForest(ctx);
1870*7a8a68f5SJulian Pullen 
1871*7a8a68f5SJulian Pullen 	if (domains_in_forest_item != NULL) {
1872*7a8a68f5SJulian Pullen 		domains_in_forest = df_dup(domains_in_forest_item->value);
1873*7a8a68f5SJulian Pullen 		if (auto_discovered != NULL)
1874*7a8a68f5SJulian Pullen 			*auto_discovered =
1875*7a8a68f5SJulian Pullen 			    (domains_in_forest_item->state == AD_STATE_AUTO);
1876*7a8a68f5SJulian Pullen 	} else if (auto_discovered != NULL)
1877*7a8a68f5SJulian Pullen 		*auto_discovered = B_FALSE;
1878*7a8a68f5SJulian Pullen 
1879*7a8a68f5SJulian Pullen 	return (domains_in_forest);
1880*7a8a68f5SJulian Pullen }
1881*7a8a68f5SJulian Pullen 
1882*7a8a68f5SJulian Pullen 
1883*7a8a68f5SJulian Pullen 
1884*7a8a68f5SJulian Pullen 
1885*7a8a68f5SJulian Pullen int
1886*7a8a68f5SJulian Pullen ad_disc_set_DomainName(ad_disc_t ctx, const char *domainName)
1887*7a8a68f5SJulian Pullen {
1888*7a8a68f5SJulian Pullen 	char *domain_name = NULL;
1889*7a8a68f5SJulian Pullen 	if (domainName != NULL) {
1890*7a8a68f5SJulian Pullen 		domain_name = strdup(domainName);
1891*7a8a68f5SJulian Pullen 		if (domain_name == NULL)
1892*7a8a68f5SJulian Pullen 			return (-1);
1893*7a8a68f5SJulian Pullen 		update_item(&ctx->domain_name, domain_name,
1894*7a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
1895*7a8a68f5SJulian Pullen 	} else if (ctx->domain_name.state == AD_STATE_FIXED)
1896*7a8a68f5SJulian Pullen 		ctx->domain_name.state = AD_STATE_INVALID;
1897*7a8a68f5SJulian Pullen 	return (0);
1898*7a8a68f5SJulian Pullen }
1899*7a8a68f5SJulian Pullen 
1900*7a8a68f5SJulian Pullen 
1901*7a8a68f5SJulian Pullen int
1902*7a8a68f5SJulian Pullen ad_disc_set_DomainController(ad_disc_t ctx,
1903*7a8a68f5SJulian Pullen 				const idmap_ad_disc_ds_t *domainController)
1904*7a8a68f5SJulian Pullen {
1905*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *domain_controller = NULL;
1906*7a8a68f5SJulian Pullen 	if (domainController != NULL) {
1907*7a8a68f5SJulian Pullen 		domain_controller = ds_dup(domainController);
1908*7a8a68f5SJulian Pullen 		if (domain_controller == NULL)
1909*7a8a68f5SJulian Pullen 			return (-1);
1910*7a8a68f5SJulian Pullen 		update_item(&ctx->domain_controller, domain_controller,
1911*7a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
1912*7a8a68f5SJulian Pullen 	} else if (ctx->domain_controller.state == AD_STATE_FIXED)
1913*7a8a68f5SJulian Pullen 		ctx->domain_controller.state = AD_STATE_INVALID;
1914*7a8a68f5SJulian Pullen 	return (0);
1915*7a8a68f5SJulian Pullen }
1916*7a8a68f5SJulian Pullen 
1917*7a8a68f5SJulian Pullen 
1918*7a8a68f5SJulian Pullen int
1919*7a8a68f5SJulian Pullen ad_disc_set_SiteName(ad_disc_t ctx, const char *siteName)
1920*7a8a68f5SJulian Pullen {
1921*7a8a68f5SJulian Pullen 	char *site_name = NULL;
1922*7a8a68f5SJulian Pullen 	if (siteName != NULL) {
1923*7a8a68f5SJulian Pullen 		site_name = strdup(siteName);
1924*7a8a68f5SJulian Pullen 		if (site_name == NULL)
1925*7a8a68f5SJulian Pullen 			return (-1);
1926*7a8a68f5SJulian Pullen 		update_item(&ctx->site_name, site_name, AD_STATE_FIXED, 0);
1927*7a8a68f5SJulian Pullen 	} else if (ctx->site_name.state == AD_STATE_FIXED)
1928*7a8a68f5SJulian Pullen 		ctx->site_name.state = AD_STATE_INVALID;
1929*7a8a68f5SJulian Pullen 	return (0);
1930*7a8a68f5SJulian Pullen }
1931*7a8a68f5SJulian Pullen 
1932*7a8a68f5SJulian Pullen int
1933*7a8a68f5SJulian Pullen ad_disc_set_ForestName(ad_disc_t ctx, const char *forestName)
1934*7a8a68f5SJulian Pullen {
1935*7a8a68f5SJulian Pullen 	char *forest_name = NULL;
1936*7a8a68f5SJulian Pullen 	if (forestName != NULL) {
1937*7a8a68f5SJulian Pullen 		forest_name = strdup(forestName);
1938*7a8a68f5SJulian Pullen 		if (forest_name == NULL)
1939*7a8a68f5SJulian Pullen 			return (-1);
1940*7a8a68f5SJulian Pullen 		update_item(&ctx->forest_name, forest_name,
1941*7a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
1942*7a8a68f5SJulian Pullen 	} else if (ctx->forest_name.state == AD_STATE_FIXED)
1943*7a8a68f5SJulian Pullen 		ctx->forest_name.state = AD_STATE_INVALID;
1944*7a8a68f5SJulian Pullen 	return (0);
1945*7a8a68f5SJulian Pullen }
1946*7a8a68f5SJulian Pullen 
1947*7a8a68f5SJulian Pullen int
1948*7a8a68f5SJulian Pullen ad_disc_set_GlobalCatalog(ad_disc_t ctx,
1949*7a8a68f5SJulian Pullen     const idmap_ad_disc_ds_t *globalCatalog)
1950*7a8a68f5SJulian Pullen {
1951*7a8a68f5SJulian Pullen 	idmap_ad_disc_ds_t *global_catalog = NULL;
1952*7a8a68f5SJulian Pullen 	if (globalCatalog != NULL) {
1953*7a8a68f5SJulian Pullen 		global_catalog = ds_dup(globalCatalog);
1954*7a8a68f5SJulian Pullen 		if (global_catalog == NULL)
1955*7a8a68f5SJulian Pullen 			return (-1);
1956*7a8a68f5SJulian Pullen 		update_item(&ctx->global_catalog, global_catalog,
1957*7a8a68f5SJulian Pullen 		    AD_STATE_FIXED, 0);
1958*7a8a68f5SJulian Pullen 	} else if (ctx->global_catalog.state == AD_STATE_FIXED)
1959*7a8a68f5SJulian Pullen 		ctx->global_catalog.state = AD_STATE_INVALID;
1960*7a8a68f5SJulian Pullen 	return (0);
1961*7a8a68f5SJulian Pullen }
1962*7a8a68f5SJulian Pullen 
1963*7a8a68f5SJulian Pullen 
1964*7a8a68f5SJulian Pullen int
1965*7a8a68f5SJulian Pullen ad_disc_unset(ad_disc_t ctx)
1966*7a8a68f5SJulian Pullen {
1967*7a8a68f5SJulian Pullen 	if (ctx->domain_name.state == AD_STATE_FIXED)
1968*7a8a68f5SJulian Pullen 		ctx->domain_name.state =  AD_STATE_INVALID;
1969*7a8a68f5SJulian Pullen 
1970*7a8a68f5SJulian Pullen 	if (ctx->domain_controller.state == AD_STATE_FIXED)
1971*7a8a68f5SJulian Pullen 		ctx->domain_controller.state =  AD_STATE_INVALID;
1972*7a8a68f5SJulian Pullen 
1973*7a8a68f5SJulian Pullen 	if (ctx->site_name.state == AD_STATE_FIXED)
1974*7a8a68f5SJulian Pullen 		ctx->site_name.state =  AD_STATE_INVALID;
1975*7a8a68f5SJulian Pullen 
1976*7a8a68f5SJulian Pullen 	if (ctx->forest_name.state == AD_STATE_FIXED)
1977*7a8a68f5SJulian Pullen 		ctx->forest_name.state =  AD_STATE_INVALID;
1978*7a8a68f5SJulian Pullen 
1979*7a8a68f5SJulian Pullen 	if (ctx->global_catalog.state == AD_STATE_FIXED)
1980*7a8a68f5SJulian Pullen 		ctx->global_catalog.state =  AD_STATE_INVALID;
1981*7a8a68f5SJulian Pullen 
1982*7a8a68f5SJulian Pullen 	return (0);
1983*7a8a68f5SJulian Pullen }
1984*7a8a68f5SJulian Pullen 
1985*7a8a68f5SJulian Pullen /*
1986*7a8a68f5SJulian Pullen  * ad_disc_get_TTL
1987*7a8a68f5SJulian Pullen  *
1988*7a8a68f5SJulian Pullen  * This routines the time to live for AD
1989*7a8a68f5SJulian Pullen  * auto discovered items.
1990*7a8a68f5SJulian Pullen  *
1991*7a8a68f5SJulian Pullen  *	Returns:
1992*7a8a68f5SJulian Pullen  *		-1 if there are no TTL items
1993*7a8a68f5SJulian Pullen  *		0  if there are expired items
1994*7a8a68f5SJulian Pullen  *		else the number of seconds
1995*7a8a68f5SJulian Pullen  *
1996*7a8a68f5SJulian Pullen  * The MIN_GT_ZERO(x, y) macro return the lesser of x and y, provided it
1997*7a8a68f5SJulian Pullen  * is positive -- min() greater than zero.
1998*7a8a68f5SJulian Pullen  */
1999*7a8a68f5SJulian Pullen #define	MIN_GT_ZERO(x, y) (((x) <= 0) ? (((y) <= 0) ? \
2000*7a8a68f5SJulian Pullen 		(-1) : (y)) : (((y) <= 0) ? (x) : (((x) > (y)) ? (y) : (x))))
2001*7a8a68f5SJulian Pullen int
2002*7a8a68f5SJulian Pullen ad_disc_get_TTL(ad_disc_t ctx)
2003*7a8a68f5SJulian Pullen {
2004*7a8a68f5SJulian Pullen 	int ttl;
2005*7a8a68f5SJulian Pullen 
2006*7a8a68f5SJulian Pullen 	ttl = MIN_GT_ZERO(ctx->domain_controller.ttl, ctx->global_catalog.ttl);
2007*7a8a68f5SJulian Pullen 	ttl = MIN_GT_ZERO(ttl, ctx->site_domain_controller.ttl);
2008*7a8a68f5SJulian Pullen 	ttl = MIN_GT_ZERO(ttl, ctx->site_global_catalog.ttl);
2009*7a8a68f5SJulian Pullen 
2010*7a8a68f5SJulian Pullen 	if (ttl == -1)
2011*7a8a68f5SJulian Pullen 		return (-1);
2012*7a8a68f5SJulian Pullen 	ttl -= time(NULL);
2013*7a8a68f5SJulian Pullen 	if (ttl < 0)
2014*7a8a68f5SJulian Pullen 		return (0);
2015*7a8a68f5SJulian Pullen 	return (ttl);
2016*7a8a68f5SJulian Pullen }
2017*7a8a68f5SJulian Pullen 
2018*7a8a68f5SJulian Pullen boolean_t
2019*7a8a68f5SJulian Pullen ad_disc_SubnetChanged(ad_disc_t ctx)
2020*7a8a68f5SJulian Pullen {
2021*7a8a68f5SJulian Pullen 	ad_subnet_t *subnets;
2022*7a8a68f5SJulian Pullen 
2023*7a8a68f5SJulian Pullen 	if (ctx->subnets_changed || ctx->subnets == NULL)
2024*7a8a68f5SJulian Pullen 		return (B_TRUE);
2025*7a8a68f5SJulian Pullen 
2026*7a8a68f5SJulian Pullen 	if ((subnets = find_subnets()) != NULL) {
2027*7a8a68f5SJulian Pullen 		if (cmpsubnets(subnets, ctx->subnets) != 0)
2028*7a8a68f5SJulian Pullen 			ctx->subnets_changed = B_TRUE;
2029*7a8a68f5SJulian Pullen 		free(subnets);
2030*7a8a68f5SJulian Pullen 	}
2031*7a8a68f5SJulian Pullen 
2032*7a8a68f5SJulian Pullen 	return (ctx->subnets_changed);
2033*7a8a68f5SJulian Pullen }
2034