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 /*
224edd44c5Sjp  * Copyright 2008 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>
430dcc7149Snw #include <net/route.h>
44c8e26105Sjp #include "addisc.h"
45c5c4113dSnw 
460dcc7149Snw #define	MACHINE_SID_LEN		(9 + UUID_LEN/4 * 11)
470dcc7149Snw #define	FMRI_BASE		"svc:/system/idmap"
480dcc7149Snw #define	CONFIG_PG		"config"
490dcc7149Snw #define	GENERAL_PG		"general"
500dcc7149Snw #define	RECONFIGURE		1
510dcc7149Snw #define	POKE_AUTO_DISCOVERY	2
52c5c4113dSnw 
53c8e26105Sjp /*LINTLIBRARY*/
54c8e26105Sjp 
55c8e26105Sjp 
56c8e26105Sjp static pthread_t update_thread_handle = 0;
57c8e26105Sjp 
580dcc7149Snw static int idmapd_ev_port = -1;
590dcc7149Snw static int rt_sock = -1;
60c8e26105Sjp 
618edda628Sbaban static int
624edd44c5Sjp generate_machine_sid(char **machine_sid)
634edd44c5Sjp {
648edda628Sbaban 	char *p;
658edda628Sbaban 	uuid_t uu;
668edda628Sbaban 	int i, j, len, rlen;
678edda628Sbaban 	uint32_t rid;
688edda628Sbaban 
698edda628Sbaban 	/*
708edda628Sbaban 	 * Generate and split 128-bit UUID into four 32-bit RIDs
718edda628Sbaban 	 * The machine_sid will be of the form S-1-5-N1-N2-N3-N4
728edda628Sbaban 	 * We depart from Windows here, which instead of 128
738edda628Sbaban 	 * bits worth of random numbers uses 96 bits.
748edda628Sbaban 	 */
758edda628Sbaban 
768edda628Sbaban 	*machine_sid = calloc(1, MACHINE_SID_LEN);
778edda628Sbaban 	if (*machine_sid == NULL) {
7871590c90Snw 		idmapdlog(LOG_ERR, "Out of memory");
798edda628Sbaban 		return (-1);
808edda628Sbaban 	}
818edda628Sbaban 	(void) strcpy(*machine_sid, "S-1-5-21");
828edda628Sbaban 	p = *machine_sid + strlen("S-1-5-21");
838edda628Sbaban 	len = MACHINE_SID_LEN - strlen("S-1-5-21");
848edda628Sbaban 
858edda628Sbaban 	uuid_clear(uu);
868edda628Sbaban 	uuid_generate_random(uu);
878edda628Sbaban 
888edda628Sbaban 	for (i = 0; i < UUID_LEN/4; i++) {
898edda628Sbaban 		j = i * 4;
908edda628Sbaban 		rid = (uu[j] << 24) | (uu[j + 1] << 16) |
914edd44c5Sjp 		    (uu[j + 2] << 8) | (uu[j + 3]);
928edda628Sbaban 		rlen = snprintf(p, len, "-%u", rid);
938edda628Sbaban 		p += rlen;
948edda628Sbaban 		len -= rlen;
958edda628Sbaban 	}
968edda628Sbaban 
978edda628Sbaban 	return (0);
988edda628Sbaban }
998edda628Sbaban 
100*479ac375Sdm 
101*479ac375Sdm /* In the case of error, exists is set to FALSE anyway */
102*479ac375Sdm static int
103*479ac375Sdm prop_exists(idmap_cfg_handles_t *handles, char *name, bool_t *exists)
10471590c90Snw {
10571590c90Snw 
106*479ac375Sdm 	scf_property_t *scf_prop;
107*479ac375Sdm 	scf_value_t *value;
108*479ac375Sdm 
109*479ac375Sdm 	*exists = FALSE;
110*479ac375Sdm 
111*479ac375Sdm 	scf_prop = scf_property_create(handles->main);
112*479ac375Sdm 	if (scf_prop == NULL) {
113*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
114*479ac375Sdm 		    scf_strerror(scf_error()));
115*479ac375Sdm 		return (-1);
116*479ac375Sdm 	}
117*479ac375Sdm 	value = scf_value_create(handles->main);
118*479ac375Sdm 	if (value == NULL) {
119*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
120*479ac375Sdm 		    scf_strerror(scf_error()));
121*479ac375Sdm 		scf_property_destroy(scf_prop);
122*479ac375Sdm 		return (-1);
123*479ac375Sdm 	}
12471590c90Snw 
12571590c90Snw 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0)
126*479ac375Sdm 		*exists = TRUE;
12771590c90Snw 
12871590c90Snw 	scf_value_destroy(value);
12971590c90Snw 	scf_property_destroy(scf_prop);
13071590c90Snw 
131*479ac375Sdm 	return (0);
13271590c90Snw }
13371590c90Snw 
134c5c4113dSnw /* Check if in the case of failure the original value of *val is preserved */
135c5c4113dSnw static int
136c8e26105Sjp get_val_int(idmap_cfg_handles_t *handles, char *name,
137c8e26105Sjp 	void *val, scf_type_t type)
138c5c4113dSnw {
139c5c4113dSnw 	int rc = 0;
140c5c4113dSnw 
141*479ac375Sdm 	scf_property_t *scf_prop;
142*479ac375Sdm 	scf_value_t *value;
143*479ac375Sdm 
144*479ac375Sdm 	scf_prop = scf_property_create(handles->main);
145*479ac375Sdm 	if (scf_prop == NULL) {
146*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
147*479ac375Sdm 		    scf_strerror(scf_error()));
148*479ac375Sdm 		return (-1);
149*479ac375Sdm 	}
150*479ac375Sdm 	value = scf_value_create(handles->main);
151*479ac375Sdm 	if (value == NULL) {
152*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
153*479ac375Sdm 		    scf_strerror(scf_error()));
154*479ac375Sdm 		scf_property_destroy(scf_prop);
155*479ac375Sdm 		return (-1);
156*479ac375Sdm 	}
157c5c4113dSnw 
158c8e26105Sjp 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
159c5c4113dSnw 	/* this is OK: the property is just undefined */
160c5c4113dSnw 		goto destruction;
161c5c4113dSnw 
162c5c4113dSnw 
163c8e26105Sjp 	if (scf_property_get_value(scf_prop, value) < 0)
164c5c4113dSnw 	/* It is still OK when a property doesn't have any value */
165c5c4113dSnw 		goto destruction;
166c5c4113dSnw 
167c5c4113dSnw 	switch (type) {
168c5c4113dSnw 	case SCF_TYPE_BOOLEAN:
169c5c4113dSnw 		rc = scf_value_get_boolean(value, val);
170c5c4113dSnw 		break;
171c5c4113dSnw 	case SCF_TYPE_COUNT:
172c5c4113dSnw 		rc = scf_value_get_count(value, val);
173c5c4113dSnw 		break;
174c5c4113dSnw 	case SCF_TYPE_INTEGER:
175c5c4113dSnw 		rc = scf_value_get_integer(value, val);
176c5c4113dSnw 		break;
177c5c4113dSnw 	default:
17871590c90Snw 		idmapdlog(LOG_ERR, "Invalid scf integer type (%d)",
17971590c90Snw 		    type);
180c5c4113dSnw 		rc = -1;
181c5c4113dSnw 		break;
182c5c4113dSnw 	}
183c5c4113dSnw 
184c5c4113dSnw 
185c5c4113dSnw destruction:
186c5c4113dSnw 	scf_value_destroy(value);
187c5c4113dSnw 	scf_property_destroy(scf_prop);
188c5c4113dSnw 
189c5c4113dSnw 	return (rc);
190c5c4113dSnw }
191c5c4113dSnw 
192c5c4113dSnw static char *
1934edd44c5Sjp scf_value2string(scf_value_t *value)
1944edd44c5Sjp {
195c5c4113dSnw 	int rc = -1;
196c5c4113dSnw 	char buf_size = 127;
197c5c4113dSnw 	int length;
198c5c4113dSnw 	char *buf = NULL;
199c5c4113dSnw 	buf = (char *) malloc(sizeof (char) * buf_size);
200c5c4113dSnw 
201c5c4113dSnw 	for (;;) {
202c5c4113dSnw 		length = scf_value_get_astring(value, buf, buf_size);
203c5c4113dSnw 		if (length < 0) {
204c5c4113dSnw 			rc = -1;
205c5c4113dSnw 			goto destruction;
206c5c4113dSnw 		}
207c5c4113dSnw 
208c5c4113dSnw 		if (length == buf_size - 1) {
209c5c4113dSnw 			buf_size *= 2;
210c5c4113dSnw 			buf = (char *)realloc(buf, buf_size * sizeof (char));
211c5c4113dSnw 			if (!buf) {
21271590c90Snw 				idmapdlog(LOG_ERR, "Out of memory");
213c5c4113dSnw 				rc = -1;
214c5c4113dSnw 				goto destruction;
215c5c4113dSnw 			}
216c5c4113dSnw 		} else {
217c5c4113dSnw 			rc = 0;
2184edd44c5Sjp 			break;
2194edd44c5Sjp 		}
220c5c4113dSnw 	}
221c5c4113dSnw 
222c5c4113dSnw destruction:
223c5c4113dSnw 	if (rc < 0) {
224c5c4113dSnw 		if (buf)
225c5c4113dSnw 			free(buf);
226c5c4113dSnw 		buf = NULL;
227c5c4113dSnw 	}
228c5c4113dSnw 
229c5c4113dSnw 	return (buf);
230c5c4113dSnw }
231c5c4113dSnw 
232c8e26105Sjp static int
233c8e26105Sjp get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport,
234*479ac375Sdm 		idmap_ad_disc_ds_t **val)
235c8e26105Sjp {
236*479ac375Sdm 	idmap_ad_disc_ds_t *servers = NULL;
237c8e26105Sjp 	scf_property_t *scf_prop;
238c8e26105Sjp 	scf_value_t *value;
239c8e26105Sjp 	scf_iter_t *iter;
240c8e26105Sjp 	char *host, *portstr;
241e3c2d6aaSnw 	int len, i;
242c8e26105Sjp 	int count = 0;
243e3c2d6aaSnw 	int rc = -1;
244c8e26105Sjp 
245c8e26105Sjp 	*val = NULL;
246c8e26105Sjp 
247c8e26105Sjp restart:
248c8e26105Sjp 	scf_prop = scf_property_create(handles->main);
249*479ac375Sdm 	if (scf_prop == NULL) {
250*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
251*479ac375Sdm 		    scf_strerror(scf_error()));
252*479ac375Sdm 		return (-1);
253*479ac375Sdm 	}
254*479ac375Sdm 
255c8e26105Sjp 	value = scf_value_create(handles->main);
256*479ac375Sdm 	if (value == NULL) {
257*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
258*479ac375Sdm 		    scf_strerror(scf_error()));
259*479ac375Sdm 		scf_property_destroy(scf_prop);
260*479ac375Sdm 		return (-1);
261*479ac375Sdm 	}
262*479ac375Sdm 
263c8e26105Sjp 	iter = scf_iter_create(handles->main);
264*479ac375Sdm 	if (iter == NULL) {
265*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_iter_create() failed: %s",
266*479ac375Sdm 		    scf_strerror(scf_error()));
267*479ac375Sdm 		scf_value_destroy(value);
268*479ac375Sdm 		scf_property_destroy(scf_prop);
269*479ac375Sdm 		return (-1);
270*479ac375Sdm 	}
271c8e26105Sjp 
272e3c2d6aaSnw 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
273c8e26105Sjp 		/* this is OK: the property is just undefined */
274e3c2d6aaSnw 		rc = 0;
275c8e26105Sjp 		goto destruction;
276e3c2d6aaSnw 	}
277c8e26105Sjp 
278c8e26105Sjp 	if (scf_iter_property_values(iter, scf_prop) < 0) {
279c8e26105Sjp 		idmapdlog(LOG_ERR,
28071590c90Snw 		    "scf_iter_property_values(%s) failed: %s",
28171590c90Snw 		    name, scf_strerror(scf_error()));
282c8e26105Sjp 		goto destruction;
283c8e26105Sjp 	}
284c8e26105Sjp 
285c8e26105Sjp 	/* Workaround scf bugs -- can't reset an iteration */
286c8e26105Sjp 	if (count == 0) {
287c8e26105Sjp 		while (scf_iter_next_value(iter, value) > 0)
288c8e26105Sjp 			count++;
289c8e26105Sjp 
290e3c2d6aaSnw 		if (count == 0) {
291c8e26105Sjp 			/* no values */
292e3c2d6aaSnw 			rc = 0;
293c8e26105Sjp 			goto destruction;
294e3c2d6aaSnw 		}
295c8e26105Sjp 
296c8e26105Sjp 		scf_value_destroy(value);
297c8e26105Sjp 		scf_iter_destroy(iter);
298c8e26105Sjp 		scf_property_destroy(scf_prop);
299c8e26105Sjp 		goto restart;
300c8e26105Sjp 	}
301c8e26105Sjp 
302c8e26105Sjp 	if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
30371590c90Snw 		idmapdlog(LOG_ERR, "Out of memory");
304c8e26105Sjp 		goto destruction;
305c8e26105Sjp 	}
306c8e26105Sjp 
307e3c2d6aaSnw 	i = 0;
308e3c2d6aaSnw 	while (i < count && scf_iter_next_value(iter, value) > 0) {
309e3c2d6aaSnw 		servers[i].priority = 0;
310e3c2d6aaSnw 		servers[i].weight = 100;
311e3c2d6aaSnw 		servers[i].port = defport;
312c8e26105Sjp 		if ((host = scf_value2string(value)) == NULL) {
313c8e26105Sjp 			goto destruction;
314c8e26105Sjp 		}
315c8e26105Sjp 		if ((portstr = strchr(host, ':')) != NULL) {
316c8e26105Sjp 			*portstr++ = '\0';
317e3c2d6aaSnw 			servers[i].port = strtol(portstr,
318c8e26105Sjp 			    (char **)NULL, 10);
319e3c2d6aaSnw 			if (servers[i].port == 0)
320e3c2d6aaSnw 				servers[i].port = defport;
321c8e26105Sjp 		}
322e3c2d6aaSnw 		len = strlcpy(servers[i].host, host,
323c8e26105Sjp 		    sizeof (servers->host));
324c8e26105Sjp 
325c8e26105Sjp 		free(host);
326c8e26105Sjp 
327c8e26105Sjp 		/* Ignore this server if the hostname is too long */
328c8e26105Sjp 		if (len < sizeof (servers->host))
329e3c2d6aaSnw 			i++;
330c8e26105Sjp 	}
331c8e26105Sjp 
332c8e26105Sjp 	*val = servers;
333c8e26105Sjp 
334e3c2d6aaSnw 	rc = 0;
335e3c2d6aaSnw 
336c8e26105Sjp destruction:
337c8e26105Sjp 	scf_value_destroy(value);
338c8e26105Sjp 	scf_iter_destroy(iter);
339c8e26105Sjp 	scf_property_destroy(scf_prop);
340c8e26105Sjp 
341c8e26105Sjp 	if (rc < 0) {
342c8e26105Sjp 		if (servers)
343c8e26105Sjp 			free(servers);
344c8e26105Sjp 		*val = NULL;
345c8e26105Sjp 	}
346c8e26105Sjp 
347c8e26105Sjp 	return (rc);
348c8e26105Sjp }
349c8e26105Sjp 
350c5c4113dSnw 
351c5c4113dSnw static int
352c8e26105Sjp get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val)
353c5c4113dSnw {
354c5c4113dSnw 	int rc = 0;
355c5c4113dSnw 
356*479ac375Sdm 	scf_property_t *scf_prop;
357*479ac375Sdm 	scf_value_t *value;
358*479ac375Sdm 
359*479ac375Sdm 	scf_prop = scf_property_create(handles->main);
360*479ac375Sdm 	if (scf_prop == NULL) {
361*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
362*479ac375Sdm 		    scf_strerror(scf_error()));
363*479ac375Sdm 		return (-1);
364*479ac375Sdm 	}
365*479ac375Sdm 	value = scf_value_create(handles->main);
366*479ac375Sdm 	if (value == NULL) {
367*479ac375Sdm 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
368*479ac375Sdm 		    scf_strerror(scf_error()));
369*479ac375Sdm 		scf_property_destroy(scf_prop);
370*479ac375Sdm 		return (-1);
371*479ac375Sdm 	}
372c5c4113dSnw 
373c8e26105Sjp 	*val = NULL;
374c5c4113dSnw 
375c8e26105Sjp 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
376c5c4113dSnw 	/* this is OK: the property is just undefined */
377c5c4113dSnw 		goto destruction;
378c5c4113dSnw 
379c8e26105Sjp 	if (scf_property_get_value(scf_prop, value) < 0) {
380651c0131Sbaban 		idmapdlog(LOG_ERR,
38171590c90Snw 		    "scf_property_get_value(%s) failed: %s",
38271590c90Snw 		    name, scf_strerror(scf_error()));
383c5c4113dSnw 		rc = -1;
384c5c4113dSnw 		goto destruction;
385c5c4113dSnw 	}
386c5c4113dSnw 
387c8e26105Sjp 	if (!(*val = scf_value2string(value)))
388c5c4113dSnw 		rc = -1;
389c5c4113dSnw 
390c5c4113dSnw destruction:
391c5c4113dSnw 	scf_value_destroy(value);
392c5c4113dSnw 	scf_property_destroy(scf_prop);
393c5c4113dSnw 
394c5c4113dSnw 	if (rc < 0) {
395c5c4113dSnw 		if (*val)
396c5c4113dSnw 			free(*val);
397c5c4113dSnw 		*val = NULL;
398c5c4113dSnw 	}
399c5c4113dSnw 
400c5c4113dSnw 	return (rc);
401c5c4113dSnw }
402c5c4113dSnw 
403c8e26105Sjp 
4048edda628Sbaban static int
405c8e26105Sjp set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val)
4068edda628Sbaban {
407e3c2d6aaSnw 	int			rc = -1;
408e3c2d6aaSnw 	int			ret = -2;
409e3c2d6aaSnw 	int			i;
4108edda628Sbaban 	scf_property_t		*scf_prop = NULL;
4118edda628Sbaban 	scf_value_t		*value = NULL;
4128edda628Sbaban 	scf_transaction_t	*tx = NULL;
4138edda628Sbaban 	scf_transaction_entry_t	*ent = NULL;
4148edda628Sbaban 
415c8e26105Sjp 	if ((scf_prop = scf_property_create(handles->main)) == NULL ||
416c8e26105Sjp 	    (value = scf_value_create(handles->main)) == NULL ||
417c8e26105Sjp 	    (tx = scf_transaction_create(handles->main)) == NULL ||
418c8e26105Sjp 	    (ent = scf_entry_create(handles->main)) == NULL) {
41971590c90Snw 		idmapdlog(LOG_ERR, "Unable to set property %s",
42071590c90Snw 		    name, scf_strerror(scf_error()));
4218edda628Sbaban 		goto destruction;
4228edda628Sbaban 	}
4238edda628Sbaban 
424e3c2d6aaSnw 	for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) {
425c8e26105Sjp 		if (scf_transaction_start(tx, handles->config_pg) == -1) {
4268edda628Sbaban 			idmapdlog(LOG_ERR,
42771590c90Snw 			    "scf_transaction_start(%s) failed: %s",
42871590c90Snw 			    name, scf_strerror(scf_error()));
4298edda628Sbaban 			goto destruction;
4308edda628Sbaban 		}
4318edda628Sbaban 
432e3c2d6aaSnw 		if (scf_transaction_property_new(tx, ent, name,
433e3c2d6aaSnw 		    SCF_TYPE_ASTRING) < 0) {
4348edda628Sbaban 			idmapdlog(LOG_ERR,
43571590c90Snw 			    "scf_transaction_property_new() failed: %s",
43671590c90Snw 			    scf_strerror(scf_error()));
4378edda628Sbaban 			goto destruction;
4388edda628Sbaban 		}
4398edda628Sbaban 
4408edda628Sbaban 		if (scf_value_set_astring(value, val) == -1) {
4418edda628Sbaban 			idmapdlog(LOG_ERR,
44271590c90Snw 			    "scf_value_set_astring() failed: %s",
44371590c90Snw 			    scf_strerror(scf_error()));
4448edda628Sbaban 			goto destruction;
4458edda628Sbaban 		}
4468edda628Sbaban 
4478edda628Sbaban 		if (scf_entry_add_value(ent, value) == -1) {
4488edda628Sbaban 			idmapdlog(LOG_ERR,
44971590c90Snw 			    "scf_entry_add_value() failed: %s",
45071590c90Snw 			    scf_strerror(scf_error()));
4518edda628Sbaban 			goto destruction;
4528edda628Sbaban 		}
4538edda628Sbaban 
454e3c2d6aaSnw 		if ((ret = scf_transaction_commit(tx)) == 1)
455e3c2d6aaSnw 			break;
456e3c2d6aaSnw 
457e3c2d6aaSnw 		if (ret == 0 && i < MAX_TRIES - 1) {
4588edda628Sbaban 			/*
4598edda628Sbaban 			 * Property group set in scf_transaction_start()
4608edda628Sbaban 			 * is not the most recent. Update pg, reset tx and
4618edda628Sbaban 			 * retry tx.
4628edda628Sbaban 			 */
4638edda628Sbaban 			idmapdlog(LOG_WARNING,
46471590c90Snw 			    "scf_transaction_commit(%s) failed - Retry: %s",
46571590c90Snw 			    name, scf_strerror(scf_error()));
466c8e26105Sjp 			if (scf_pg_update(handles->config_pg) == -1) {
4678edda628Sbaban 				idmapdlog(LOG_ERR,
46871590c90Snw 				    "scf_pg_update() failed: %s",
46971590c90Snw 				    scf_strerror(scf_error()));
4708edda628Sbaban 				goto destruction;
4718edda628Sbaban 			}
4728edda628Sbaban 			scf_transaction_reset(tx);
4738edda628Sbaban 		}
4748edda628Sbaban 	}
4758edda628Sbaban 
476e3c2d6aaSnw 
477e3c2d6aaSnw 	if (ret == 1)
478e3c2d6aaSnw 		rc = 0;
479e3c2d6aaSnw 	else if (ret != -2)
4808edda628Sbaban 		idmapdlog(LOG_ERR,
48171590c90Snw 		    "scf_transaction_commit(%s) failed: %s",
48271590c90Snw 		    name, scf_strerror(scf_error()));
4838edda628Sbaban 
4848edda628Sbaban destruction:
4858edda628Sbaban 	scf_value_destroy(value);
4868edda628Sbaban 	scf_entry_destroy(ent);
4878edda628Sbaban 	scf_transaction_destroy(tx);
4888edda628Sbaban 	scf_property_destroy(scf_prop);
4898edda628Sbaban 	return (rc);
4908edda628Sbaban }
4918edda628Sbaban 
492c8e26105Sjp static int
493c8e26105Sjp update_value(char **value, char **new, char *name)
494c8e26105Sjp {
495c8e26105Sjp 	if (*new == NULL)
496349d5d8fSnw 		return (0);
497c8e26105Sjp 
498c8e26105Sjp 	if (*value != NULL && strcmp(*new, *value) == 0) {
499c8e26105Sjp 		free(*new);
500c8e26105Sjp 		*new = NULL;
501349d5d8fSnw 		return (0);
502c8e26105Sjp 	}
503c8e26105Sjp 
50471590c90Snw 	idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
505c8e26105Sjp 	if (*value != NULL)
506c8e26105Sjp 		free(*value);
507c8e26105Sjp 	*value = *new;
508c8e26105Sjp 	*new = NULL;
509349d5d8fSnw 	return (1);
510c8e26105Sjp }
511c8e26105Sjp 
512c8e26105Sjp static int
513*479ac375Sdm update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new, char *name)
514c8e26105Sjp {
515c8e26105Sjp 	int i;
516c8e26105Sjp 
5170dcc7149Snw 	if (*value == *new)
5180dcc7149Snw 		/* Nothing to do */
519349d5d8fSnw 		return (0);
520c8e26105Sjp 
5210dcc7149Snw 	if (*value != NULL && *new != NULL &&
5220dcc7149Snw 	    ad_disc_compare_ds(*value, *new) == 0) {
523c8e26105Sjp 		free(*new);
524c8e26105Sjp 		*new = NULL;
525349d5d8fSnw 		return (0);
526c8e26105Sjp 	}
527c8e26105Sjp 
528c8e26105Sjp 	if (*value)
529c8e26105Sjp 		free(*value);
530c8e26105Sjp 
531c8e26105Sjp 	*value = *new;
532c8e26105Sjp 	*new = NULL;
5330dcc7149Snw 
5340dcc7149Snw 	if (*value == NULL) {
5350dcc7149Snw 		/* We're unsetting this DS property */
53671590c90Snw 		idmapdlog(LOG_INFO, "change %s=<none>", name);
537349d5d8fSnw 		return (1);
5380dcc7149Snw 	}
5390dcc7149Snw 
5400dcc7149Snw 	/* List all the new DSs */
5410dcc7149Snw 	for (i = 0; (*value)[i].host[0] != '\0'; i++)
54271590c90Snw 		idmapdlog(LOG_INFO, "change %s=%s port=%d", name,
5430dcc7149Snw 		    (*value)[i].host, (*value)[i].port);
544349d5d8fSnw 	return (1);
545c8e26105Sjp }
546c8e26105Sjp 
547c8e26105Sjp 
5480dcc7149Snw #define	MAX_CHECK_TIME		(20 * 60)
549c8e26105Sjp 
550c8e26105Sjp /*
5510dcc7149Snw  * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
5520dcc7149Snw  * interfaces.
553c8e26105Sjp  *
5540dcc7149Snw  * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
555c8e26105Sjp  */
556c8e26105Sjp static
557c8e26105Sjp int
5580dcc7149Snw pfroute_event_is_interesting(int rt_sock)
559c8e26105Sjp {
5600dcc7149Snw 	int nbytes;
5610dcc7149Snw 	int64_t msg[2048 / 8];
5620dcc7149Snw 	struct rt_msghdr *rtm;
5630dcc7149Snw 	int is_interesting = FALSE;
564c8e26105Sjp 
5650dcc7149Snw 	for (;;) {
5660dcc7149Snw 		if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
5670dcc7149Snw 			break;
5680dcc7149Snw 		rtm = (struct rt_msghdr *)msg;
5690dcc7149Snw 		if (rtm->rtm_version != RTM_VERSION)
5700dcc7149Snw 			continue;
5710dcc7149Snw 		if (nbytes < rtm->rtm_msglen)
5720dcc7149Snw 			continue;
5730dcc7149Snw 		switch (rtm->rtm_type) {
5740dcc7149Snw 		case RTM_NEWADDR:
5750dcc7149Snw 		case RTM_DELADDR:
5760dcc7149Snw 		case RTM_IFINFO:
5770dcc7149Snw 			is_interesting = TRUE;
5780dcc7149Snw 			break;
5790dcc7149Snw 		default:
5800dcc7149Snw 			break;
5810dcc7149Snw 		}
582c8e26105Sjp 	}
5830dcc7149Snw 	return (is_interesting);
5840dcc7149Snw }
5850dcc7149Snw 
5860dcc7149Snw /*
5870dcc7149Snw  * Returns 1 if SIGHUP has been received (see hup_handler() elsewhere) or if an
5880dcc7149Snw  * interface address was added or removed; otherwise it returns 0.
5890dcc7149Snw  *
5900dcc7149Snw  * Note that port_get() does not update its timeout argument when EINTR, unlike
5910dcc7149Snw  * nanosleep().  We probably don't care very much here, but if we did care then
5920dcc7149Snw  * we could always use a timer event and associate it with the same event port,
5930dcc7149Snw  * then we could get accurate waiting regardless of EINTRs.
5940dcc7149Snw  */
5950dcc7149Snw static
5960dcc7149Snw int
597349d5d8fSnw wait_for_event(int poke_is_interesting, struct timespec *timeoutp)
5980dcc7149Snw {
5990dcc7149Snw 	port_event_t pe;
600c8e26105Sjp 
601c8e26105Sjp retry:
6020dcc7149Snw 	memset(&pe, 0, sizeof (pe));
603349d5d8fSnw 	if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
604c8e26105Sjp 		switch (errno) {
605c8e26105Sjp 		case EINTR:
6060dcc7149Snw 			goto retry;
607c8e26105Sjp 		case ETIME:
608c8e26105Sjp 			/* Timeout */
6090dcc7149Snw 			return (FALSE);
610c8e26105Sjp 		default:
6110dcc7149Snw 			/* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
6120dcc7149Snw 			idmapdlog(LOG_ERR, "Event port failed: %s",
6130dcc7149Snw 			    strerror(errno));
6140dcc7149Snw 			exit(1);
6150dcc7149Snw 			/* NOTREACHED */
616c8e26105Sjp 			break;
617c8e26105Sjp 		}
618c8e26105Sjp 	}
619c8e26105Sjp 
6200dcc7149Snw 	if (pe.portev_source == PORT_SOURCE_USER &&
6210dcc7149Snw 	    pe.portev_events == POKE_AUTO_DISCOVERY)
6220dcc7149Snw 		return (poke_is_interesting ? TRUE : FALSE);
6230dcc7149Snw 
6240dcc7149Snw 	if (pe.portev_source == PORT_SOURCE_FD && pe.portev_object == rt_sock) {
6250dcc7149Snw 		/* PF_ROUTE socket read event, re-associate fd, handle event */
6260dcc7149Snw 		if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock,
6270dcc7149Snw 		    POLLIN, NULL) != 0) {
6280dcc7149Snw 			idmapdlog(LOG_ERR, "Failed to re-associate the "
6290dcc7149Snw 			    "routing socket with the event port: %s",
6300dcc7149Snw 			    strerror(errno));
6310dcc7149Snw 			exit(1);
6320dcc7149Snw 		}
6330dcc7149Snw 		/*
6340dcc7149Snw 		 * The network configuration may still be in flux.  No matter,
6350dcc7149Snw 		 * the resolver will re-transmit and timout if need be.
6360dcc7149Snw 		 */
6370dcc7149Snw 		return (pfroute_event_is_interesting(rt_sock));
6380dcc7149Snw 	}
639c8e26105Sjp 
6400dcc7149Snw 	if (pe.portev_source == PORT_SOURCE_USER &&
6410dcc7149Snw 	    pe.portev_events == RECONFIGURE) {
642e3c2d6aaSnw 		int rc;
643e3c2d6aaSnw 
644e3c2d6aaSnw 		/*
645e3c2d6aaSnw 		 * Blow away the ccache, we might have re-joined the
646e3c2d6aaSnw 		 * domain or joined a new one
647e3c2d6aaSnw 		 */
648e3c2d6aaSnw 		(void) unlink(IDMAP_CACHEDIR "/ccache");
649e3c2d6aaSnw 		/* HUP is the refresh method, so re-read SMF config */
65071590c90Snw 		(void) idmapdlog(LOG_INFO, "SMF refresh");
651349d5d8fSnw 		rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER|CFG_LOG);
652349d5d8fSnw 		if (rc < -1) {
653349d5d8fSnw 			(void) idmapdlog(LOG_ERR, "Fatal errors while reading "
654349d5d8fSnw 			    "SMF properties");
655349d5d8fSnw 			exit(1);
656349d5d8fSnw 		} else if (rc == -1) {
657349d5d8fSnw 			(void) idmapdlog(LOG_WARNING, "Various errors "
658349d5d8fSnw 			    "re-loading configuration may cause AD lookups "
659349d5d8fSnw 			    "to fail");
660349d5d8fSnw 		}
661349d5d8fSnw 		return (FALSE);
662c8e26105Sjp 	}
663c8e26105Sjp 
6640dcc7149Snw 	return (FALSE);
665c8e26105Sjp }
666c8e26105Sjp 
667c8e26105Sjp void *
668c8e26105Sjp idmap_cfg_update_thread(void *arg)
669c8e26105Sjp {
670c8e26105Sjp 
6710dcc7149Snw 	int			ttl, changed, poke_is_interesting;
672c8e26105Sjp 	idmap_cfg_handles_t	*handles = &_idmapdstate.cfg->handles;
673c8e26105Sjp 	ad_disc_t		ad_ctx = handles->ad_ctx;
674349d5d8fSnw 	struct timespec		timeout, *timeoutp;
675c8e26105Sjp 
6760dcc7149Snw 	poke_is_interesting = 1;
6770dcc7149Snw 	for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) {
678349d5d8fSnw 		/*
679349d5d8fSnw 		 * If ttl < 0 then we can wait for an event without timing out.
680349d5d8fSnw 		 * If idmapd needs to notice that the system has been joined to
681349d5d8fSnw 		 * a Windows domain then idmapd needs to be refreshed.
682349d5d8fSnw 		 */
683349d5d8fSnw 		timeoutp = (ttl < 0) ? NULL : &timeout;
684349d5d8fSnw 		if (ttl > MAX_CHECK_TIME)
685c8e26105Sjp 			ttl = MAX_CHECK_TIME;
6860dcc7149Snw 		timeout.tv_sec = ttl;
6870dcc7149Snw 		timeout.tv_nsec = 0;
688349d5d8fSnw 		changed = wait_for_event(poke_is_interesting, timeoutp);
6890dcc7149Snw 
6900dcc7149Snw 		/*
6910dcc7149Snw 		 * If there are no interesting events, and this is not the first
6920dcc7149Snw 		 * time through the loop, and we haven't waited the most that
6930dcc7149Snw 		 * we're willing to wait, so do nothing but wait some more.
6940dcc7149Snw 		 */
6950dcc7149Snw 		if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME)
6960dcc7149Snw 			continue;
6970dcc7149Snw 
6980dcc7149Snw 		(void) ad_disc_SubnetChanged(ad_ctx);
699c8e26105Sjp 
700349d5d8fSnw 		if (idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER) < -1) {
701349d5d8fSnw 			(void) idmapdlog(LOG_ERR, "Fatal errors while reading "
702349d5d8fSnw 			    "SMF properties");
703349d5d8fSnw 			exit(1);
704349d5d8fSnw 		}
705c8e26105Sjp 
706349d5d8fSnw 		if (_idmapdstate.cfg->pgcfg.global_catalog == NULL ||
707349d5d8fSnw 		    _idmapdstate.cfg->pgcfg.global_catalog[0].host[0] == '\0')
7080dcc7149Snw 			poke_is_interesting = 1;
709349d5d8fSnw 		else
7100dcc7149Snw 			poke_is_interesting = 0;
711c8e26105Sjp 	}
712c8e26105Sjp 	/*NOTREACHED*/
713c8e26105Sjp 	return (NULL);
714c8e26105Sjp }
715c8e26105Sjp 
716c8e26105Sjp int
7170dcc7149Snw idmap_cfg_start_updates(void)
718c8e26105Sjp {
7190dcc7149Snw 	if ((idmapd_ev_port = port_create()) < 0) {
72071590c90Snw 		idmapdlog(LOG_ERR, "Failed to create event port: %s",
72171590c90Snw 		    strerror(errno));
722c8e26105Sjp 		return (-1);
7230dcc7149Snw 	}
7240dcc7149Snw 
7250dcc7149Snw 	if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
72671590c90Snw 		idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
72771590c90Snw 		    strerror(errno));
7280dcc7149Snw 		(void) close(idmapd_ev_port);
7290dcc7149Snw 		return (-1);
7300dcc7149Snw 	}
7310dcc7149Snw 
7320dcc7149Snw 	if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
73371590c90Snw 		idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
73471590c90Snw 		    strerror(errno));
7350dcc7149Snw 		(void) close(rt_sock);
7360dcc7149Snw 		(void) close(idmapd_ev_port);
7370dcc7149Snw 		return (-1);
7380dcc7149Snw 	}
7390dcc7149Snw 
7400dcc7149Snw 	if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
7410dcc7149Snw 	    rt_sock, POLLIN, NULL) != 0) {
74271590c90Snw 		idmapdlog(LOG_ERR, "Failed to associate the routing "
74371590c90Snw 		    "socket with the event port: %s", strerror(errno));
7440dcc7149Snw 		(void) close(rt_sock);
7450dcc7149Snw 		(void) close(idmapd_ev_port);
7460dcc7149Snw 		return (-1);
7470dcc7149Snw 	}
7480dcc7149Snw 
7490dcc7149Snw 	if ((errno = pthread_create(&update_thread_handle, NULL,
7500dcc7149Snw 	    idmap_cfg_update_thread, NULL)) != 0) {
75171590c90Snw 		idmapdlog(LOG_ERR, "Failed to start update thread: %s",
75271590c90Snw 		    strerror(errno));
7530dcc7149Snw 		(void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
7540dcc7149Snw 		(void) close(rt_sock);
7550dcc7149Snw 		(void) close(idmapd_ev_port);
7560dcc7149Snw 		return (-1);
7570dcc7149Snw 	}
7580dcc7149Snw 
7590dcc7149Snw 	return (0);
760c8e26105Sjp }
761c8e26105Sjp 
762*479ac375Sdm /*
763*479ac375Sdm  * Reject attribute names with invalid characters.
764*479ac375Sdm  */
765*479ac375Sdm static
766*479ac375Sdm int
767*479ac375Sdm valid_ldap_attr(const char *attr) {
768*479ac375Sdm 	for (; *attr; attr++) {
769*479ac375Sdm 		if (!isalnum(*attr) && *attr != '-' &&
770*479ac375Sdm 		    *attr != '_' && *attr != '.' && *attr != ';')
771*479ac375Sdm 			return (0);
772*479ac375Sdm 	}
773*479ac375Sdm 	return (1);
774*479ac375Sdm }
775*479ac375Sdm 
776349d5d8fSnw /*
777349d5d8fSnw  * This is the half of idmap_cfg_load() that loads property values from
778349d5d8fSnw  * SMF (using the config/ property group of the idmap FMRI).
779349d5d8fSnw  *
780349d5d8fSnw  * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
781*479ac375Sdm  *               -3 -> hard smf config failures
782349d5d8fSnw  * reading from SMF.
783349d5d8fSnw  */
784349d5d8fSnw static
785c5c4113dSnw int
786349d5d8fSnw idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
787349d5d8fSnw 	int *errors)
788c5c4113dSnw {
789e3c2d6aaSnw 	int rc;
790e8c27ec8Sbaban 	uint8_t bool_val;
791c8e26105Sjp 	char *str = NULL;
79271590c90Snw 	bool_t new_debug_mode;
793c8e26105Sjp 
794c8e26105Sjp 	if (scf_pg_update(handles->config_pg) < 0) {
79571590c90Snw 		idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
79671590c90Snw 		    scf_strerror(scf_error()));
797349d5d8fSnw 		return (-2);
798c5c4113dSnw 	}
799c5c4113dSnw 
800c8e26105Sjp 	if (scf_pg_update(handles->general_pg) < 0) {
80171590c90Snw 		idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
80271590c90Snw 		    scf_strerror(scf_error()));
803349d5d8fSnw 		return (-2);
804c5c4113dSnw 	}
805c5c4113dSnw 
806*479ac375Sdm 
807*479ac375Sdm 	rc = prop_exists(handles, "debug", &new_debug_mode);
808*479ac375Sdm 	if (rc != 0)
809*479ac375Sdm 		errors++;
810*479ac375Sdm 
81171590c90Snw 	if (_idmapdstate.debug_mode != new_debug_mode) {
81271590c90Snw 		if (_idmapdstate.debug_mode == FALSE) {
81371590c90Snw 			_idmapdstate.debug_mode = new_debug_mode;
81471590c90Snw 			idmapdlog(LOG_DEBUG, "debug mode enabled");
81571590c90Snw 		} else {
81671590c90Snw 			idmapdlog(LOG_DEBUG, "debug mode disabled");
81771590c90Snw 			_idmapdstate.debug_mode = new_debug_mode;
81871590c90Snw 		}
81971590c90Snw 	}
82071590c90Snw 
821c8e26105Sjp 	rc = get_val_int(handles, "list_size_limit",
822c8e26105Sjp 	    &pgcfg->list_size_limit, SCF_TYPE_COUNT);
823c8e26105Sjp 	if (rc != 0) {
824e3c2d6aaSnw 		pgcfg->list_size_limit = 0;
825e3c2d6aaSnw 		errors++;
826c8e26105Sjp 	}
827c5c4113dSnw 
828c8e26105Sjp 	rc = get_val_astring(handles, "domain_name",
829c8e26105Sjp 	    &pgcfg->domain_name);
830e3c2d6aaSnw 	if (rc != 0)
831e3c2d6aaSnw 		errors++;
832e3c2d6aaSnw 	else
833349d5d8fSnw 		(void) ad_disc_set_DomainName(handles->ad_ctx,
834349d5d8fSnw 		    pgcfg->domain_name);
835c8e26105Sjp 
836c8e26105Sjp 	rc = get_val_astring(handles, "default_domain",
837c8e26105Sjp 	    &pgcfg->default_domain);
838c8e26105Sjp 	if (rc != 0) {
839e3c2d6aaSnw 		/*
840e3c2d6aaSnw 		 * SCF failures fetching config/default_domain we treat
841e3c2d6aaSnw 		 * as fatal as they may leave ID mapping rules that
842e3c2d6aaSnw 		 * match unqualified winnames flapping in the wind.
843e3c2d6aaSnw 		 */
844349d5d8fSnw 		return (-2);
845c8e26105Sjp 	}
846c8e26105Sjp 
847c8e26105Sjp 	rc = get_val_astring(handles, "mapping_domain", &str);
848e3c2d6aaSnw 	if (rc != 0)
849e3c2d6aaSnw 		errors++;
850c5c4113dSnw 
851c5c4113dSnw 	/*
852c8e26105Sjp 	 * We treat default_domain as having been specified in SMF IFF
853c8e26105Sjp 	 * either (the config/default_domain property was set) or (the
854c8e26105Sjp 	 * old, obsolete, never documented config/mapping_domain
855c8e26105Sjp 	 * property was set and the new config/domain_name property was
856c8e26105Sjp 	 * not set).
857c5c4113dSnw 	 */
858c8e26105Sjp 	pgcfg->dflt_dom_set_in_smf = TRUE;
859c8e26105Sjp 	if (pgcfg->default_domain == NULL) {
860c8e26105Sjp 
861c8e26105Sjp 		pgcfg->dflt_dom_set_in_smf = FALSE;
862c8e26105Sjp 
863c8e26105Sjp 		if (pgcfg->domain_name != NULL) {
864c8e26105Sjp 			pgcfg->default_domain = strdup(pgcfg->domain_name);
865c8e26105Sjp 			if (str != NULL) {
866c8e26105Sjp 				idmapdlog(LOG_WARNING,
86771590c90Snw 				    "Ignoring obsolete, undocumented "
86871590c90Snw 				    "config/mapping_domain property");
869c8e26105Sjp 			}
870c8e26105Sjp 		} else if (str != NULL) {
871c8e26105Sjp 			pgcfg->default_domain = strdup(str);
872c8e26105Sjp 			pgcfg->dflt_dom_set_in_smf = TRUE;
873c8e26105Sjp 			idmapdlog(LOG_WARNING,
87471590c90Snw 			    "The config/mapping_domain property is "
875c8e26105Sjp 			    "obsolete; support for it will be removed, "
87671590c90Snw 			    "please use config/default_domain instead");
877c5c4113dSnw 		}
878c5c4113dSnw 	}
879c5c4113dSnw 
880c8e26105Sjp 	if (str != NULL)
881c8e26105Sjp 		free(str);
882c8e26105Sjp 
883c8e26105Sjp 	rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
884e3c2d6aaSnw 	if (rc != 0)
885e3c2d6aaSnw 		errors++;
886c8e26105Sjp 	if (pgcfg->machine_sid == NULL) {
8878edda628Sbaban 		/* If machine_sid not configured, generate one */
888349d5d8fSnw 		if (generate_machine_sid(&pgcfg->machine_sid) < 0)
889349d5d8fSnw 			return (-2);
890c8e26105Sjp 		rc = set_val_astring(handles, "machine_sid",
891c8e26105Sjp 		    pgcfg->machine_sid);
892e3c2d6aaSnw 		if (rc != 0)
893e3c2d6aaSnw 			errors++;
8948edda628Sbaban 	}
895c5c4113dSnw 
896c8e26105Sjp 	str = NULL;
897c8e26105Sjp 	rc = get_val_ds(handles, "domain_controller", 389,
898c8e26105Sjp 	    &pgcfg->domain_controller);
899e3c2d6aaSnw 	if (rc != 0)
900e3c2d6aaSnw 		errors++;
901e3c2d6aaSnw 	else
902349d5d8fSnw 		(void) ad_disc_set_DomainController(handles->ad_ctx,
903e3c2d6aaSnw 		    pgcfg->domain_controller);
904c5c4113dSnw 
905c8e26105Sjp 	rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
906e3c2d6aaSnw 	if (rc != 0)
907e3c2d6aaSnw 		errors++;
908e3c2d6aaSnw 	else
909349d5d8fSnw 		(void) ad_disc_set_ForestName(handles->ad_ctx,
910349d5d8fSnw 		    pgcfg->forest_name);
911c8e26105Sjp 
912c8e26105Sjp 	rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
913e3c2d6aaSnw 	if (rc != 0)
914e3c2d6aaSnw 		errors++;
915e3c2d6aaSnw 	else
916349d5d8fSnw 		(void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
917c8e26105Sjp 
918c8e26105Sjp 	str = NULL;
919c8e26105Sjp 	rc = get_val_ds(handles, "global_catalog", 3268,
920c8e26105Sjp 	    &pgcfg->global_catalog);
921e3c2d6aaSnw 	if (rc != 0)
922e3c2d6aaSnw 		errors++;
923e3c2d6aaSnw 	else
924349d5d8fSnw 		(void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
925349d5d8fSnw 		    pgcfg->global_catalog);
926c8e26105Sjp 
927e8c27ec8Sbaban 	/*
928e8c27ec8Sbaban 	 * Read directory-based name mappings related SMF properties
929e8c27ec8Sbaban 	 */
930e8c27ec8Sbaban 	bool_val = 0;
931e8c27ec8Sbaban 	rc = get_val_int(handles, "ds_name_mapping_enabled",
932e8c27ec8Sbaban 	    &bool_val, SCF_TYPE_BOOLEAN);
933349d5d8fSnw 	if (rc != 0)
934349d5d8fSnw 		return (-2);
935e8c27ec8Sbaban 
936349d5d8fSnw 	if (!bool_val)
937349d5d8fSnw 		return (rc);
938e8c27ec8Sbaban 
939349d5d8fSnw 	pgcfg->ds_name_mapping_enabled = TRUE;
940349d5d8fSnw 	rc = get_val_astring(handles, "ad_unixuser_attr",
941349d5d8fSnw 	    &pgcfg->ad_unixuser_attr);
942349d5d8fSnw 	if (rc != 0)
943349d5d8fSnw 		return (-2);
944*479ac375Sdm 	if (pgcfg->ad_unixuser_attr != NULL &&
945*479ac375Sdm 	    !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
946*479ac375Sdm 		idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
947*479ac375Sdm 		    "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
948*479ac375Sdm 		return (-3);
949*479ac375Sdm 	}
950e8c27ec8Sbaban 
951349d5d8fSnw 	rc = get_val_astring(handles, "ad_unixgroup_attr",
952349d5d8fSnw 	    &pgcfg->ad_unixgroup_attr);
953349d5d8fSnw 	if (rc != 0)
954349d5d8fSnw 		return (-2);
955*479ac375Sdm 	if (pgcfg->ad_unixgroup_attr != NULL &&
956*479ac375Sdm 	    !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
957*479ac375Sdm 		idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
958*479ac375Sdm 		    "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
959*479ac375Sdm 		return (-3);
960*479ac375Sdm 	}
961e8c27ec8Sbaban 
962349d5d8fSnw 	rc = get_val_astring(handles, "nldap_winname_attr",
963349d5d8fSnw 	    &pgcfg->nldap_winname_attr);
964349d5d8fSnw 	if (rc != 0)
965349d5d8fSnw 		return (-2);
966*479ac375Sdm 	if (pgcfg->nldap_winname_attr != NULL &&
967*479ac375Sdm 	    !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
968*479ac375Sdm 		idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
969*479ac375Sdm 		    "valid LDAP attribute name", pgcfg->nldap_winname_attr);
970349d5d8fSnw 		return (-3);
971e8c27ec8Sbaban 	}
972349d5d8fSnw 	if (pgcfg->ad_unixuser_attr == NULL &&
973*479ac375Sdm 	    pgcfg->ad_unixgroup_attr == NULL &&
974*479ac375Sdm 	    pgcfg->nldap_winname_attr == NULL) {
975349d5d8fSnw 		idmapdlog(LOG_ERR,
976349d5d8fSnw 		    "If config/ds_name_mapping_enabled property is set to "
977349d5d8fSnw 		    "true then atleast one of the following name mapping "
978349d5d8fSnw 		    "attributes must be specified. (config/ad_unixuser_attr OR "
979*479ac375Sdm 		    "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
980349d5d8fSnw 		return (-3);
981349d5d8fSnw 	}
982c8e26105Sjp 
983349d5d8fSnw 	return (rc);
984e3c2d6aaSnw 
985349d5d8fSnw }
986349d5d8fSnw 
987349d5d8fSnw /*
988349d5d8fSnw  * This is the half of idmap_cfg_load() that auto-discovers values of
989349d5d8fSnw  * discoverable properties that weren't already set via SMF properties.
990349d5d8fSnw  *
991349d5d8fSnw  * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
992349d5d8fSnw  * needs to be careful not to overwrite any properties set in SMF.
993349d5d8fSnw  */
994349d5d8fSnw static
995349d5d8fSnw void
996349d5d8fSnw idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
997349d5d8fSnw {
998349d5d8fSnw 	ad_disc_t ad_ctx = handles->ad_ctx;
999349d5d8fSnw 
1000349d5d8fSnw 	ad_disc_refresh(ad_ctx);
1001349d5d8fSnw 
1002349d5d8fSnw 	if (pgcfg->default_domain == NULL)
1003c8e26105Sjp 		pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx);
1004c8e26105Sjp 
1005349d5d8fSnw 	if (pgcfg->domain_name == NULL)
1006c8e26105Sjp 		pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx);
1007c8e26105Sjp 
1008349d5d8fSnw 	if (pgcfg->domain_controller == NULL)
1009c8e26105Sjp 		pgcfg->domain_controller =
1010c8e26105Sjp 		    ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE);
1011c8e26105Sjp 
1012349d5d8fSnw 	if (pgcfg->forest_name == NULL)
1013c8e26105Sjp 		pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx);
1014c8e26105Sjp 
1015349d5d8fSnw 	if (pgcfg->site_name == NULL)
1016c8e26105Sjp 		pgcfg->site_name = ad_disc_get_SiteName(ad_ctx);
1017c8e26105Sjp 
1018349d5d8fSnw 	if (pgcfg->global_catalog == NULL)
1019c8e26105Sjp 		pgcfg->global_catalog =
1020c8e26105Sjp 		    ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE);
1021349d5d8fSnw 
1022349d5d8fSnw 	if (pgcfg->domain_name == NULL)
1023349d5d8fSnw 		idmapdlog(LOG_DEBUG, "unable to discover Domain Name");
1024349d5d8fSnw 	if (pgcfg->domain_controller == NULL)
1025349d5d8fSnw 		idmapdlog(LOG_DEBUG, "unable to discover Domain Controller");
1026349d5d8fSnw 	if (pgcfg->forest_name == NULL)
1027349d5d8fSnw 		idmapdlog(LOG_DEBUG, "unable to discover Forest Name");
1028349d5d8fSnw 	if (pgcfg->site_name == NULL)
1029349d5d8fSnw 		idmapdlog(LOG_DEBUG, "unable to discover Site Name");
1030349d5d8fSnw 	if (pgcfg->global_catalog == NULL)
1031349d5d8fSnw 		idmapdlog(LOG_DEBUG, "unable to discover Global Catalog");
1032349d5d8fSnw }
1033349d5d8fSnw 
1034349d5d8fSnw /*
1035349d5d8fSnw  * idmap_cfg_load() is called at startup, and periodically via the
1036349d5d8fSnw  * update thread when the auto-discovery TTLs expire, as well as part of
1037349d5d8fSnw  * the refresh method, to update the current configuration.  It always
1038349d5d8fSnw  * reads from SMF, but you still have to refresh the service after
1039349d5d8fSnw  * changing the config pg in order for the changes to take effect.
1040349d5d8fSnw  *
1041349d5d8fSnw  * There are two flags:
1042349d5d8fSnw  *
1043349d5d8fSnw  *  - CFG_DISCOVER
1044349d5d8fSnw  *  - CFG_LOG
1045349d5d8fSnw  *
1046349d5d8fSnw  * If CFG_DISCOVER is set then idmap_cfg_load() calls
1047349d5d8fSnw  * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
1048349d5d8fSnw  * values that weren't set in SMF.
1049349d5d8fSnw  *
1050349d5d8fSnw  * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE)
1051349d5d8fSnw  * whether the configuration changed.  This should be used only from the
1052349d5d8fSnw  * refresh method.
1053349d5d8fSnw  *
1054349d5d8fSnw  * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1055349d5d8fSnw  * reading from SMF.
1056349d5d8fSnw  */
1057349d5d8fSnw int
1058349d5d8fSnw idmap_cfg_load(idmap_cfg_t *cfg, int flags)
1059349d5d8fSnw {
1060349d5d8fSnw 	int rc = 0;
1061349d5d8fSnw 	int errors = 0;
1062349d5d8fSnw 	int changed = 0;
1063349d5d8fSnw 	idmap_pg_config_t new_pgcfg, *live_pgcfg;
1064349d5d8fSnw 
1065349d5d8fSnw 	live_pgcfg = &cfg->pgcfg;
1066349d5d8fSnw 	(void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
1067349d5d8fSnw 
1068349d5d8fSnw 	pthread_mutex_lock(&cfg->handles.mutex);
1069349d5d8fSnw 
1070349d5d8fSnw 	if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
1071349d5d8fSnw 		goto err;
1072349d5d8fSnw 
1073349d5d8fSnw 	if (flags & CFG_DISCOVER)
1074349d5d8fSnw 		idmap_cfg_discover(&cfg->handles, &new_pgcfg);
1075349d5d8fSnw 
1076349d5d8fSnw 	WRLOCK_CONFIG();
1077349d5d8fSnw 	if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) {
1078349d5d8fSnw 		idmapdlog(LOG_INFO, "change list_size=%d",
1079349d5d8fSnw 		    new_pgcfg.list_size_limit);
1080349d5d8fSnw 		live_pgcfg->list_size_limit = new_pgcfg.list_size_limit;
1081349d5d8fSnw 	}
1082349d5d8fSnw 
1083349d5d8fSnw 	/* Non-discoverable props updated here */
1084349d5d8fSnw 	changed += update_value(&live_pgcfg->machine_sid,
1085349d5d8fSnw 	    &new_pgcfg.machine_sid, "machine_sid");
1086349d5d8fSnw 
1087349d5d8fSnw 	changed += live_pgcfg->ds_name_mapping_enabled !=
1088349d5d8fSnw 	    new_pgcfg.ds_name_mapping_enabled;
1089349d5d8fSnw 	live_pgcfg->ds_name_mapping_enabled =
1090349d5d8fSnw 	    new_pgcfg.ds_name_mapping_enabled;
1091349d5d8fSnw 
1092349d5d8fSnw 	changed += update_value(&live_pgcfg->ad_unixuser_attr,
1093349d5d8fSnw 	    &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
1094349d5d8fSnw 
1095349d5d8fSnw 	changed += update_value(&live_pgcfg->ad_unixgroup_attr,
1096349d5d8fSnw 	    &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
1097349d5d8fSnw 
1098349d5d8fSnw 	changed += update_value(&live_pgcfg->nldap_winname_attr,
1099349d5d8fSnw 	    &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
1100349d5d8fSnw 
1101349d5d8fSnw 	/* Props that can be discovered and set in SMF updated here */
1102349d5d8fSnw 	if (live_pgcfg->dflt_dom_set_in_smf == FALSE)
1103349d5d8fSnw 		changed += update_value(&live_pgcfg->default_domain,
1104349d5d8fSnw 		    &new_pgcfg.default_domain, "default_domain");
1105349d5d8fSnw 
1106349d5d8fSnw 	changed += update_value(&live_pgcfg->domain_name,
1107349d5d8fSnw 	    &new_pgcfg.domain_name, "domain_name");
1108349d5d8fSnw 
1109349d5d8fSnw 	changed += update_dirs(&live_pgcfg->domain_controller,
1110349d5d8fSnw 	    &new_pgcfg.domain_controller, "domain_controller");
1111349d5d8fSnw 
1112349d5d8fSnw 	changed += update_value(&live_pgcfg->forest_name,
1113349d5d8fSnw 	    &new_pgcfg.forest_name, "forest_name");
1114349d5d8fSnw 
1115349d5d8fSnw 	changed += update_value(&live_pgcfg->site_name,
1116349d5d8fSnw 	    &new_pgcfg.site_name, "site_name");
1117349d5d8fSnw 
1118349d5d8fSnw 	if (update_dirs(&live_pgcfg->global_catalog,
1119349d5d8fSnw 	    &new_pgcfg.global_catalog, "global_catalog")) {
1120349d5d8fSnw 		changed++;
1121349d5d8fSnw 		/*
1122349d5d8fSnw 		 * Right now we only update the ad_t used for AD lookups
1123349d5d8fSnw 		 * when the GC list is updated.  When we add mixed
1124349d5d8fSnw 		 * ds-based mapping we'll also need to update the ad_t
1125349d5d8fSnw 		 * used to talk to the domain, not just the one used to
1126349d5d8fSnw 		 * talk to the GC.
1127349d5d8fSnw 		 */
1128349d5d8fSnw 		if (live_pgcfg->global_catalog != NULL &&
1129349d5d8fSnw 		    live_pgcfg->global_catalog[0].host[0] != '\0')
1130349d5d8fSnw 			reload_ad();
1131349d5d8fSnw 	}
1132349d5d8fSnw 
1133349d5d8fSnw 	idmap_cfg_unload(&new_pgcfg);
1134349d5d8fSnw 
1135349d5d8fSnw 	if (flags & CFG_LOG) {
1136349d5d8fSnw 		/*
1137349d5d8fSnw 		 * If the config changes as a result of a refresh of the
1138349d5d8fSnw 		 * service, then logging about it can provide useful
1139349d5d8fSnw 		 * feedback to the sysadmin.
1140349d5d8fSnw 		 */
1141349d5d8fSnw 		idmapdlog(LOG_NOTICE, "Configuration %schanged",
1142349d5d8fSnw 		    changed ? "" : "un");
1143c8e26105Sjp 	}
1144e3c2d6aaSnw 
1145349d5d8fSnw 	UNLOCK_CONFIG();
1146349d5d8fSnw 
1147349d5d8fSnw err:
1148349d5d8fSnw 	pthread_mutex_unlock(&cfg->handles.mutex);
1149c5c4113dSnw 
1150e8c27ec8Sbaban 	if (rc < -1)
1151e3c2d6aaSnw 		return (rc);
1152e3c2d6aaSnw 
1153e3c2d6aaSnw 	return ((errors == 0) ? 0 : -1);
1154c5c4113dSnw }
1155c5c4113dSnw 
1156651c0131Sbaban /*
1157651c0131Sbaban  * Initialize 'cfg'.
1158651c0131Sbaban  */
1159c5c4113dSnw idmap_cfg_t *
11604edd44c5Sjp idmap_cfg_init()
11614edd44c5Sjp {
1162c8e26105Sjp 	idmap_cfg_handles_t *handles;
1163c5c4113dSnw 
1164c5c4113dSnw 	/* First the smf repository handles: */
1165c5c4113dSnw 	idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
1166c5c4113dSnw 	if (!cfg) {
116771590c90Snw 		idmapdlog(LOG_ERR, "Out of memory");
1168c5c4113dSnw 		return (NULL);
1169c5c4113dSnw 	}
1170c8e26105Sjp 	handles = &cfg->handles;
1171c5c4113dSnw 
1172c8e26105Sjp 	(void) pthread_mutex_init(&handles->mutex, NULL);
1173c8e26105Sjp 
1174c8e26105Sjp 	if (!(handles->main = scf_handle_create(SCF_VERSION))) {
117571590c90Snw 		idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
117671590c90Snw 		    scf_strerror(scf_error()));
1177c5c4113dSnw 		goto error;
1178c5c4113dSnw 	}
1179c5c4113dSnw 
1180c8e26105Sjp 	if (scf_handle_bind(handles->main) < 0) {
118171590c90Snw 		idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
118271590c90Snw 		    scf_strerror(scf_error()));
1183c5c4113dSnw 		goto error;
1184c5c4113dSnw 	}
1185c5c4113dSnw 
1186c8e26105Sjp 	if (!(handles->service = scf_service_create(handles->main)) ||
1187c8e26105Sjp 	    !(handles->instance = scf_instance_create(handles->main)) ||
1188c8e26105Sjp 	    !(handles->config_pg = scf_pg_create(handles->main)) ||
1189c8e26105Sjp 	    !(handles->general_pg = scf_pg_create(handles->main))) {
119071590c90Snw 		idmapdlog(LOG_ERR, "scf handle creation failed: %s",
119171590c90Snw 		    scf_strerror(scf_error()));
1192c5c4113dSnw 		goto error;
1193c5c4113dSnw 	}
1194c5c4113dSnw 
1195c8e26105Sjp 	if (scf_handle_decode_fmri(handles->main,
11964edd44c5Sjp 	    FMRI_BASE "/:properties/" CONFIG_PG,
11974edd44c5Sjp 	    NULL,				/* scope */
11984edd44c5Sjp 	    handles->service,		/* service */
11994edd44c5Sjp 	    handles->instance,		/* instance */
12004edd44c5Sjp 	    handles->config_pg,		/* pg */
12014edd44c5Sjp 	    NULL,				/* prop */
12024edd44c5Sjp 	    SCF_DECODE_FMRI_EXACT) < 0) {
120371590c90Snw 		idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
120471590c90Snw 		    scf_strerror(scf_error()));
1205c5c4113dSnw 		goto error;
1206c5c4113dSnw 	}
1207c5c4113dSnw 
1208c8e26105Sjp 	if (scf_service_get_pg(handles->service,
12094edd44c5Sjp 	    GENERAL_PG, handles->general_pg) < 0) {
121071590c90Snw 		idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s",
121171590c90Snw 		    scf_strerror(scf_error()));
1212c5c4113dSnw 		goto error;
1213c5c4113dSnw 	}
1214c5c4113dSnw 
1215c8e26105Sjp 	/* Initialize AD Auto Discovery context */
1216c8e26105Sjp 	handles->ad_ctx = ad_disc_init();
1217c8e26105Sjp 	if (handles->ad_ctx == NULL)
1218c8e26105Sjp 		goto error;
1219c8e26105Sjp 
1220c5c4113dSnw 	return (cfg);
1221c5c4113dSnw 
1222c5c4113dSnw error:
1223c5c4113dSnw 	(void) idmap_cfg_fini(cfg);
1224c5c4113dSnw 	return (NULL);
1225c5c4113dSnw }
1226c5c4113dSnw 
1227c8e26105Sjp void
12284edd44c5Sjp idmap_cfg_unload(idmap_pg_config_t *pgcfg)
12294edd44c5Sjp {
1230c8e26105Sjp 
1231c8e26105Sjp 	if (pgcfg->default_domain) {
1232c8e26105Sjp 		free(pgcfg->default_domain);
1233c8e26105Sjp 		pgcfg->default_domain = NULL;
1234c8e26105Sjp 	}
1235c8e26105Sjp 	if (pgcfg->domain_name) {
1236c8e26105Sjp 		free(pgcfg->domain_name);
1237c8e26105Sjp 		pgcfg->domain_name = NULL;
1238c8e26105Sjp 	}
1239c8e26105Sjp 	if (pgcfg->machine_sid) {
1240c8e26105Sjp 		free(pgcfg->machine_sid);
1241c8e26105Sjp 		pgcfg->machine_sid = NULL;
1242c8e26105Sjp 	}
1243c8e26105Sjp 	if (pgcfg->domain_controller) {
1244c5c4113dSnw 		free(pgcfg->domain_controller);
1245c8e26105Sjp 		pgcfg->domain_controller = NULL;
1246c8e26105Sjp 	}
1247c8e26105Sjp 	if (pgcfg->forest_name) {
1248c8e26105Sjp 		free(pgcfg->forest_name);
1249c8e26105Sjp 		pgcfg->forest_name = NULL;
1250c8e26105Sjp 	}
1251c8e26105Sjp 	if (pgcfg->site_name) {
1252c8e26105Sjp 		free(pgcfg->site_name);
1253c8e26105Sjp 		pgcfg->site_name = NULL;
1254c8e26105Sjp 	}
1255c8e26105Sjp 	if (pgcfg->global_catalog) {
1256c8e26105Sjp 		free(pgcfg->global_catalog);
1257c8e26105Sjp 		pgcfg->global_catalog = NULL;
1258c8e26105Sjp 	}
1259e8c27ec8Sbaban 	if (pgcfg->ad_unixuser_attr) {
1260e8c27ec8Sbaban 		free(pgcfg->ad_unixuser_attr);
1261e8c27ec8Sbaban 		pgcfg->ad_unixuser_attr = NULL;
1262e8c27ec8Sbaban 	}
1263e8c27ec8Sbaban 	if (pgcfg->ad_unixgroup_attr) {
1264e8c27ec8Sbaban 		free(pgcfg->ad_unixgroup_attr);
1265e8c27ec8Sbaban 		pgcfg->ad_unixgroup_attr = NULL;
1266e8c27ec8Sbaban 	}
1267e8c27ec8Sbaban 	if (pgcfg->nldap_winname_attr) {
1268e8c27ec8Sbaban 		free(pgcfg->nldap_winname_attr);
1269e8c27ec8Sbaban 		pgcfg->nldap_winname_attr = NULL;
1270e8c27ec8Sbaban 	}
1271c5c4113dSnw }
1272c5c4113dSnw 
1273c5c4113dSnw int
1274c5c4113dSnw idmap_cfg_fini(idmap_cfg_t *cfg)
1275c5c4113dSnw {
1276c8e26105Sjp 	idmap_cfg_handles_t *handles = &cfg->handles;
1277c8e26105Sjp 	idmap_cfg_unload(&cfg->pgcfg);
1278c8e26105Sjp 
1279c8e26105Sjp 	(void) pthread_mutex_destroy(&handles->mutex);
1280c8e26105Sjp 	scf_pg_destroy(handles->config_pg);
1281c8e26105Sjp 	scf_pg_destroy(handles->general_pg);
1282c8e26105Sjp 	scf_instance_destroy(handles->instance);
1283c8e26105Sjp 	scf_service_destroy(handles->service);
1284c8e26105Sjp 	scf_handle_destroy(handles->main);
1285e8c27ec8Sbaban 	if (handles->ad_ctx != NULL)
1286e8c27ec8Sbaban 		ad_disc_fini(handles->ad_ctx);
1287c5c4113dSnw 	free(cfg);
1288c5c4113dSnw 
1289c5c4113dSnw 	return (0);
1290c5c4113dSnw }
12910dcc7149Snw 
12920dcc7149Snw void
12930dcc7149Snw idmap_cfg_poke_updates(void)
12940dcc7149Snw {
1295349d5d8fSnw 	if (idmapd_ev_port != -1)
1296349d5d8fSnw 		(void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
12970dcc7149Snw }
12980dcc7149Snw 
12990dcc7149Snw /*ARGSUSED*/
13000dcc7149Snw void
1301349d5d8fSnw idmap_cfg_hup_handler(int sig)
1302349d5d8fSnw {
13030dcc7149Snw 	if (idmapd_ev_port >= 0)
13040dcc7149Snw 		(void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
13050dcc7149Snw }
1306