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