1c5c4113dSnw /*
2c5c4113dSnw  * CDDL HEADER START
3c5c4113dSnw  *
4c5c4113dSnw  * The contents of this file are subject to the terms of the
5c5c4113dSnw  * Common Development and Distribution License (the "License").
6c5c4113dSnw  * You may not use this file except in compliance with the License.
7c5c4113dSnw  *
8c5c4113dSnw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c5c4113dSnw  * or http://www.opensolaris.org/os/licensing.
10c5c4113dSnw  * See the License for the specific language governing permissions
11c5c4113dSnw  * and limitations under the License.
12c5c4113dSnw  *
13c5c4113dSnw  * When distributing Covered Code, include this CDDL HEADER in each
14c5c4113dSnw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c5c4113dSnw  * If applicable, add the following below this CDDL HEADER, with the
16c5c4113dSnw  * fields enclosed by brackets "[]" replaced with your own identifying
17c5c4113dSnw  * information: Portions Copyright [yyyy] [name of copyright owner]
18c5c4113dSnw  *
19c5c4113dSnw  * CDDL HEADER END
20c5c4113dSnw  */
21c5c4113dSnw /*
22c5c4113dSnw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23c5c4113dSnw  * Use is subject to license terms.
24c5c4113dSnw  */
25c5c4113dSnw 
26c5c4113dSnw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27c5c4113dSnw 
28c5c4113dSnw /*
29c5c4113dSnw  * Config routines common to idmap(1M) and idmapd(1M)
30c5c4113dSnw  */
31c5c4113dSnw 
32c5c4113dSnw #include <stdlib.h>
33c5c4113dSnw #include <strings.h>
34c5c4113dSnw #include <libintl.h>
35c5c4113dSnw #include <ctype.h>
36c5c4113dSnw #include <errno.h>
37651c0131Sbaban #include "idmapd.h"
38c5c4113dSnw #include <stdio.h>
39c5c4113dSnw #include <stdarg.h>
408edda628Sbaban #include <uuid/uuid.h>
41c8e26105Sjp #include <pthread.h>
42c8e26105Sjp #include <port.h>
43c8e26105Sjp #include "addisc.h"
44c5c4113dSnw 
458edda628Sbaban #define	MACHINE_SID_LEN	(9 + UUID_LEN/4 * 11)
46c5c4113dSnw #define	FMRI_BASE "svc:/system/idmap"
47c5c4113dSnw #define	CONFIG_PG "config"
48c5c4113dSnw #define	GENERAL_PG "general"
49c5c4113dSnw /* initial length of the array for policy options/attributes: */
50c5c4113dSnw #define	DEF_ARRAY_LENGTH 16
51c5c4113dSnw 
52c8e26105Sjp /*LINTLIBRARY*/
53c8e26105Sjp 
54c8e26105Sjp 
55651c0131Sbaban static const char *me = "idmapd";
56c5c4113dSnw 
57c8e26105Sjp 
58c8e26105Sjp static pthread_t update_thread_handle = 0;
59c8e26105Sjp 
60c8e26105Sjp int hup_ev_port = -1;
61c8e26105Sjp extern int hupped;
62c8e26105Sjp 
638edda628Sbaban static int
648edda628Sbaban generate_machine_sid(char **machine_sid) {
658edda628Sbaban 	char *p;
668edda628Sbaban 	uuid_t uu;
678edda628Sbaban 	int i, j, len, rlen;
688edda628Sbaban 	uint32_t rid;
698edda628Sbaban 
708edda628Sbaban 	/*
718edda628Sbaban 	 * Generate and split 128-bit UUID into four 32-bit RIDs
728edda628Sbaban 	 * The machine_sid will be of the form S-1-5-N1-N2-N3-N4
738edda628Sbaban 	 * We depart from Windows here, which instead of 128
748edda628Sbaban 	 * bits worth of random numbers uses 96 bits.
758edda628Sbaban 	 */
768edda628Sbaban 
778edda628Sbaban 	*machine_sid = calloc(1, MACHINE_SID_LEN);
788edda628Sbaban 	if (*machine_sid == NULL) {
798edda628Sbaban 		idmapdlog(LOG_ERR, "%s: Out of memory", me);
808edda628Sbaban 		return (-1);
818edda628Sbaban 	}
828edda628Sbaban 	(void) strcpy(*machine_sid, "S-1-5-21");
838edda628Sbaban 	p = *machine_sid + strlen("S-1-5-21");
848edda628Sbaban 	len = MACHINE_SID_LEN - strlen("S-1-5-21");
858edda628Sbaban 
868edda628Sbaban 	uuid_clear(uu);
878edda628Sbaban 	uuid_generate_random(uu);
888edda628Sbaban 
898edda628Sbaban 	for (i = 0; i < UUID_LEN/4; i++) {
908edda628Sbaban 		j = i * 4;
918edda628Sbaban 		rid = (uu[j] << 24) | (uu[j + 1] << 16) |
928edda628Sbaban 			(uu[j + 2] << 8) | (uu[j + 3]);
938edda628Sbaban 		rlen = snprintf(p, len, "-%u", rid);
948edda628Sbaban 		p += rlen;
958edda628Sbaban 		len -= rlen;
968edda628Sbaban 	}
978edda628Sbaban 
988edda628Sbaban 	return (0);
998edda628Sbaban }
1008edda628Sbaban 
101c5c4113dSnw /* Check if in the case of failure the original value of *val is preserved */
102c5c4113dSnw static int
103c8e26105Sjp get_val_int(idmap_cfg_handles_t *handles, char *name,
104c8e26105Sjp 	void *val, scf_type_t type)
105c5c4113dSnw {
106c5c4113dSnw 	int rc = 0;
107c5c4113dSnw 
108c8e26105Sjp 	scf_property_t *scf_prop = scf_property_create(handles->main);
109c8e26105Sjp 	scf_value_t *value = scf_value_create(handles->main);
110c5c4113dSnw 
111c8e26105Sjp 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
112c5c4113dSnw 	/* this is OK: the property is just undefined */
113c5c4113dSnw 		goto destruction;
114c5c4113dSnw 
115c5c4113dSnw 
116c8e26105Sjp 	if (scf_property_get_value(scf_prop, value) < 0)
117c5c4113dSnw 	/* It is still OK when a property doesn't have any value */
118c5c4113dSnw 		goto destruction;
119c5c4113dSnw 
120c5c4113dSnw 	switch (type) {
121c5c4113dSnw 	case SCF_TYPE_BOOLEAN:
122c5c4113dSnw 		rc = scf_value_get_boolean(value, val);
123c5c4113dSnw 		break;
124c5c4113dSnw 	case SCF_TYPE_COUNT:
125c5c4113dSnw 		rc = scf_value_get_count(value, val);
126c5c4113dSnw 		break;
127c5c4113dSnw 	case SCF_TYPE_INTEGER:
128c5c4113dSnw 		rc = scf_value_get_integer(value, val);
129c5c4113dSnw 		break;
130c5c4113dSnw 	default:
131651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: Invalid scf integer type (%d)",
132651c0131Sbaban 		    me, type);
133c5c4113dSnw 		rc = -1;
134c5c4113dSnw 		break;
135c5c4113dSnw 	}
136c5c4113dSnw 
137c5c4113dSnw 
138c5c4113dSnw destruction:
139c5c4113dSnw 	scf_value_destroy(value);
140c5c4113dSnw 	scf_property_destroy(scf_prop);
141c5c4113dSnw 
142c5c4113dSnw 	return (rc);
143c5c4113dSnw }
144c5c4113dSnw 
145c5c4113dSnw static char *
146c5c4113dSnw scf_value2string(scf_value_t *value) {
147c5c4113dSnw 	int rc = -1;
148c5c4113dSnw 	char buf_size = 127;
149c5c4113dSnw 	int length;
150c5c4113dSnw 	char *buf = NULL;
151c5c4113dSnw 	buf = (char *) malloc(sizeof (char) * buf_size);
152c5c4113dSnw 
153c5c4113dSnw 	for (;;) {
154c5c4113dSnw 		length = scf_value_get_astring(value, buf, buf_size);
155c5c4113dSnw 		if (length < 0) {
156c5c4113dSnw 			rc = -1;
157c5c4113dSnw 			goto destruction;
158c5c4113dSnw 		}
159c5c4113dSnw 
160c5c4113dSnw 		if (length == buf_size - 1) {
161c5c4113dSnw 			buf_size *= 2;
162c5c4113dSnw 			buf = (char *)realloc(buf, buf_size * sizeof (char));
163c5c4113dSnw 			if (!buf) {
164651c0131Sbaban 				idmapdlog(LOG_ERR, "%s: Out of memory", me);
165c5c4113dSnw 				rc = -1;
166c5c4113dSnw 				goto destruction;
167c5c4113dSnw 			}
168c5c4113dSnw 		} else {
169c5c4113dSnw 			rc = 0;
170c8e26105Sjp 		    break;
171c8e26105Sjp 	    }
172c5c4113dSnw 	}
173c5c4113dSnw 
174c5c4113dSnw destruction:
175c5c4113dSnw 	if (rc < 0) {
176c5c4113dSnw 		if (buf)
177c5c4113dSnw 			free(buf);
178c5c4113dSnw 		buf = NULL;
179c5c4113dSnw 	}
180c5c4113dSnw 
181c5c4113dSnw 	return (buf);
182c5c4113dSnw }
183c5c4113dSnw 
184c8e26105Sjp static int
185c8e26105Sjp get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport,
186c8e26105Sjp 		ad_disc_ds_t **val)
187c8e26105Sjp {
188c8e26105Sjp 	ad_disc_ds_t *servers = NULL;
189c8e26105Sjp 	scf_property_t *scf_prop;
190c8e26105Sjp 	scf_value_t *value;
191c8e26105Sjp 	scf_iter_t *iter;
192c8e26105Sjp 	char *host, *portstr;
193e3c2d6aaSnw 	int len, i;
194c8e26105Sjp 	int count = 0;
195e3c2d6aaSnw 	int rc = -1;
196c8e26105Sjp 
197c8e26105Sjp 	*val = NULL;
198c8e26105Sjp 
199c8e26105Sjp restart:
200c8e26105Sjp 	scf_prop = scf_property_create(handles->main);
201c8e26105Sjp 	value = scf_value_create(handles->main);
202c8e26105Sjp 	iter = scf_iter_create(handles->main);
203c8e26105Sjp 
204e3c2d6aaSnw 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
205c8e26105Sjp 		/* this is OK: the property is just undefined */
206e3c2d6aaSnw 		rc = 0;
207c8e26105Sjp 		goto destruction;
208e3c2d6aaSnw 	}
209c8e26105Sjp 
210c8e26105Sjp 	if (scf_iter_property_values(iter, scf_prop) < 0) {
211c8e26105Sjp 		idmapdlog(LOG_ERR,
212c8e26105Sjp 		    "%s: scf_iter_property_values(%s) failed: %s",
213c8e26105Sjp 		    me, name, scf_strerror(scf_error()));
214c8e26105Sjp 		goto destruction;
215c8e26105Sjp 	}
216c8e26105Sjp 
217c8e26105Sjp 	/* Workaround scf bugs -- can't reset an iteration */
218c8e26105Sjp 	if (count == 0) {
219c8e26105Sjp 		while (scf_iter_next_value(iter, value) > 0)
220c8e26105Sjp 			count++;
221c8e26105Sjp 
222e3c2d6aaSnw 		if (count == 0) {
223c8e26105Sjp 			/* no values */
224e3c2d6aaSnw 			rc = 0;
225c8e26105Sjp 			goto destruction;
226e3c2d6aaSnw 		}
227c8e26105Sjp 
228c8e26105Sjp 		scf_value_destroy(value);
229c8e26105Sjp 		scf_iter_destroy(iter);
230c8e26105Sjp 		scf_property_destroy(scf_prop);
231c8e26105Sjp 		goto restart;
232c8e26105Sjp 	}
233c8e26105Sjp 
234c8e26105Sjp 	if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
235c8e26105Sjp 		idmapdlog(LOG_ERR, "%s: Out of memory", me);
236c8e26105Sjp 		goto destruction;
237c8e26105Sjp 	}
238c8e26105Sjp 
239e3c2d6aaSnw 	i = 0;
240e3c2d6aaSnw 	while (i < count && scf_iter_next_value(iter, value) > 0) {
241e3c2d6aaSnw 		servers[i].priority = 0;
242e3c2d6aaSnw 		servers[i].weight = 100;
243e3c2d6aaSnw 		servers[i].port = defport;
244c8e26105Sjp 		if ((host = scf_value2string(value)) == NULL) {
245c8e26105Sjp 			goto destruction;
246c8e26105Sjp 		}
247c8e26105Sjp 		if ((portstr = strchr(host, ':')) != NULL) {
248c8e26105Sjp 			*portstr++ = '\0';
249e3c2d6aaSnw 			servers[i].port = strtol(portstr,
250c8e26105Sjp 			    (char **)NULL, 10);
251e3c2d6aaSnw 			if (servers[i].port == 0)
252e3c2d6aaSnw 				servers[i].port = defport;
253c8e26105Sjp 		}
254e3c2d6aaSnw 		len = strlcpy(servers[i].host, host,
255c8e26105Sjp 		    sizeof (servers->host));
256c8e26105Sjp 
257c8e26105Sjp 		free(host);
258c8e26105Sjp 
259c8e26105Sjp 		/* Ignore this server if the hostname is too long */
260c8e26105Sjp 		if (len < sizeof (servers->host))
261e3c2d6aaSnw 			i++;
262c8e26105Sjp 	}
263c8e26105Sjp 
264c8e26105Sjp 	*val = servers;
265c8e26105Sjp 
266e3c2d6aaSnw 	rc = 0;
267e3c2d6aaSnw 
268c8e26105Sjp destruction:
269c8e26105Sjp 	scf_value_destroy(value);
270c8e26105Sjp 	scf_iter_destroy(iter);
271c8e26105Sjp 	scf_property_destroy(scf_prop);
272c8e26105Sjp 
273c8e26105Sjp 	if (rc < 0) {
274c8e26105Sjp 		if (servers)
275c8e26105Sjp 			free(servers);
276c8e26105Sjp 		*val = NULL;
277c8e26105Sjp 	}
278c8e26105Sjp 
279c8e26105Sjp 	return (rc);
280c8e26105Sjp }
281c8e26105Sjp 
282c5c4113dSnw 
283c5c4113dSnw static int
284c8e26105Sjp get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val)
285c5c4113dSnw {
286c5c4113dSnw 	int rc = 0;
287c5c4113dSnw 
288c8e26105Sjp 	scf_property_t *scf_prop = scf_property_create(handles->main);
289c8e26105Sjp 	scf_value_t *value = scf_value_create(handles->main);
290c5c4113dSnw 
291c8e26105Sjp 	*val = NULL;
292c5c4113dSnw 
293c8e26105Sjp 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
294c5c4113dSnw 	/* this is OK: the property is just undefined */
295c5c4113dSnw 		goto destruction;
296c5c4113dSnw 
297c8e26105Sjp 	if (scf_property_get_value(scf_prop, value) < 0) {
298651c0131Sbaban 		idmapdlog(LOG_ERR,
299651c0131Sbaban 		    "%s: scf_property_get_value(%s) failed: %s",
300651c0131Sbaban 		    me, name, scf_strerror(scf_error()));
301c5c4113dSnw 		rc = -1;
302c5c4113dSnw 		goto destruction;
303c5c4113dSnw 	}
304c5c4113dSnw 
305c8e26105Sjp 	if (!(*val = scf_value2string(value)))
306c5c4113dSnw 		rc = -1;
307c5c4113dSnw 
308c5c4113dSnw destruction:
309c5c4113dSnw 	scf_value_destroy(value);
310c5c4113dSnw 	scf_property_destroy(scf_prop);
311c5c4113dSnw 
312c5c4113dSnw 	if (rc < 0) {
313c5c4113dSnw 		if (*val)
314c5c4113dSnw 			free(*val);
315c5c4113dSnw 		*val = NULL;
316c5c4113dSnw 	}
317c5c4113dSnw 
318c5c4113dSnw 	return (rc);
319c5c4113dSnw }
320c5c4113dSnw 
321c8e26105Sjp 
3228edda628Sbaban static int
323c8e26105Sjp set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val)
3248edda628Sbaban {
325e3c2d6aaSnw 	int			rc = -1;
326e3c2d6aaSnw 	int			ret = -2;
327e3c2d6aaSnw 	int			i;
3288edda628Sbaban 	scf_property_t		*scf_prop = NULL;
3298edda628Sbaban 	scf_value_t		*value = NULL;
3308edda628Sbaban 	scf_transaction_t	*tx = NULL;
3318edda628Sbaban 	scf_transaction_entry_t	*ent = NULL;
3328edda628Sbaban 
333c8e26105Sjp 	if ((scf_prop = scf_property_create(handles->main)) == NULL ||
334c8e26105Sjp 	    (value = scf_value_create(handles->main)) == NULL ||
335c8e26105Sjp 	    (tx = scf_transaction_create(handles->main)) == NULL ||
336c8e26105Sjp 	    (ent = scf_entry_create(handles->main)) == NULL) {
3378edda628Sbaban 		idmapdlog(LOG_ERR, "%s: Unable to set property %s: %s",
3388edda628Sbaban 		    me, name, scf_strerror(scf_error()));
3398edda628Sbaban 		goto destruction;
3408edda628Sbaban 	}
3418edda628Sbaban 
342e3c2d6aaSnw 	for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) {
343c8e26105Sjp 		if (scf_transaction_start(tx, handles->config_pg) == -1) {
3448edda628Sbaban 			idmapdlog(LOG_ERR,
3458edda628Sbaban 			    "%s: scf_transaction_start(%s) failed: %s",
3468edda628Sbaban 			    me, name, scf_strerror(scf_error()));
3478edda628Sbaban 			goto destruction;
3488edda628Sbaban 		}
3498edda628Sbaban 
350e3c2d6aaSnw 		if (scf_transaction_property_new(tx, ent, name,
351e3c2d6aaSnw 		    SCF_TYPE_ASTRING) < 0) {
3528edda628Sbaban 			idmapdlog(LOG_ERR,
3538edda628Sbaban 			    "%s: scf_transaction_property_new() failed: %s",
3548edda628Sbaban 			    me, scf_strerror(scf_error()));
3558edda628Sbaban 			goto destruction;
3568edda628Sbaban 		}
3578edda628Sbaban 
3588edda628Sbaban 		if (scf_value_set_astring(value, val) == -1) {
3598edda628Sbaban 			idmapdlog(LOG_ERR,
3608edda628Sbaban 			    "%s: scf_value_set_astring() failed: %s",
3618edda628Sbaban 			    me, scf_strerror(scf_error()));
3628edda628Sbaban 			goto destruction;
3638edda628Sbaban 		}
3648edda628Sbaban 
3658edda628Sbaban 		if (scf_entry_add_value(ent, value) == -1) {
3668edda628Sbaban 			idmapdlog(LOG_ERR,
3678edda628Sbaban 			    "%s: scf_entry_add_value() failed: %s",
3688edda628Sbaban 			    me, scf_strerror(scf_error()));
3698edda628Sbaban 			goto destruction;
3708edda628Sbaban 		}
3718edda628Sbaban 
372e3c2d6aaSnw 		if ((ret = scf_transaction_commit(tx)) == 1)
373e3c2d6aaSnw 			break;
374e3c2d6aaSnw 
375e3c2d6aaSnw 		if (ret == 0 && i < MAX_TRIES - 1) {
3768edda628Sbaban 			/*
3778edda628Sbaban 			 * Property group set in scf_transaction_start()
3788edda628Sbaban 			 * is not the most recent. Update pg, reset tx and
3798edda628Sbaban 			 * retry tx.
3808edda628Sbaban 			 */
3818edda628Sbaban 			idmapdlog(LOG_WARNING,
3828edda628Sbaban 			    "%s: scf_transaction_commit(%s) failed - Retry: %s",
3838edda628Sbaban 			    me, name, scf_strerror(scf_error()));
384c8e26105Sjp 			if (scf_pg_update(handles->config_pg) == -1) {
3858edda628Sbaban 				idmapdlog(LOG_ERR,
3868edda628Sbaban 				    "%s: scf_pg_update() failed: %s",
3878edda628Sbaban 				    me, scf_strerror(scf_error()));
3888edda628Sbaban 				goto destruction;
3898edda628Sbaban 			}
3908edda628Sbaban 			scf_transaction_reset(tx);
3918edda628Sbaban 		}
3928edda628Sbaban 	}
3938edda628Sbaban 
394e3c2d6aaSnw 
395e3c2d6aaSnw 	if (ret == 1)
396e3c2d6aaSnw 		rc = 0;
397e3c2d6aaSnw 	else if (ret != -2)
3988edda628Sbaban 		idmapdlog(LOG_ERR,
3998edda628Sbaban 		    "%s: scf_transaction_commit(%s) failed: %s",
4008edda628Sbaban 		    me, name, scf_strerror(scf_error()));
4018edda628Sbaban 
4028edda628Sbaban destruction:
4038edda628Sbaban 	scf_value_destroy(value);
4048edda628Sbaban 	scf_entry_destroy(ent);
4058edda628Sbaban 	scf_transaction_destroy(tx);
4068edda628Sbaban 	scf_property_destroy(scf_prop);
4078edda628Sbaban 	return (rc);
4088edda628Sbaban }
4098edda628Sbaban 
410c8e26105Sjp static int
411c8e26105Sjp update_value(char **value, char **new, char *name)
412c8e26105Sjp {
413c8e26105Sjp 	if (*new == NULL)
414c8e26105Sjp 		return (FALSE);
415c8e26105Sjp 
416c8e26105Sjp 	if (*value != NULL && strcmp(*new, *value) == 0) {
417c8e26105Sjp 		free(*new);
418c8e26105Sjp 		*new = NULL;
419c8e26105Sjp 		return (FALSE);
420c8e26105Sjp 	}
421c8e26105Sjp 
422c8e26105Sjp 	idmapdlog(LOG_INFO, "%s: change %s=%s", me, name, CHECK_NULL(*new));
423c8e26105Sjp 	if (*value != NULL)
424c8e26105Sjp 		free(*value);
425c8e26105Sjp 	*value = *new;
426c8e26105Sjp 	*new = NULL;
427c8e26105Sjp 	return (TRUE);
428c8e26105Sjp }
429c8e26105Sjp 
430c8e26105Sjp static int
431c8e26105Sjp update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name)
432c8e26105Sjp {
433c8e26105Sjp 	int i;
434c8e26105Sjp 
435c8e26105Sjp 	if (*new == NULL)
436c8e26105Sjp 		return (FALSE);
437c8e26105Sjp 
438c8e26105Sjp 	if (*value != NULL && ad_disc_compare_ds(*value, *new) == 0) {
439c8e26105Sjp 		free(*new);
440c8e26105Sjp 		*new = NULL;
441c8e26105Sjp 		return (FALSE);
442c8e26105Sjp 	}
443c8e26105Sjp 
444c8e26105Sjp 	if (*value)
445c8e26105Sjp 		free(*value);
446c8e26105Sjp 
447c8e26105Sjp 	for (i = 0; (*new)[i].host[0] != '\0'; i++)
448c8e26105Sjp 		idmapdlog(LOG_INFO, "%s: change %s=%s port=%d", me, name,
449c8e26105Sjp 		    (*new)[i].host, (*new)[i].port);
450c8e26105Sjp 	*value = *new;
451c8e26105Sjp 	*new = NULL;
452c8e26105Sjp 	return (TRUE);
453c8e26105Sjp }
454c8e26105Sjp 
455c8e26105Sjp 
456c8e26105Sjp #define	SUBNET_CHECK_TIME	(2 * 60)
457c8e26105Sjp #define	MAX_CHECK_TIME		(10 * 60)
458c8e26105Sjp 
459c8e26105Sjp /*
460c8e26105Sjp  * Returns 1 if SIGHUP has been received (see hup_handler elsewhere), 0
461c8e26105Sjp  * otherwise.  Uses an event port and a user-defined event.
462c8e26105Sjp  *
463c8e26105Sjp  * Note that port_get() does not update its timeout argument when EINTR,
464c8e26105Sjp  * unlike nanosleep().  We probably don't care very much here because
465c8e26105Sjp  * the only signals we expect are ones that will lead to idmapd dying or
466c8e26105Sjp  * SIGHUP, and we intend for the latter to cause this function to
467c8e26105Sjp  * return.  But if we did care then we could always use a timer event
468c8e26105Sjp  * (see timer_create(3RT)) and associate it with the same event port,
469c8e26105Sjp  * then we could get accurate waiting regardless of EINTRs.
470c8e26105Sjp  */
471c8e26105Sjp static
472c8e26105Sjp int
473c8e26105Sjp wait_for_ttl(struct timespec *timeout)
474c8e26105Sjp {
475c8e26105Sjp 	port_event_t pe;
476c8e26105Sjp 	int retries = 1;
477c8e26105Sjp 
478c8e26105Sjp 	/*
479c8e26105Sjp 	 * If event port creation failed earlier and fails now then we
480c8e26105Sjp 	 * simply don't learn about SIGHUPs in a timely fashion.  No big
481c8e26105Sjp 	 * deal
482c8e26105Sjp 	 */
483c8e26105Sjp 	if (hup_ev_port == -1 && (hup_ev_port = port_create()) < 0) {
484c8e26105Sjp 		(void) nanosleep(timeout, NULL);
485c8e26105Sjp 		return (0);
486c8e26105Sjp 	}
487c8e26105Sjp 
488c8e26105Sjp retry:
489c8e26105Sjp 	if (port_get(hup_ev_port, &pe, timeout) != 0) {
490c8e26105Sjp 		switch (errno) {
491c8e26105Sjp 		case EBADF:
492c8e26105Sjp 		case EBADFD:
493c8e26105Sjp 			hup_ev_port = -1;
494c8e26105Sjp 			(void) nanosleep(timeout, NULL);
495c8e26105Sjp 			break;
496c8e26105Sjp 		case EINVAL:
497c8e26105Sjp 			/*
498c8e26105Sjp 			 * Shouldn't happen, except, perhaps, near the
499c8e26105Sjp 			 * end of time
500c8e26105Sjp 			 */
501c8e26105Sjp 			timeout->tv_nsec = 0;
502c8e26105Sjp 			timeout->tv_sec = MAX_CHECK_TIME;
503c8e26105Sjp 			if (retries-- > 0)
504c8e26105Sjp 				goto retry;
505c8e26105Sjp 			/* NOTREACHED */
506c8e26105Sjp 			break;
507c8e26105Sjp 		case EINTR:
508c8e26105Sjp 			if (!hupped)
509c8e26105Sjp 				goto retry;
510c8e26105Sjp 			break;
511c8e26105Sjp 		case ETIME:
512c8e26105Sjp 			/* Timeout */
513c8e26105Sjp 			break;
514c8e26105Sjp 		default:
515c8e26105Sjp 			/* EFAULT */
516c8e26105Sjp 			(void) nanosleep(timeout, NULL);
517c8e26105Sjp 			break;
518c8e26105Sjp 		}
519c8e26105Sjp 	}
520c8e26105Sjp 
521c8e26105Sjp 	/*
522c8e26105Sjp 	 * We only have one event that we care about, a user event, so
523c8e26105Sjp 	 * there's nothing to check or clean up about pe.
524c8e26105Sjp 	 *
525c8e26105Sjp 	 * If we get here it's either because we had a SIGHUP and a user
526c8e26105Sjp 	 * event was sent to our port, or because the port_get() timed
527c8e26105Sjp 	 * out (or even both!).
528c8e26105Sjp 	 */
529c8e26105Sjp 
530c8e26105Sjp 	if (hupped) {
531e3c2d6aaSnw 		int rc;
532e3c2d6aaSnw 
533c8e26105Sjp 		hupped = 0;
534e3c2d6aaSnw 		/*
535e3c2d6aaSnw 		 * Blow away the ccache, we might have re-joined the
536e3c2d6aaSnw 		 * domain or joined a new one
537e3c2d6aaSnw 		 */
538e3c2d6aaSnw 		(void) unlink(IDMAP_CACHEDIR "/ccache");
539e3c2d6aaSnw 		/* HUP is the refresh method, so re-read SMF config */
540c8e26105Sjp 		(void) idmapdlog(LOG_INFO, "idmapd: SMF refresh");
541c8e26105Sjp 		WRLOCK_CONFIG();
542c8e26105Sjp 		(void) idmap_cfg_unload(&_idmapdstate.cfg->pgcfg);
543e3c2d6aaSnw 		rc = idmap_cfg_load(&_idmapdstate.cfg->handles,
544e3c2d6aaSnw 		    &_idmapdstate.cfg->pgcfg, 1);
545*e8c27ec8Sbaban 		if (rc < -1)
546e3c2d6aaSnw 			(void) idmapdlog(LOG_ERR,
547e3c2d6aaSnw 			    "idmapd: Various errors re-loading configuration "
548e3c2d6aaSnw 			    "will cause AD lookups to fail");
549*e8c27ec8Sbaban 		else if (rc == -1)
550e3c2d6aaSnw 			(void) idmapdlog(LOG_WARNING,
551e3c2d6aaSnw 			    "idmapd: Various errors re-loading configuration "
552e3c2d6aaSnw 			    "may cause AD lookups to fail");
553c8e26105Sjp 		UNLOCK_CONFIG();
554c8e26105Sjp 		return (1);
555c8e26105Sjp 	}
556c8e26105Sjp 
557c8e26105Sjp 	return (0);
558c8e26105Sjp }
559c8e26105Sjp 
560c8e26105Sjp void *
561c8e26105Sjp idmap_cfg_update_thread(void *arg)
562c8e26105Sjp {
563c8e26105Sjp 
564c8e26105Sjp 	idmap_pg_config_t	new_cfg;
565e3c2d6aaSnw 	int			ttl, changed;
566c8e26105Sjp 	idmap_cfg_handles_t	*handles = &_idmapdstate.cfg->handles;
567c8e26105Sjp 	idmap_pg_config_t	*live_cfg = &_idmapdstate.cfg->pgcfg;
568c8e26105Sjp 	ad_disc_t		ad_ctx = handles->ad_ctx;
569c8e26105Sjp 	struct timespec		delay;
570e3c2d6aaSnw 	int			first = 1;
571c8e26105Sjp 
572c8e26105Sjp 	(void) memset(&new_cfg, 0, sizeof (new_cfg));
573c8e26105Sjp 
574c8e26105Sjp 	for (;;) {
575c8e26105Sjp 		changed = FALSE;
576e3c2d6aaSnw 
577e3c2d6aaSnw 		if (first) {
578e3c2d6aaSnw 			ttl = 1;
579e3c2d6aaSnw 			first = 0;
580e3c2d6aaSnw 		} else {
581e3c2d6aaSnw 			ttl = ad_disc_get_TTL(ad_ctx);
582e3c2d6aaSnw 		}
583e3c2d6aaSnw 
584c8e26105Sjp 		if (ttl > MAX_CHECK_TIME)
585c8e26105Sjp 			ttl = MAX_CHECK_TIME;
586c8e26105Sjp 		while (ttl > 0 || ttl == -1) {
587c8e26105Sjp 			if (ttl == -1) {
588c8e26105Sjp 				wait_for_ttl(NULL);
589c8e26105Sjp 			} else if (ttl > SUBNET_CHECK_TIME) {
590c8e26105Sjp 				/*
591c8e26105Sjp 				 * We really ought to just monitor
592c8e26105Sjp 				 * network interfaces with a PF_ROUTE
593c8e26105Sjp 				 * socket...  This crude method of
594c8e26105Sjp 				 * discovering subnet changes will do
595c8e26105Sjp 				 * for now.  Though might even not want
596c8e26105Sjp 				 * to bother: subnet changes leading to
597c8e26105Sjp 				 * sitename changes ought never happen,
598c8e26105Sjp 				 * and requiring a refresh when they do
599c8e26105Sjp 				 * should be no problem (SMF/NWAM ought
600c8e26105Sjp 				 * to be able to refresh us).
601c8e26105Sjp 				 */
602c8e26105Sjp 				delay.tv_sec = SUBNET_CHECK_TIME;
603c8e26105Sjp 				delay.tv_nsec = 0;
604c8e26105Sjp 				if (wait_for_ttl(&delay)) {
605c8e26105Sjp 					/* Got SIGHUP, re-discover */
606c8e26105Sjp 					ttl = 0;
607c8e26105Sjp 					changed = TRUE;
608c8e26105Sjp 					break;
609c8e26105Sjp 				}
610c8e26105Sjp 				ttl -= SUBNET_CHECK_TIME;
611c8e26105Sjp 				if (ad_disc_SubnetChanged(ad_ctx))
612c8e26105Sjp 					break;
613c8e26105Sjp 			} else {
614c8e26105Sjp 				delay.tv_sec = ttl;
615c8e26105Sjp 				delay.tv_nsec = 0;
616c8e26105Sjp 				if (wait_for_ttl(&delay))
617c8e26105Sjp 					changed = TRUE;
618c8e26105Sjp 				ttl = 0;
619c8e26105Sjp 			}
620c8e26105Sjp 		}
621c8e26105Sjp 
622c8e26105Sjp 		/*
623c8e26105Sjp 		 * Load configuration data into a private copy.
624c8e26105Sjp 		 *
625c8e26105Sjp 		 * The fixed values (i.e., from SMF) have already been
626c8e26105Sjp 		 * set in AD auto discovery, so if all values have been
627c8e26105Sjp 		 * set in SMF and they haven't been changed or the
628c8e26105Sjp 		 * service been refreshed then the rest of this loop's
629c8e26105Sjp 		 * body is one big no-op.
630c8e26105Sjp 		 */
631c8e26105Sjp 		pthread_mutex_lock(&handles->mutex);
632c8e26105Sjp 
633c8e26105Sjp 		new_cfg.default_domain = ad_disc_get_DomainName(ad_ctx);
634c8e26105Sjp 		if (new_cfg.default_domain == NULL) {
635c8e26105Sjp 			idmapdlog(LOG_INFO,
636c8e26105Sjp 			    "%s: unable to discover Default Domain", me);
637c8e26105Sjp 		}
638c8e26105Sjp 
639c8e26105Sjp 		new_cfg.domain_name = ad_disc_get_DomainName(ad_ctx);
640c8e26105Sjp 		if (new_cfg.domain_name == NULL) {
641c8e26105Sjp 			idmapdlog(LOG_INFO,
642c8e26105Sjp 			    "%s: unable to discover Domain Name", me);
643c8e26105Sjp 		}
644c8e26105Sjp 
645c8e26105Sjp 		new_cfg.domain_controller =
646c8e26105Sjp 		    ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE);
647c8e26105Sjp 		if (new_cfg.domain_controller == NULL) {
648c8e26105Sjp 			idmapdlog(LOG_INFO,
649c8e26105Sjp 			    "%s: unable to discover Domain Controller", me);
650c8e26105Sjp 		}
651c8e26105Sjp 
652c8e26105Sjp 		new_cfg.forest_name = ad_disc_get_ForestName(ad_ctx);
653c8e26105Sjp 		if (new_cfg.forest_name == NULL) {
654c8e26105Sjp 			idmapdlog(LOG_INFO,
655c8e26105Sjp 			    "%s: unable to discover Forest Name", me);
656c8e26105Sjp 		}
657c8e26105Sjp 
658c8e26105Sjp 		new_cfg.site_name = ad_disc_get_SiteName(ad_ctx);
659c8e26105Sjp 		if (new_cfg.site_name == NULL) {
660c8e26105Sjp 			idmapdlog(LOG_INFO,
661c8e26105Sjp 			    "%s: unable to discover Site Name", me);
662c8e26105Sjp 		}
663c8e26105Sjp 
664c8e26105Sjp 		new_cfg.global_catalog =
665c8e26105Sjp 		    ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE);
666c8e26105Sjp 		if (new_cfg.global_catalog == NULL) {
667c8e26105Sjp 			idmapdlog(LOG_INFO,
668c8e26105Sjp 			    "%s: unable to discover Global Catalog", me);
669c8e26105Sjp 		}
670c8e26105Sjp 
671c8e26105Sjp 		pthread_mutex_unlock(&handles->mutex);
672c8e26105Sjp 
673c8e26105Sjp 		if (new_cfg.default_domain == NULL &&
674c8e26105Sjp 		    new_cfg.domain_name == NULL &&
675c8e26105Sjp 		    new_cfg.domain_controller == NULL &&
676c8e26105Sjp 		    new_cfg.forest_name == NULL &&
677c8e26105Sjp 		    new_cfg.global_catalog == NULL) {
678c8e26105Sjp 			idmapdlog(LOG_NOTICE, "%s: Could not auto-discover AD "
679c8e26105Sjp 			    "domain and forest names nor domain controllers "
680c8e26105Sjp 			    "and global catalog servers", me);
681c8e26105Sjp 			idmap_cfg_unload(&new_cfg);
682c8e26105Sjp 			continue;
683c8e26105Sjp 		}
684c8e26105Sjp 
685c8e26105Sjp 		/*
686c8e26105Sjp 		 * Update the live configuration
687c8e26105Sjp 		 */
688c8e26105Sjp 		WRLOCK_CONFIG();
689c8e26105Sjp 
690c8e26105Sjp 		if (live_cfg->list_size_limit != new_cfg.list_size_limit) {
691c8e26105Sjp 			idmapdlog(LOG_INFO, "%s: change list_size=%d", me,
692c8e26105Sjp 			    new_cfg.list_size_limit);
693c8e26105Sjp 			live_cfg->list_size_limit = new_cfg.list_size_limit;
694c8e26105Sjp 		}
695c8e26105Sjp 
696c8e26105Sjp 		/*
697c8e26105Sjp 		 * If default_domain came from SMF then we must not
698c8e26105Sjp 		 * auto-discover it.
699c8e26105Sjp 		 */
700c8e26105Sjp 		if (live_cfg->dflt_dom_set_in_smf == FALSE &&
701c8e26105Sjp 		    update_value(&live_cfg->default_domain,
702c8e26105Sjp 		    &new_cfg.default_domain, "default_domain") == TRUE)
703c8e26105Sjp 			changed = TRUE;
704c8e26105Sjp 
705c8e26105Sjp 		(void) update_value(&live_cfg->domain_name,
706c8e26105Sjp 		    &new_cfg.domain_name, "domain_name");
707c8e26105Sjp 
708c8e26105Sjp 		(void) update_dirs(&live_cfg->domain_controller,
709c8e26105Sjp 		    &new_cfg.domain_controller, "domain_controller");
710c8e26105Sjp 
711c8e26105Sjp 		(void) update_value(&live_cfg->forest_name,
712c8e26105Sjp 		    &new_cfg.forest_name, "forest_name");
713c8e26105Sjp 
714c8e26105Sjp 		(void) update_value(&live_cfg->site_name,
715c8e26105Sjp 		    &new_cfg.site_name, "site_name");
716c8e26105Sjp 
717c8e26105Sjp 		if (update_dirs(&live_cfg->global_catalog,
718c8e26105Sjp 		    &new_cfg.global_catalog, "global_catalog") == TRUE)
719c8e26105Sjp 			changed = TRUE;
720c8e26105Sjp 		UNLOCK_CONFIG();
721c8e26105Sjp 
722c8e26105Sjp 		idmap_cfg_unload(&new_cfg);
723c8e26105Sjp 
724c8e26105Sjp 
725c8e26105Sjp 		/*
726c8e26105Sjp 		 * Re-create the ad_t/ad_host_t objects if
727c8e26105Sjp 		 * either the default domain or the global
728c8e26105Sjp 		 * catalog server list changed.
729c8e26105Sjp 		 */
730c8e26105Sjp 
731c8e26105Sjp 		if (changed) {
732c8e26105Sjp 			RDLOCK_CONFIG();
733c8e26105Sjp 			(void) reload_ad();
734c8e26105Sjp 			UNLOCK_CONFIG();
735c8e26105Sjp 			print_idmapdstate();
736c8e26105Sjp 		}
737c8e26105Sjp 	}
738c8e26105Sjp 	/*NOTREACHED*/
739c8e26105Sjp 	return (NULL);
740c8e26105Sjp }
741c8e26105Sjp 
742c8e26105Sjp 
743c8e26105Sjp int
744c8e26105Sjp idmap_cfg_start_updates(idmap_cfg_t *cfg)
745c8e26105Sjp {
746c8e26105Sjp 	/* Don't check for failure -- see wait_for_ttl() */
747c8e26105Sjp 	hup_ev_port = port_create();
748c8e26105Sjp 
749c8e26105Sjp 	errno = pthread_create(&update_thread_handle, NULL,
750c8e26105Sjp 	    idmap_cfg_update_thread, NULL);
751c8e26105Sjp 	if (errno == 0)
752c8e26105Sjp 		return (0);
753c8e26105Sjp 	else
754c8e26105Sjp 		return (-1);
755c8e26105Sjp }
756c8e26105Sjp 
757c8e26105Sjp 
758c5c4113dSnw int
759e3c2d6aaSnw idmap_cfg_load(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
760e3c2d6aaSnw 	int discover)
761c5c4113dSnw {
762e3c2d6aaSnw 	int rc;
763e3c2d6aaSnw 	int errors = 0;
764*e8c27ec8Sbaban 	uint8_t bool_val;
765c8e26105Sjp 	char *str = NULL;
766c8e26105Sjp 	ad_disc_t ad_ctx = handles->ad_ctx;
767c5c4113dSnw 
768c8e26105Sjp 	pgcfg->list_size_limit = 0;
769c8e26105Sjp 	pgcfg->default_domain = NULL;
770c8e26105Sjp 	pgcfg->domain_name = NULL;
771c8e26105Sjp 	pgcfg->machine_sid = NULL;
772c8e26105Sjp 	pgcfg->domain_controller = NULL;
773c8e26105Sjp 	pgcfg->forest_name = NULL;
774c8e26105Sjp 	pgcfg->site_name = NULL;
775c8e26105Sjp 	pgcfg->global_catalog = NULL;
776*e8c27ec8Sbaban 	pgcfg->ad_unixuser_attr = NULL;
777*e8c27ec8Sbaban 	pgcfg->ad_unixgroup_attr = NULL;
778*e8c27ec8Sbaban 	pgcfg->nldap_winname_attr = NULL;
779*e8c27ec8Sbaban 	pgcfg->ds_name_mapping_enabled = FALSE;
780c5c4113dSnw 
781c8e26105Sjp 	pthread_mutex_lock(&handles->mutex);
782c8e26105Sjp 
783c8e26105Sjp 	ad_disc_refresh(handles->ad_ctx);
784c8e26105Sjp 
785c8e26105Sjp 	if (scf_pg_update(handles->config_pg) < 0) {
786651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s",
787651c0131Sbaban 		    me, scf_strerror(scf_error()));
788e3c2d6aaSnw 		rc = -2;
789c8e26105Sjp 		goto exit;
790c5c4113dSnw 	}
791c5c4113dSnw 
792c8e26105Sjp 	if (scf_pg_update(handles->general_pg) < 0) {
793651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s",
794651c0131Sbaban 		    me, scf_strerror(scf_error()));
795e3c2d6aaSnw 		rc = -2;
796c8e26105Sjp 		goto exit;
797c5c4113dSnw 	}
798c5c4113dSnw 
799c8e26105Sjp 	rc = get_val_int(handles, "list_size_limit",
800c8e26105Sjp 	    &pgcfg->list_size_limit, SCF_TYPE_COUNT);
801c8e26105Sjp 	if (rc != 0) {
802e3c2d6aaSnw 		pgcfg->list_size_limit = 0;
803e3c2d6aaSnw 		errors++;
804c8e26105Sjp 	}
805c5c4113dSnw 
806c8e26105Sjp 	rc = get_val_astring(handles, "domain_name",
807c8e26105Sjp 	    &pgcfg->domain_name);
808e3c2d6aaSnw 	if (rc != 0)
809e3c2d6aaSnw 		errors++;
810e3c2d6aaSnw 	else
811e3c2d6aaSnw 		(void) ad_disc_set_DomainName(ad_ctx, pgcfg->domain_name);
812c8e26105Sjp 
813c8e26105Sjp 	rc = get_val_astring(handles, "default_domain",
814c8e26105Sjp 	    &pgcfg->default_domain);
815c8e26105Sjp 	if (rc != 0) {
816e3c2d6aaSnw 		/*
817e3c2d6aaSnw 		 * SCF failures fetching config/default_domain we treat
818e3c2d6aaSnw 		 * as fatal as they may leave ID mapping rules that
819e3c2d6aaSnw 		 * match unqualified winnames flapping in the wind.
820e3c2d6aaSnw 		 */
821e3c2d6aaSnw 		rc = -2;
822c8e26105Sjp 		goto exit;
823c8e26105Sjp 	}
824c8e26105Sjp 
825c8e26105Sjp 	rc = get_val_astring(handles, "mapping_domain", &str);
826e3c2d6aaSnw 	if (rc != 0)
827e3c2d6aaSnw 		errors++;
828c5c4113dSnw 
829c5c4113dSnw 	/*
830c8e26105Sjp 	 * We treat default_domain as having been specified in SMF IFF
831c8e26105Sjp 	 * either (the config/default_domain property was set) or (the
832c8e26105Sjp 	 * old, obsolete, never documented config/mapping_domain
833c8e26105Sjp 	 * property was set and the new config/domain_name property was
834c8e26105Sjp 	 * not set).
835c5c4113dSnw 	 */
836c8e26105Sjp 	pgcfg->dflt_dom_set_in_smf = TRUE;
837c8e26105Sjp 	if (pgcfg->default_domain == NULL) {
838c8e26105Sjp 
839c8e26105Sjp 		pgcfg->dflt_dom_set_in_smf = FALSE;
840c8e26105Sjp 
841c8e26105Sjp 		if (pgcfg->domain_name != NULL) {
842c8e26105Sjp 			pgcfg->default_domain = strdup(pgcfg->domain_name);
843c8e26105Sjp 			if (str != NULL) {
844c8e26105Sjp 				idmapdlog(LOG_WARNING,
845c8e26105Sjp 				    "%s: Ignoring obsolete, undocumented "
846c8e26105Sjp 				    "config/mapping_domain property", me);
847c8e26105Sjp 			}
848c8e26105Sjp 		} else if (str != NULL) {
849c8e26105Sjp 			pgcfg->default_domain = strdup(str);
850c8e26105Sjp 			pgcfg->dflt_dom_set_in_smf = TRUE;
851c8e26105Sjp 			idmapdlog(LOG_WARNING,
852c8e26105Sjp 			    "%s: The config/mapping_domain property is "
853c8e26105Sjp 			    "obsolete; support for it will be removed, "
854c8e26105Sjp 			    "please use config/default_domain instead",
855c8e26105Sjp 			    me);
856c5c4113dSnw 		}
857c5c4113dSnw 	}
858c5c4113dSnw 
859c8e26105Sjp 	if (str != NULL)
860c8e26105Sjp 		free(str);
861c8e26105Sjp 
862c8e26105Sjp 	rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
863e3c2d6aaSnw 	if (rc != 0)
864e3c2d6aaSnw 		errors++;
865c8e26105Sjp 	if (pgcfg->machine_sid == NULL) {
8668edda628Sbaban 		/* If machine_sid not configured, generate one */
867c8e26105Sjp 		if (generate_machine_sid(&pgcfg->machine_sid) < 0) {
868e3c2d6aaSnw 			rc =  -2;
869c8e26105Sjp 			goto exit;
870c8e26105Sjp 		}
871c8e26105Sjp 		rc = set_val_astring(handles, "machine_sid",
872c8e26105Sjp 		    pgcfg->machine_sid);
873e3c2d6aaSnw 		if (rc != 0)
874e3c2d6aaSnw 			errors++;
8758edda628Sbaban 	}
876c5c4113dSnw 
877c8e26105Sjp 	str = NULL;
878c8e26105Sjp 	rc = get_val_ds(handles, "domain_controller", 389,
879c8e26105Sjp 	    &pgcfg->domain_controller);
880e3c2d6aaSnw 	if (rc != 0)
881e3c2d6aaSnw 		errors++;
882e3c2d6aaSnw 	else
883e3c2d6aaSnw 		(void) ad_disc_set_DomainController(ad_ctx,
884e3c2d6aaSnw 		    pgcfg->domain_controller);
885c5c4113dSnw 
886c8e26105Sjp 	rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
887e3c2d6aaSnw 	if (rc != 0)
888e3c2d6aaSnw 		errors++;
889e3c2d6aaSnw 	else
890e3c2d6aaSnw 		(void) ad_disc_set_ForestName(ad_ctx, pgcfg->forest_name);
891c8e26105Sjp 
892c8e26105Sjp 	rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
893e3c2d6aaSnw 	if (rc != 0)
894e3c2d6aaSnw 		errors++;
895e3c2d6aaSnw 	else
896e3c2d6aaSnw 		(void) ad_disc_set_SiteName(ad_ctx, pgcfg->site_name);
897c8e26105Sjp 
898c8e26105Sjp 	str = NULL;
899c8e26105Sjp 	rc = get_val_ds(handles, "global_catalog", 3268,
900c8e26105Sjp 	    &pgcfg->global_catalog);
901e3c2d6aaSnw 	if (rc != 0)
902e3c2d6aaSnw 		errors++;
903e3c2d6aaSnw 	else
904e3c2d6aaSnw 		(void) ad_disc_set_GlobalCatalog(ad_ctx, pgcfg->global_catalog);
905c8e26105Sjp 
906*e8c27ec8Sbaban 	/*
907*e8c27ec8Sbaban 	 * Read directory-based name mappings related SMF properties
908*e8c27ec8Sbaban 	 */
909*e8c27ec8Sbaban 	bool_val = 0;
910*e8c27ec8Sbaban 	rc = get_val_int(handles, "ds_name_mapping_enabled",
911*e8c27ec8Sbaban 	    &bool_val, SCF_TYPE_BOOLEAN);
912*e8c27ec8Sbaban 	if (rc != 0) {
913*e8c27ec8Sbaban 		rc = -2;
914*e8c27ec8Sbaban 		goto exit;
915*e8c27ec8Sbaban 	} else if (bool_val) {
916*e8c27ec8Sbaban 		pgcfg->ds_name_mapping_enabled = TRUE;
917*e8c27ec8Sbaban 		rc = get_val_astring(handles, "ad_unixuser_attr",
918*e8c27ec8Sbaban 		    &pgcfg->ad_unixuser_attr);
919*e8c27ec8Sbaban 		if (rc != 0) {
920*e8c27ec8Sbaban 			rc = -2;
921*e8c27ec8Sbaban 			goto exit;
922*e8c27ec8Sbaban 		}
923*e8c27ec8Sbaban 
924*e8c27ec8Sbaban 		rc = get_val_astring(handles, "ad_unixgroup_attr",
925*e8c27ec8Sbaban 		    &pgcfg->ad_unixgroup_attr);
926*e8c27ec8Sbaban 		if (rc != 0) {
927*e8c27ec8Sbaban 			rc = -2;
928*e8c27ec8Sbaban 			goto exit;
929*e8c27ec8Sbaban 		}
930*e8c27ec8Sbaban 
931*e8c27ec8Sbaban 		rc = get_val_astring(handles, "nldap_winname_attr",
932*e8c27ec8Sbaban 		    &pgcfg->nldap_winname_attr);
933*e8c27ec8Sbaban 		if (rc != 0) {
934*e8c27ec8Sbaban 			rc = -2;
935*e8c27ec8Sbaban 			goto exit;
936*e8c27ec8Sbaban 		}
937*e8c27ec8Sbaban 
938*e8c27ec8Sbaban 		if (pgcfg->nldap_winname_attr != NULL) {
939*e8c27ec8Sbaban 			idmapdlog(LOG_ERR,
940*e8c27ec8Sbaban 			    "%s: native LDAP based name mapping not supported "
941*e8c27ec8Sbaban 			    "at this time. Please unset "
942*e8c27ec8Sbaban 			    "config/nldap_winname_attr and restart idmapd.",
943*e8c27ec8Sbaban 			    me);
944*e8c27ec8Sbaban 			rc = -3;
945*e8c27ec8Sbaban 			goto exit;
946*e8c27ec8Sbaban 		}
947*e8c27ec8Sbaban 
948*e8c27ec8Sbaban 		if (pgcfg->ad_unixuser_attr == NULL &&
949*e8c27ec8Sbaban 		    pgcfg->ad_unixgroup_attr == NULL) {
950*e8c27ec8Sbaban 			idmapdlog(LOG_ERR,
951*e8c27ec8Sbaban 			    "%s: If config/ds_name_mapping_enabled property "
952*e8c27ec8Sbaban 			    "is set to true then atleast one of the following "
953*e8c27ec8Sbaban 			    "name mapping attributes must be specified. "
954*e8c27ec8Sbaban 			    "(config/ad_unixuser_attr OR "
955*e8c27ec8Sbaban 			    "config/ad_unixgroup_attr)", me);
956*e8c27ec8Sbaban 			rc = -3;
957*e8c27ec8Sbaban 			goto exit;
958*e8c27ec8Sbaban 		}
959*e8c27ec8Sbaban 	}
960*e8c27ec8Sbaban 
961c8e26105Sjp 
962e3c2d6aaSnw 	if (!discover)
963e3c2d6aaSnw 		goto exit;
964e3c2d6aaSnw 
965c8e26105Sjp 	/*
966c8e26105Sjp 	 * Auto Discover the rest
967c8e26105Sjp 	 */
968c8e26105Sjp 	if (pgcfg->default_domain == NULL) {
969c8e26105Sjp 		pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx);
970c8e26105Sjp 		if (pgcfg->default_domain == NULL) {
971c8e26105Sjp 			idmapdlog(LOG_INFO,
972c8e26105Sjp 			    "%s: unable to discover Default Domain", me);
973c8e26105Sjp 		}
974c8e26105Sjp 	}
975c8e26105Sjp 
976c8e26105Sjp 	if (pgcfg->domain_name == NULL) {
977c8e26105Sjp 		pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx);
978c8e26105Sjp 		if (pgcfg->domain_name == NULL) {
979c8e26105Sjp 			idmapdlog(LOG_INFO,
980c8e26105Sjp 			    "%s: unable to discover Domain Name", me);
981c8e26105Sjp 		}
982c8e26105Sjp 	}
983c8e26105Sjp 
984c8e26105Sjp 	if (pgcfg->domain_controller == NULL) {
985c8e26105Sjp 		pgcfg->domain_controller =
986c8e26105Sjp 		    ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE);
987c8e26105Sjp 		if (pgcfg->domain_controller == NULL) {
988c8e26105Sjp 			idmapdlog(LOG_INFO,
989c8e26105Sjp 			    "%s: unable to discover Domain Controller", me);
990c8e26105Sjp 		}
991c8e26105Sjp 	}
992c8e26105Sjp 
993c8e26105Sjp 	if (pgcfg->forest_name == NULL) {
994c8e26105Sjp 		pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx);
995c8e26105Sjp 		if (pgcfg->forest_name == NULL) {
996c8e26105Sjp 			idmapdlog(LOG_INFO,
997c8e26105Sjp 			    "%s: unable to discover Forest Name", me);
998c8e26105Sjp 		}
999c8e26105Sjp 	}
1000c8e26105Sjp 
1001c8e26105Sjp 	if (pgcfg->site_name == NULL) {
1002c8e26105Sjp 		pgcfg->site_name = ad_disc_get_SiteName(ad_ctx);
1003c8e26105Sjp 		if (pgcfg->site_name == NULL) {
1004c8e26105Sjp 			idmapdlog(LOG_INFO,
1005c8e26105Sjp 			    "%s: unable to discover Site Name", me);
1006c8e26105Sjp 		}
1007c8e26105Sjp 	}
1008c8e26105Sjp 
1009c8e26105Sjp 	if (pgcfg->global_catalog == NULL) {
1010c8e26105Sjp 		pgcfg->global_catalog =
1011c8e26105Sjp 		    ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE);
1012c8e26105Sjp 		if (pgcfg->global_catalog == NULL) {
1013c8e26105Sjp 			idmapdlog(LOG_INFO,
1014c8e26105Sjp 			    "%s: unable to discover Global Catalog", me);
1015c8e26105Sjp 		}
1016c8e26105Sjp 	}
1017e3c2d6aaSnw 
1018c8e26105Sjp exit:
1019c8e26105Sjp 	pthread_mutex_unlock(&handles->mutex);
1020c5c4113dSnw 
1021*e8c27ec8Sbaban 	if (rc < -1)
1022e3c2d6aaSnw 		return (rc);
1023e3c2d6aaSnw 
1024e3c2d6aaSnw 	return ((errors == 0) ? 0 : -1);
1025c5c4113dSnw }
1026c5c4113dSnw 
1027651c0131Sbaban /*
1028651c0131Sbaban  * Initialize 'cfg'.
1029651c0131Sbaban  */
1030c5c4113dSnw idmap_cfg_t *
1031c5c4113dSnw idmap_cfg_init() {
1032c8e26105Sjp 	idmap_cfg_handles_t *handles;
1033c5c4113dSnw 
1034c5c4113dSnw 	/* First the smf repository handles: */
1035c5c4113dSnw 	idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
1036c5c4113dSnw 	if (!cfg) {
1037651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: Out of memory", me);
1038c5c4113dSnw 		return (NULL);
1039c5c4113dSnw 	}
1040c8e26105Sjp 	handles = &cfg->handles;
1041c5c4113dSnw 
1042c8e26105Sjp 	(void) pthread_mutex_init(&handles->mutex, NULL);
1043c8e26105Sjp 
1044c8e26105Sjp 	if (!(handles->main = scf_handle_create(SCF_VERSION))) {
1045651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf_handle_create() failed: %s",
1046651c0131Sbaban 		    me, scf_strerror(scf_error()));
1047c5c4113dSnw 		goto error;
1048c5c4113dSnw 	}
1049c5c4113dSnw 
1050c8e26105Sjp 	if (scf_handle_bind(handles->main) < 0) {
1051651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf_handle_bind() failed: %s",
1052651c0131Sbaban 		    me, scf_strerror(scf_error()));
1053c5c4113dSnw 		goto error;
1054c5c4113dSnw 	}
1055c5c4113dSnw 
1056c8e26105Sjp 	if (!(handles->service = scf_service_create(handles->main)) ||
1057c8e26105Sjp 	    !(handles->instance = scf_instance_create(handles->main)) ||
1058c8e26105Sjp 	    !(handles->config_pg = scf_pg_create(handles->main)) ||
1059c8e26105Sjp 	    !(handles->general_pg = scf_pg_create(handles->main))) {
1060651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf handle creation failed: %s",
1061651c0131Sbaban 		    me, scf_strerror(scf_error()));
1062c5c4113dSnw 		goto error;
1063c5c4113dSnw 	}
1064c5c4113dSnw 
1065c8e26105Sjp 	if (scf_handle_decode_fmri(handles->main,
1066c5c4113dSnw 		FMRI_BASE "/:properties/" CONFIG_PG,
1067c5c4113dSnw 		NULL,				/* scope */
1068c8e26105Sjp 		handles->service,		/* service */
1069c8e26105Sjp 		handles->instance,		/* instance */
1070c8e26105Sjp 		handles->config_pg,		/* pg */
1071c5c4113dSnw 		NULL,				/* prop */
1072c8e26105Sjp 		SCF_DECODE_FMRI_EXACT) < 0) {
1073651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf_handle_decode_fmri() failed: %s",
1074651c0131Sbaban 		    me, scf_strerror(scf_error()));
1075c5c4113dSnw 		goto error;
1076c5c4113dSnw 
1077c5c4113dSnw 	}
1078c5c4113dSnw 
1079c8e26105Sjp 	if (scf_service_get_pg(handles->service,
1080c8e26105Sjp 		GENERAL_PG, handles->general_pg) < 0) {
1081651c0131Sbaban 		idmapdlog(LOG_ERR, "%s: scf_service_get_pg() failed: %s",
1082651c0131Sbaban 		    me, scf_strerror(scf_error()));
1083c5c4113dSnw 		goto error;
1084c5c4113dSnw 	}
1085c5c4113dSnw 
1086c8e26105Sjp 	/* Initialize AD Auto Discovery context */
1087c8e26105Sjp 	handles->ad_ctx = ad_disc_init();
1088c8e26105Sjp 	if (handles->ad_ctx == NULL)
1089c8e26105Sjp 		goto error;
1090c8e26105Sjp 
1091c5c4113dSnw 	return (cfg);
1092c5c4113dSnw 
1093c5c4113dSnw error:
1094c5c4113dSnw 	(void) idmap_cfg_fini(cfg);
1095c5c4113dSnw 	return (NULL);
1096c5c4113dSnw }
1097c5c4113dSnw 
1098c8e26105Sjp void
1099c8e26105Sjp idmap_cfg_unload(idmap_pg_config_t *pgcfg) {
1100c8e26105Sjp 
1101c8e26105Sjp 	if (pgcfg->default_domain) {
1102c8e26105Sjp 		free(pgcfg->default_domain);
1103c8e26105Sjp 		pgcfg->default_domain = NULL;
1104c8e26105Sjp 	}
1105c8e26105Sjp 	if (pgcfg->domain_name) {
1106c8e26105Sjp 		free(pgcfg->domain_name);
1107c8e26105Sjp 		pgcfg->domain_name = NULL;
1108c8e26105Sjp 	}
1109c8e26105Sjp 	if (pgcfg->machine_sid) {
1110c8e26105Sjp 		free(pgcfg->machine_sid);
1111c8e26105Sjp 		pgcfg->machine_sid = NULL;
1112c8e26105Sjp 	}
1113c8e26105Sjp 	if (pgcfg->domain_controller) {
1114c5c4113dSnw 		free(pgcfg->domain_controller);
1115c8e26105Sjp 		pgcfg->domain_controller = NULL;
1116c8e26105Sjp 	}
1117c8e26105Sjp 	if (pgcfg->forest_name) {
1118c8e26105Sjp 		free(pgcfg->forest_name);
1119c8e26105Sjp 		pgcfg->forest_name = NULL;
1120c8e26105Sjp 	}
1121c8e26105Sjp 	if (pgcfg->site_name) {
1122c8e26105Sjp 		free(pgcfg->site_name);
1123c8e26105Sjp 		pgcfg->site_name = NULL;
1124c8e26105Sjp 	}
1125c8e26105Sjp 	if (pgcfg->global_catalog) {
1126c8e26105Sjp 		free(pgcfg->global_catalog);
1127c8e26105Sjp 		pgcfg->global_catalog = NULL;
1128c8e26105Sjp 	}
1129*e8c27ec8Sbaban 	if (pgcfg->ad_unixuser_attr) {
1130*e8c27ec8Sbaban 		free(pgcfg->ad_unixuser_attr);
1131*e8c27ec8Sbaban 		pgcfg->ad_unixuser_attr = NULL;
1132*e8c27ec8Sbaban 	}
1133*e8c27ec8Sbaban 	if (pgcfg->ad_unixgroup_attr) {
1134*e8c27ec8Sbaban 		free(pgcfg->ad_unixgroup_attr);
1135*e8c27ec8Sbaban 		pgcfg->ad_unixgroup_attr = NULL;
1136*e8c27ec8Sbaban 	}
1137*e8c27ec8Sbaban 	if (pgcfg->nldap_winname_attr) {
1138*e8c27ec8Sbaban 		free(pgcfg->nldap_winname_attr);
1139*e8c27ec8Sbaban 		pgcfg->nldap_winname_attr = NULL;
1140*e8c27ec8Sbaban 	}
1141c5c4113dSnw }
1142c5c4113dSnw 
1143c5c4113dSnw int
1144c5c4113dSnw idmap_cfg_fini(idmap_cfg_t *cfg)
1145c5c4113dSnw {
1146c8e26105Sjp 	idmap_cfg_handles_t *handles = &cfg->handles;
1147c8e26105Sjp 	idmap_cfg_unload(&cfg->pgcfg);
1148c8e26105Sjp 
1149c8e26105Sjp 	(void) pthread_mutex_destroy(&handles->mutex);
1150c8e26105Sjp 	scf_pg_destroy(handles->config_pg);
1151c8e26105Sjp 	scf_pg_destroy(handles->general_pg);
1152c8e26105Sjp 	scf_instance_destroy(handles->instance);
1153c8e26105Sjp 	scf_service_destroy(handles->service);
1154c8e26105Sjp 	scf_handle_destroy(handles->main);
1155*e8c27ec8Sbaban 	if (handles->ad_ctx != NULL)
1156*e8c27ec8Sbaban 		ad_disc_fini(handles->ad_ctx);
1157c5c4113dSnw 	free(cfg);
1158c5c4113dSnw 
1159c5c4113dSnw 	return (0);
1160c5c4113dSnw }
1161