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