Home | History | Annotate | Download | only in idmapd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 /*
     28  * Config routines common to idmap(1M) and idmapd(1M)
     29  */
     30 
     31 #include <stdlib.h>
     32 #include <strings.h>
     33 #include <libintl.h>
     34 #include <ctype.h>
     35 #include <errno.h>
     36 #include "idmapd.h"
     37 #include <stdio.h>
     38 #include <stdarg.h>
     39 #include <uuid/uuid.h>
     40 #include <pthread.h>
     41 #include <port.h>
     42 #include <net/route.h>
     43 #include <sys/u8_textprep.h>
     44 #include "addisc.h"
     45 
     46 #define	MACHINE_SID_LEN		(9 + 3 * 11)
     47 #define	FMRI_BASE		"svc:/system/idmap"
     48 #define	CONFIG_PG		"config"
     49 #define	GENERAL_PG		"general"
     50 #define	RECONFIGURE		1
     51 #define	POKE_AUTO_DISCOVERY	2
     52 
     53 /*LINTLIBRARY*/
     54 
     55 
     56 static pthread_t update_thread_handle = 0;
     57 
     58 static int idmapd_ev_port = -1;
     59 static int rt_sock = -1;
     60 
     61 struct enum_lookup_map directory_mapping_map[] = {
     62 	{ DIRECTORY_MAPPING_NONE, "none" },
     63 	{ DIRECTORY_MAPPING_NAME, "name" },
     64 	{ DIRECTORY_MAPPING_IDMU, "idmu" },
     65 	{ 0, NULL },
     66 };
     67 
     68 static int
     69 generate_machine_sid(char **machine_sid)
     70 {
     71 	char *p;
     72 	uuid_t uu;
     73 	int i, j, len, rlen;
     74 	uint32_t rid;
     75 
     76 	/*
     77 	 * Generate and split 128-bit UUID into three 32-bit RIDs The
     78 	 * machine_sid will be of the form S-1-5-21-N1-N2-N3 (that's
     79 	 * four RIDs altogether).
     80 	 *
     81 	 * Technically we could use up to 14 random RIDs here, but it
     82 	 * turns out that with some versions of Windows using SIDs with
     83 	 * more than  five RIDs in security descriptors causes problems.
     84 	 */
     85 
     86 	*machine_sid = calloc(1, MACHINE_SID_LEN);
     87 	if (*machine_sid == NULL) {
     88 		idmapdlog(LOG_ERR, "Out of memory");
     89 		return (-1);
     90 	}
     91 	(void) strcpy(*machine_sid, "S-1-5-21");
     92 	p = *machine_sid + strlen("S-1-5-21");
     93 	len = MACHINE_SID_LEN - strlen("S-1-5-21");
     94 
     95 	uuid_clear(uu);
     96 	uuid_generate_random(uu);
     97 
     98 #if UUID_LEN != 16
     99 #error UUID size is not 16!
    100 #endif
    101 
    102 	for (i = 0; i < 3; i++) {
    103 		j = i * 4;
    104 		rid = (uu[j] << 24) | (uu[j + 1] << 16) |
    105 		    (uu[j + 2] << 8) | (uu[j + 3]);
    106 		rlen = snprintf(p, len, "-%u", rid);
    107 		p += rlen;
    108 		len -= rlen;
    109 	}
    110 
    111 	return (0);
    112 }
    113 
    114 
    115 /* In the case of error, exists is set to FALSE anyway */
    116 static int
    117 prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
    118 {
    119 
    120 	scf_property_t *scf_prop;
    121 	scf_value_t *value;
    122 
    123 	*exists = B_FALSE;
    124 
    125 	scf_prop = scf_property_create(handles->main);
    126 	if (scf_prop == NULL) {
    127 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
    128 		    scf_strerror(scf_error()));
    129 		return (-1);
    130 	}
    131 	value = scf_value_create(handles->main);
    132 	if (value == NULL) {
    133 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
    134 		    scf_strerror(scf_error()));
    135 		scf_property_destroy(scf_prop);
    136 		return (-1);
    137 	}
    138 
    139 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0)
    140 		*exists = B_TRUE;
    141 
    142 	scf_value_destroy(value);
    143 	scf_property_destroy(scf_prop);
    144 
    145 	return (0);
    146 }
    147 
    148 /* Check if in the case of failure the original value of *val is preserved */
    149 static int
    150 get_val_int(idmap_cfg_handles_t *handles, const char *name,
    151 	void *val, scf_type_t type)
    152 {
    153 	int rc = 0;
    154 
    155 	scf_property_t *scf_prop;
    156 	scf_value_t *value;
    157 	uint8_t b;
    158 
    159 	switch (type) {
    160 	case SCF_TYPE_BOOLEAN:
    161 		*(boolean_t *)val = B_FALSE;
    162 		break;
    163 	case SCF_TYPE_COUNT:
    164 		*(uint64_t *)val = 0;
    165 		break;
    166 	case SCF_TYPE_INTEGER:
    167 		*(int64_t *)val = 0;
    168 		break;
    169 	default:
    170 		idmapdlog(LOG_ERR, "Invalid scf integer type (%d)",
    171 		    type);
    172 		abort();
    173 	}
    174 
    175 	scf_prop = scf_property_create(handles->main);
    176 	if (scf_prop == NULL) {
    177 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
    178 		    scf_strerror(scf_error()));
    179 		return (-1);
    180 	}
    181 	value = scf_value_create(handles->main);
    182 	if (value == NULL) {
    183 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
    184 		    scf_strerror(scf_error()));
    185 		scf_property_destroy(scf_prop);
    186 		return (-1);
    187 	}
    188 
    189 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
    190 	/* this is OK: the property is just undefined */
    191 		goto destruction;
    192 
    193 
    194 	if (scf_property_get_value(scf_prop, value) < 0)
    195 	/* It is still OK when a property doesn't have any value */
    196 		goto destruction;
    197 
    198 	switch (type) {
    199 	case SCF_TYPE_BOOLEAN:
    200 		rc = scf_value_get_boolean(value, &b);
    201 		*(boolean_t *)val = b;
    202 		break;
    203 	case SCF_TYPE_COUNT:
    204 		rc = scf_value_get_count(value, val);
    205 		break;
    206 	case SCF_TYPE_INTEGER:
    207 		rc = scf_value_get_integer(value, val);
    208 		break;
    209 	default:
    210 		abort();	/* tested above */
    211 		/* NOTREACHED */
    212 	}
    213 
    214 	if (rc != 0) {
    215 		idmapdlog(LOG_ERR, "Can not retrieve config/%s:  %s",
    216 		    name, scf_strerror(scf_error()));
    217 	}
    218 
    219 destruction:
    220 	scf_value_destroy(value);
    221 	scf_property_destroy(scf_prop);
    222 
    223 	return (rc);
    224 }
    225 
    226 static char *
    227 scf_value2string(const char *name, scf_value_t *value)
    228 {
    229 	static size_t max_val = 0;
    230 
    231 	if (max_val == 0)
    232 		max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
    233 
    234 	char buf[max_val + 1];
    235 	if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
    236 		idmapdlog(LOG_ERR, "Can not retrieve config/%s:  %s",
    237 		    name, scf_strerror(scf_error()));
    238 		return (NULL);
    239 	}
    240 
    241 	char *s = strdup(buf);
    242 	if (s == NULL)
    243 		idmapdlog(LOG_ERR, "Out of memory");
    244 
    245 	return (s);
    246 }
    247 
    248 static int
    249 get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport,
    250 		idmap_ad_disc_ds_t **val)
    251 {
    252 	idmap_ad_disc_ds_t *servers = NULL;
    253 	scf_property_t *scf_prop;
    254 	scf_value_t *value;
    255 	scf_iter_t *iter;
    256 	char *host, *portstr;
    257 	int len, i;
    258 	int count = 0;
    259 	int rc = -1;
    260 
    261 	*val = NULL;
    262 
    263 restart:
    264 	scf_prop = scf_property_create(handles->main);
    265 	if (scf_prop == NULL) {
    266 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
    267 		    scf_strerror(scf_error()));
    268 		return (-1);
    269 	}
    270 
    271 	value = scf_value_create(handles->main);
    272 	if (value == NULL) {
    273 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
    274 		    scf_strerror(scf_error()));
    275 		scf_property_destroy(scf_prop);
    276 		return (-1);
    277 	}
    278 
    279 	iter = scf_iter_create(handles->main);
    280 	if (iter == NULL) {
    281 		idmapdlog(LOG_ERR, "scf_iter_create() failed: %s",
    282 		    scf_strerror(scf_error()));
    283 		scf_value_destroy(value);
    284 		scf_property_destroy(scf_prop);
    285 		return (-1);
    286 	}
    287 
    288 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
    289 		/* this is OK: the property is just undefined */
    290 		rc = 0;
    291 		goto destruction;
    292 	}
    293 
    294 	if (scf_iter_property_values(iter, scf_prop) < 0) {
    295 		idmapdlog(LOG_ERR,
    296 		    "scf_iter_property_values(%s) failed: %s",
    297 		    name, scf_strerror(scf_error()));
    298 		goto destruction;
    299 	}
    300 
    301 	/* Workaround scf bugs -- can't reset an iteration */
    302 	if (count == 0) {
    303 		while (scf_iter_next_value(iter, value) > 0)
    304 			count++;
    305 
    306 		if (count == 0) {
    307 			/* no values */
    308 			rc = 0;
    309 			goto destruction;
    310 		}
    311 
    312 		scf_value_destroy(value);
    313 		scf_iter_destroy(iter);
    314 		scf_property_destroy(scf_prop);
    315 		goto restart;
    316 	}
    317 
    318 	if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
    319 		idmapdlog(LOG_ERR, "Out of memory");
    320 		goto destruction;
    321 	}
    322 
    323 	i = 0;
    324 	while (i < count && scf_iter_next_value(iter, value) > 0) {
    325 		servers[i].priority = 0;
    326 		servers[i].weight = 100;
    327 		servers[i].port = defport;
    328 		if ((host = scf_value2string(name, value)) == NULL) {
    329 			goto destruction;
    330 		}
    331 		if ((portstr = strchr(host, ':')) != NULL) {
    332 			*portstr++ = '\0';
    333 			servers[i].port = strtol(portstr,
    334 			    (char **)NULL, 10);
    335 			if (servers[i].port == 0)
    336 				servers[i].port = defport;
    337 		}
    338 		len = strlcpy(servers[i].host, host,
    339 		    sizeof (servers->host));
    340 
    341 		free(host);
    342 
    343 		/* Ignore this server if the hostname is too long */
    344 		if (len < sizeof (servers->host))
    345 			i++;
    346 	}
    347 
    348 	*val = servers;
    349 
    350 	rc = 0;
    351 
    352 destruction:
    353 	scf_value_destroy(value);
    354 	scf_iter_destroy(iter);
    355 	scf_property_destroy(scf_prop);
    356 
    357 	if (rc < 0) {
    358 		if (servers)
    359 			free(servers);
    360 		*val = NULL;
    361 	}
    362 
    363 	return (rc);
    364 }
    365 
    366 
    367 static int
    368 get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
    369 {
    370 	int rc = 0;
    371 
    372 	scf_property_t *scf_prop;
    373 	scf_value_t *value;
    374 
    375 	scf_prop = scf_property_create(handles->main);
    376 	if (scf_prop == NULL) {
    377 		idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
    378 		    scf_strerror(scf_error()));
    379 		return (-1);
    380 	}
    381 	value = scf_value_create(handles->main);
    382 	if (value == NULL) {
    383 		idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
    384 		    scf_strerror(scf_error()));
    385 		scf_property_destroy(scf_prop);
    386 		return (-1);
    387 	}
    388 
    389 	*val = NULL;
    390 
    391 	if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
    392 	/* this is OK: the property is just undefined */
    393 		goto destruction;
    394 
    395 	if (scf_property_get_value(scf_prop, value) < 0) {
    396 		idmapdlog(LOG_ERR,
    397 		    "scf_property_get_value(%s) failed: %s",
    398 		    name, scf_strerror(scf_error()));
    399 		rc = -1;
    400 		goto destruction;
    401 	}
    402 
    403 	*val = scf_value2string(name, value);
    404 	if (*val == NULL)
    405 		rc = -1;
    406 
    407 destruction:
    408 	scf_value_destroy(value);
    409 	scf_property_destroy(scf_prop);
    410 
    411 	if (rc < 0) {
    412 		if (*val)
    413 			free(*val);
    414 		*val = NULL;
    415 	}
    416 
    417 	return (rc);
    418 }
    419 
    420 
    421 static int
    422 del_val(idmap_cfg_handles_t *handles, const char *name)
    423 {
    424 	int			rc = -1;
    425 	int			ret;
    426 	scf_transaction_t	*tx = NULL;
    427 	scf_transaction_entry_t	*ent = NULL;
    428 
    429 	if ((tx = scf_transaction_create(handles->main)) == NULL) {
    430 		idmapdlog(LOG_ERR,
    431 		    "scf_transaction_create() failed: %s",
    432 		    scf_strerror(scf_error()));
    433 		goto destruction;
    434 	}
    435 	if ((ent = scf_entry_create(handles->main)) == NULL) {
    436 		idmapdlog(LOG_ERR,
    437 		    "scf_entry_create() failed: %s",
    438 		    scf_strerror(scf_error()));
    439 		goto destruction;
    440 	}
    441 
    442 	do {
    443 		if (scf_pg_update(handles->config_pg) == -1) {
    444 			idmapdlog(LOG_ERR,
    445 			    "scf_pg_update(%s) failed: %s",
    446 			    name, scf_strerror(scf_error()));
    447 			goto destruction;
    448 		}
    449 		if (scf_transaction_start(tx, handles->config_pg) != 0) {
    450 			idmapdlog(LOG_ERR,
    451 			    "scf_transaction_start(%s) failed: %s",
    452 			    name, scf_strerror(scf_error()));
    453 			goto destruction;
    454 		}
    455 
    456 		if (scf_transaction_property_delete(tx, ent, name) != 0) {
    457 			/* Don't complain if it already doesn't exist. */
    458 			if (scf_error() != SCF_ERROR_NOT_FOUND) {
    459 				idmapdlog(LOG_ERR,
    460 				    "scf_transaction_property_delete() failed:"
    461 				    " %s",
    462 				    scf_strerror(scf_error()));
    463 			}
    464 			goto destruction;
    465 		}
    466 
    467 		ret = scf_transaction_commit(tx);
    468 
    469 		if (ret == 0)
    470 			scf_transaction_reset(tx);
    471 	} while (ret == 0);
    472 
    473 	if (ret == -1) {
    474 		idmapdlog(LOG_ERR,
    475 		    "scf_transaction_commit(%s) failed: %s",
    476 		    name, scf_strerror(scf_error()));
    477 		goto destruction;
    478 	}
    479 
    480 	rc = 0;
    481 
    482 destruction:
    483 	if (ent != NULL)
    484 		scf_entry_destroy(ent);
    485 	if (tx != NULL)
    486 		scf_transaction_destroy(tx);
    487 	return (rc);
    488 }
    489 
    490 
    491 static int
    492 set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val)
    493 {
    494 	int			rc = -1;
    495 	int			ret = -2;
    496 	int			i;
    497 	scf_property_t		*scf_prop = NULL;
    498 	scf_value_t		*value = NULL;
    499 	scf_transaction_t	*tx = NULL;
    500 	scf_transaction_entry_t	*ent = NULL;
    501 
    502 	if ((scf_prop = scf_property_create(handles->main)) == NULL ||
    503 	    (value = scf_value_create(handles->main)) == NULL ||
    504 	    (tx = scf_transaction_create(handles->main)) == NULL ||
    505 	    (ent = scf_entry_create(handles->main)) == NULL) {
    506 		idmapdlog(LOG_ERR, "Unable to set property %s",
    507 		    name, scf_strerror(scf_error()));
    508 		goto destruction;
    509 	}
    510 
    511 	for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) {
    512 		if (scf_transaction_start(tx, handles->config_pg) == -1) {
    513 			idmapdlog(LOG_ERR,
    514 			    "scf_transaction_start(%s) failed: %s",
    515 			    name, scf_strerror(scf_error()));
    516 			goto destruction;
    517 		}
    518 
    519 		if (scf_transaction_property_new(tx, ent, name,
    520 		    SCF_TYPE_ASTRING) < 0) {
    521 			idmapdlog(LOG_ERR,
    522 			    "scf_transaction_property_new() failed: %s",
    523 			    scf_strerror(scf_error()));
    524 			goto destruction;
    525 		}
    526 
    527 		if (scf_value_set_astring(value, val) == -1) {
    528 			idmapdlog(LOG_ERR,
    529 			    "scf_value_set_astring() failed: %s",
    530 			    scf_strerror(scf_error()));
    531 			goto destruction;
    532 		}
    533 
    534 		if (scf_entry_add_value(ent, value) == -1) {
    535 			idmapdlog(LOG_ERR,
    536 			    "scf_entry_add_value() failed: %s",
    537 			    scf_strerror(scf_error()));
    538 			goto destruction;
    539 		}
    540 
    541 		if ((ret = scf_transaction_commit(tx)) == 1)
    542 			break;
    543 
    544 		if (ret == 0 && i < MAX_TRIES - 1) {
    545 			/*
    546 			 * Property group set in scf_transaction_start()
    547 			 * is not the most recent. Update pg, reset tx and
    548 			 * retry tx.
    549 			 */
    550 			idmapdlog(LOG_WARNING,
    551 			    "scf_transaction_commit(%s) failed - Retry: %s",
    552 			    name, scf_strerror(scf_error()));
    553 			if (scf_pg_update(handles->config_pg) == -1) {
    554 				idmapdlog(LOG_ERR,
    555 				    "scf_pg_update() failed: %s",
    556 				    scf_strerror(scf_error()));
    557 				goto destruction;
    558 			}
    559 			scf_transaction_reset(tx);
    560 		}
    561 	}
    562 
    563 
    564 	if (ret == 1)
    565 		rc = 0;
    566 	else if (ret != -2)
    567 		idmapdlog(LOG_ERR,
    568 		    "scf_transaction_commit(%s) failed: %s",
    569 		    name, scf_strerror(scf_error()));
    570 
    571 destruction:
    572 	scf_value_destroy(value);
    573 	scf_entry_destroy(ent);
    574 	scf_transaction_destroy(tx);
    575 	scf_property_destroy(scf_prop);
    576 	return (rc);
    577 }
    578 
    579 
    580 
    581 /*
    582  * This function updates a boolean value.
    583  * If nothing has changed it returns 0 else 1
    584  */
    585 static int
    586 update_bool(boolean_t *value, boolean_t *new, char *name)
    587 {
    588 	if (*value == *new)
    589 		return (0);
    590 
    591 	idmapdlog(LOG_INFO, "change %s=%s", name, *new ? "true" : "false");
    592 	*value = *new;
    593 	return (1);
    594 }
    595 
    596 
    597 /*
    598  * This function updates a string value.
    599  * If nothing has changed it returns 0 else 1
    600  */
    601 static int
    602 update_string(char **value, char **new, char *name)
    603 {
    604 	if (*new == NULL)
    605 		return (0);
    606 
    607 	if (*value != NULL && strcmp(*new, *value) == 0) {
    608 		free(*new);
    609 		*new = NULL;
    610 		return (0);
    611 	}
    612 
    613 	idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
    614 	if (*value != NULL)
    615 		free(*value);
    616 	*value = *new;
    617 	*new = NULL;
    618 	return (1);
    619 }
    620 
    621 static int
    622 update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
    623 {
    624 	if (*value == *new)
    625 		return (0);
    626 
    627 	idmapdlog(LOG_INFO, "change %s=%s", name, enum_lookup(*new, map));
    628 
    629 	*value = *new;
    630 
    631 	return (1);
    632 }
    633 
    634 /*
    635  * This function updates a directory service structure.
    636  * If nothing has changed it returns 0 else 1
    637  */
    638 static int
    639 update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new, char *name)
    640 {
    641 	int i;
    642 
    643 	if (*value == *new)
    644 		/* Nothing to do */
    645 		return (0);
    646 
    647 	if (*value != NULL && *new != NULL &&
    648 	    ad_disc_compare_ds(*value, *new) == 0) {
    649 		free(*new);
    650 		*new = NULL;
    651 		return (0);
    652 	}
    653 
    654 	if (*value != NULL)
    655 		free(*value);
    656 
    657 	*value = *new;
    658 	*new = NULL;
    659 
    660 	if (*value == NULL) {
    661 		/* We're unsetting this DS property */
    662 		idmapdlog(LOG_INFO, "change %s=<none>", name);
    663 		return (1);
    664 	}
    665 
    666 	/* List all the new DSs */
    667 	for (i = 0; (*value)[i].host[0] != '\0'; i++)
    668 		idmapdlog(LOG_INFO, "change %s=%s port=%d", name,
    669 		    (*value)[i].host, (*value)[i].port);
    670 	return (1);
    671 }
    672 
    673 /*
    674  * This function updates a trusted domains structure.
    675  * If nothing has changed it returns 0 else 1
    676  */
    677 static int
    678 update_trusted_domains(ad_disc_trusteddomains_t **value,
    679 			ad_disc_trusteddomains_t **new, char *name)
    680 {
    681 	int i;
    682 
    683 	if (*value == *new)
    684 		/* Nothing to do */
    685 		return (0);
    686 
    687 	if (*value != NULL && *new != NULL &&
    688 	    ad_disc_compare_trusteddomains(*value, *new) == 0) {
    689 		free(*new);
    690 		*new = NULL;
    691 		return (0);
    692 	}
    693 
    694 	if (*value != NULL)
    695 		free(*value);
    696 
    697 	*value = *new;
    698 	*new = NULL;
    699 
    700 	if (*value == NULL) {
    701 		/* We're unsetting this DS property */
    702 		idmapdlog(LOG_INFO, "change %s=<none>", name);
    703 		return (1);
    704 	}
    705 
    706 	/* List all the new domains */
    707 	for (i = 0; (*value)[i].domain[0] != '\0'; i++)
    708 		idmapdlog(LOG_INFO, "change %s=%s direction=%s", name,
    709 		    (*value)[i].domain,
    710 		    (*value)[i].direction == 3 ? "bi-directional" : "inbound");
    711 	return (1);
    712 }
    713 
    714 
    715 /*
    716  * This function updates a domains in a forest structure.
    717  * If nothing has changed it returns 0 else 1
    718  */
    719 static int
    720 update_domains_in_forest(ad_disc_domainsinforest_t **value,
    721 			ad_disc_domainsinforest_t **new, char *name)
    722 {
    723 	int i;
    724 
    725 	if (*value == *new)
    726 		/* Nothing to do */
    727 		return (0);
    728 
    729 	if (*value != NULL && *new != NULL &&
    730 	    ad_disc_compare_domainsinforest(*value, *new) == 0) {
    731 		free(*new);
    732 		*new = NULL;
    733 		return (0);
    734 	}
    735 
    736 	if (*value != NULL)
    737 		free(*value);
    738 
    739 	*value = *new;
    740 	*new = NULL;
    741 
    742 	if (*value == NULL) {
    743 		/* We're unsetting this DS property */
    744 		idmapdlog(LOG_INFO, "change %s=<none>", name);
    745 		return (1);
    746 	}
    747 
    748 	/* List all the new domains */
    749 	for (i = 0; (*value)[i].domain[0] != '\0'; i++)
    750 		idmapdlog(LOG_INFO, "change %s=%s", name,
    751 		    (*value)[i].domain);
    752 	return (1);
    753 }
    754 
    755 
    756 static void
    757 free_trusted_forests(idmap_trustedforest_t **value, int *num_values)
    758 {
    759 	int i;
    760 
    761 	for (i = 0; i < *num_values; i++) {
    762 		free((*value)[i].forest_name);
    763 		free((*value)[i].global_catalog);
    764 		free((*value)[i].domains_in_forest);
    765 	}
    766 	free(*value);
    767 	*value = NULL;
    768 	*num_values = 0;
    769 }
    770 
    771 
    772 static int
    773 compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1,
    774 			ad_disc_domainsinforest_t *df2)
    775 {
    776 	int		i, j;
    777 	int		num_df1 = 0;
    778 	int		num_df2 = 0;
    779 	boolean_t	match;
    780 
    781 	for (i = 0; df1[i].domain[0] != '\0'; i++)
    782 		if (df1[i].trusted)
    783 			num_df1++;
    784 
    785 	for (j = 0; df2[j].domain[0] != '\0'; j++)
    786 		if (df2[j].trusted)
    787 			num_df2++;
    788 
    789 	if (num_df1 != num_df2)
    790 		return (1);
    791 
    792 	for (i = 0; df1[i].domain[0] != '\0'; i++) {
    793 		if (df1[i].trusted) {
    794 			match = B_FALSE;
    795 			for (j = 0; df2[j].domain[0] != '\0'; j++) {
    796 				if (df2[j].trusted &&
    797 				    domain_eq(df1[i].domain, df2[j].domain) &&
    798 				    strcmp(df1[i].sid, df2[j].sid) == 0) {
    799 					match = B_TRUE;
    800 					break;
    801 				}
    802 			}
    803 			if (!match)
    804 				return (1);
    805 		}
    806 	}
    807 	return (0);
    808 }
    809 
    810 
    811 
    812 /*
    813  * This function updates trusted forest structure.
    814  * If nothing has changed it returns 0 else 1
    815  */
    816 static int
    817 update_trusted_forest(idmap_trustedforest_t **value, int *num_value,
    818 			idmap_trustedforest_t **new, int *num_new, char *name)
    819 {
    820 	int i, j;
    821 	boolean_t match;
    822 
    823 	if (*value == *new)
    824 		/* Nothing to do */
    825 		return (0);
    826 
    827 	if (*value != NULL && *new != NULL) {
    828 		if (*num_value != *num_new)
    829 			goto not_equal;
    830 		for (i = 0; i < *num_value; i++) {
    831 			match = B_FALSE;
    832 			for (j = 0; j < *num_new; j++) {
    833 				if (strcmp((*value)[i].forest_name,
    834 				    (*new)[j].forest_name) == 0 &&
    835 				    ad_disc_compare_ds(
    836 				    (*value)[i].global_catalog,
    837 				    (*new)[j].global_catalog) == 0 &&
    838 				    compare_trusteddomainsinforest(
    839 				    (*value)[i].domains_in_forest,
    840 				    (*new)[j].domains_in_forest) == 0) {
    841 					match = B_TRUE;
    842 					break;
    843 				}
    844 			}
    845 			if (!match)
    846 				goto not_equal;
    847 		}
    848 		free_trusted_forests(new, num_new);
    849 		return (0);
    850 	}
    851 not_equal:
    852 	if (*value != NULL)
    853 		free_trusted_forests(value, num_value);
    854 	*value = *new;
    855 	*num_value = *num_new;
    856 	*new = NULL;
    857 	*num_new = 0;
    858 
    859 	if (*value == NULL) {
    860 		/* We're unsetting this DS property */
    861 		idmapdlog(LOG_INFO, "change %s=<none>", name);
    862 		return (1);
    863 	}
    864 
    865 	/* List all the trusted forests */
    866 	for (i = 0; i < *num_value; i++) {
    867 		for (j = 0; (*value)[i].domains_in_forest[j].domain[0] != '\0';
    868 		    j++) {
    869 			/* List trusted Domains in the forest. */
    870 			if ((*value)[i].domains_in_forest[j].trusted)
    871 				idmapdlog(LOG_INFO, "change %s=%s domain=%s",
    872 				    name, (*value)[i].forest_name,
    873 				    (*value)[i].domains_in_forest[j].domain);
    874 		}
    875 		/* List the hosts */
    876 		for (j = 0; (*value)[i].global_catalog[j].host[0] != '\0'; j++)
    877 			idmapdlog(LOG_INFO, "change %s=%s host=%s port=%d",
    878 			    name, (*value)[i].forest_name,
    879 			    (*value)[i].global_catalog[j].host,
    880 			    (*value)[i].global_catalog[j].port);
    881 	}
    882 	return (1);
    883 }
    884 
    885 const char *
    886 enum_lookup(int value, struct enum_lookup_map *map)
    887 {
    888 	for (; map->string != NULL; map++) {
    889 		if (value == map->value) {
    890 			return (map->string);
    891 		}
    892 	}
    893 	return ("(invalid)");
    894 }
    895 
    896 #define	MAX_CHECK_TIME		(20 * 60)
    897 
    898 /*
    899  * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
    900  * interfaces.
    901  *
    902  * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
    903  */
    904 static
    905 int
    906 pfroute_event_is_interesting(int rt_sock)
    907 {
    908 	int nbytes;
    909 	int64_t msg[2048 / 8];
    910 	struct rt_msghdr *rtm;
    911 	int is_interesting = FALSE;
    912 
    913 	for (;;) {
    914 		if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
    915 			break;
    916 		rtm = (struct rt_msghdr *)msg;
    917 		if (rtm->rtm_version != RTM_VERSION)
    918 			continue;
    919 		if (nbytes < rtm->rtm_msglen)
    920 			continue;
    921 		switch (rtm->rtm_type) {
    922 		case RTM_NEWADDR:
    923 		case RTM_DELADDR:
    924 		case RTM_IFINFO:
    925 			is_interesting = TRUE;
    926 			break;
    927 		default:
    928 			break;
    929 		}
    930 	}
    931 	return (is_interesting);
    932 }
    933 
    934 /*
    935  * Returns 1 if SIGHUP has been received (see hup_handler() elsewhere) or if an
    936  * interface address was added or removed; otherwise it returns 0.
    937  *
    938  * Note that port_get() does not update its timeout argument when EINTR, unlike
    939  * nanosleep().  We probably don't care very much here, but if we did care then
    940  * we could always use a timer event and associate it with the same event port,
    941  * then we could get accurate waiting regardless of EINTRs.
    942  */
    943 static
    944 int
    945 wait_for_event(int poke_is_interesting, struct timespec *timeoutp)
    946 {
    947 	port_event_t pe;
    948 
    949 retry:
    950 	memset(&pe, 0, sizeof (pe));
    951 	if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
    952 		switch (errno) {
    953 		case EINTR:
    954 			goto retry;
    955 		case ETIME:
    956 			/* Timeout */
    957 			return (FALSE);
    958 		default:
    959 			/* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
    960 			idmapdlog(LOG_ERR, "Event port failed: %s",
    961 			    strerror(errno));
    962 			exit(1);
    963 			/* NOTREACHED */
    964 			break;
    965 		}
    966 	}
    967 
    968 	if (pe.portev_source == PORT_SOURCE_USER &&
    969 	    pe.portev_events == POKE_AUTO_DISCOVERY)
    970 		return (poke_is_interesting ? TRUE : FALSE);
    971 
    972 	if (pe.portev_source == PORT_SOURCE_FD && pe.portev_object == rt_sock) {
    973 		/* PF_ROUTE socket read event, re-associate fd, handle event */
    974 		if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock,
    975 		    POLLIN, NULL) != 0) {
    976 			idmapdlog(LOG_ERR, "Failed to re-associate the "
    977 			    "routing socket with the event port: %s",
    978 			    strerror(errno));
    979 			exit(1);
    980 		}
    981 		/*
    982 		 * The network configuration may still be in flux.  No matter,
    983 		 * the resolver will re-transmit and timout if need be.
    984 		 */
    985 		return (pfroute_event_is_interesting(rt_sock));
    986 	}
    987 
    988 	if (pe.portev_source == PORT_SOURCE_USER &&
    989 	    pe.portev_events == RECONFIGURE) {
    990 		int rc;
    991 
    992 		/*
    993 		 * Blow away the ccache, we might have re-joined the
    994 		 * domain or joined a new one
    995 		 */
    996 		(void) unlink(IDMAP_CACHEDIR "/ccache");
    997 		/* HUP is the refresh method, so re-read SMF config */
    998 		idmapdlog(LOG_INFO, "SMF refresh");
    999 		rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER|CFG_LOG);
   1000 		if (rc < -1) {
   1001 			idmapdlog(LOG_ERR, "Fatal errors while reading "
   1002 			    "SMF properties");
   1003 			exit(1);
   1004 		} else if (rc == -1) {
   1005 			idmapdlog(LOG_WARNING, "Various errors "
   1006 			    "re-loading configuration may cause AD lookups "
   1007 			    "to fail");
   1008 		}
   1009 		return (FALSE);
   1010 	}
   1011 
   1012 	return (FALSE);
   1013 }
   1014 
   1015 void *
   1016 idmap_cfg_update_thread(void *arg)
   1017 {
   1018 
   1019 	int			ttl, changed, poke_is_interesting;
   1020 	idmap_cfg_handles_t	*handles = &_idmapdstate.cfg->handles;
   1021 	ad_disc_t		ad_ctx = handles->ad_ctx;
   1022 	struct timespec		timeout, *timeoutp;
   1023 
   1024 	poke_is_interesting = 1;
   1025 	for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) {
   1026 		/*
   1027 		 * If ttl < 0 then we can wait for an event without timing out.
   1028 		 * If idmapd needs to notice that the system has been joined to
   1029 		 * a Windows domain then idmapd needs to be refreshed.
   1030 		 */
   1031 		timeoutp = (ttl < 0) ? NULL : &timeout;
   1032 		if (ttl > MAX_CHECK_TIME)
   1033 			ttl = MAX_CHECK_TIME;
   1034 		timeout.tv_sec = ttl;
   1035 		timeout.tv_nsec = 0;
   1036 		changed = wait_for_event(poke_is_interesting, timeoutp);
   1037 
   1038 		/*
   1039 		 * If there are no interesting events, and this is not the first
   1040 		 * time through the loop, and we haven't waited the most that
   1041 		 * we're willing to wait, so do nothing but wait some more.
   1042 		 */
   1043 		if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME)
   1044 			continue;
   1045 
   1046 		(void) ad_disc_SubnetChanged(ad_ctx);
   1047 
   1048 		if (idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER) < -1) {
   1049 			idmapdlog(LOG_ERR, "Fatal errors while reading "
   1050 			    "SMF properties");
   1051 			exit(1);
   1052 		}
   1053 
   1054 		if (_idmapdstate.cfg->pgcfg.global_catalog == NULL ||
   1055 		    _idmapdstate.cfg->pgcfg.global_catalog[0].host[0] == '\0')
   1056 			poke_is_interesting = 1;
   1057 		else
   1058 			poke_is_interesting = 0;
   1059 	}
   1060 	/*NOTREACHED*/
   1061 	return (NULL);
   1062 }
   1063 
   1064 int
   1065 idmap_cfg_start_updates(void)
   1066 {
   1067 	if ((idmapd_ev_port = port_create()) < 0) {
   1068 		idmapdlog(LOG_ERR, "Failed to create event port: %s",
   1069 		    strerror(errno));
   1070 		return (-1);
   1071 	}
   1072 
   1073 	if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
   1074 		idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
   1075 		    strerror(errno));
   1076 		(void) close(idmapd_ev_port);
   1077 		return (-1);
   1078 	}
   1079 
   1080 	if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
   1081 		idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
   1082 		    strerror(errno));
   1083 		(void) close(rt_sock);
   1084 		(void) close(idmapd_ev_port);
   1085 		return (-1);
   1086 	}
   1087 
   1088 	if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
   1089 	    rt_sock, POLLIN, NULL) != 0) {
   1090 		idmapdlog(LOG_ERR, "Failed to associate the routing "
   1091 		    "socket with the event port: %s", strerror(errno));
   1092 		(void) close(rt_sock);
   1093 		(void) close(idmapd_ev_port);
   1094 		return (-1);
   1095 	}
   1096 
   1097 	if ((errno = pthread_create(&update_thread_handle, NULL,
   1098 	    idmap_cfg_update_thread, NULL)) != 0) {
   1099 		idmapdlog(LOG_ERR, "Failed to start update thread: %s",
   1100 		    strerror(errno));
   1101 		(void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
   1102 		(void) close(rt_sock);
   1103 		(void) close(idmapd_ev_port);
   1104 		return (-1);
   1105 	}
   1106 
   1107 	return (0);
   1108 }
   1109 
   1110 /*
   1111  * Reject attribute names with invalid characters.
   1112  */
   1113 static
   1114 int
   1115 valid_ldap_attr(const char *attr) {
   1116 	for (; *attr; attr++) {
   1117 		if (!isalnum(*attr) && *attr != '-' &&
   1118 		    *attr != '_' && *attr != '.' && *attr != ';')
   1119 			return (0);
   1120 	}
   1121 	return (1);
   1122 }
   1123 
   1124 static
   1125 int
   1126 check_smf_debug_mode(idmap_cfg_handles_t *handles)
   1127 {
   1128 	boolean_t new_debug_mode;
   1129 	int rc;
   1130 
   1131 	rc = prop_exists(handles, "debug", &new_debug_mode);
   1132 	if (rc != 0)
   1133 		return (rc);
   1134 
   1135 	if (_idmapdstate.debug_mode != new_debug_mode) {
   1136 		if (!_idmapdstate.debug_mode) {
   1137 			_idmapdstate.debug_mode = new_debug_mode;
   1138 			idmap_log_stderr(LOG_DEBUG);
   1139 			idmapdlog(LOG_DEBUG, "debug mode enabled");
   1140 		} else {
   1141 			idmapdlog(LOG_DEBUG, "debug mode disabled");
   1142 			idmap_log_stderr(-1);
   1143 			_idmapdstate.debug_mode = new_debug_mode;
   1144 		}
   1145 	}
   1146 
   1147 	return (0);
   1148 }
   1149 
   1150 /*
   1151  * This is the half of idmap_cfg_load() that loads property values from
   1152  * SMF (using the config/ property group of the idmap FMRI).
   1153  *
   1154  * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
   1155  *               -3 -> hard smf config failures
   1156  * reading from SMF.
   1157  */
   1158 static
   1159 int
   1160 idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
   1161 	int * const errors)
   1162 {
   1163 	int rc;
   1164 	char *s;
   1165 
   1166 	*errors = 0;
   1167 
   1168 	if (scf_pg_update(handles->config_pg) < 0) {
   1169 		idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
   1170 		    scf_strerror(scf_error()));
   1171 		return (-2);
   1172 	}
   1173 
   1174 	if (scf_pg_update(handles->general_pg) < 0) {
   1175 		idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
   1176 		    scf_strerror(scf_error()));
   1177 		return (-2);
   1178 	}
   1179 
   1180 	rc = check_smf_debug_mode(handles);
   1181 	if (rc != 0)
   1182 		(*errors)++;
   1183 
   1184 	rc = get_val_int(handles, "unresolvable_sid_mapping",
   1185 	    &pgcfg->eph_map_unres_sids, SCF_TYPE_BOOLEAN);
   1186 	if (rc != 0)
   1187 		(*errors)++;
   1188 
   1189 	rc = get_val_astring(handles, "directory_based_mapping", &s);
   1190 	if (rc != 0)
   1191 		(*errors)++;
   1192 	else if (s == NULL || strcasecmp(s, "none") == 0)
   1193 		pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
   1194 	else if (strcasecmp(s, "name") == 0)
   1195 		pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
   1196 	else if (strcasecmp(s, "idmu") == 0)
   1197 		pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
   1198 	else {
   1199 		pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
   1200 		idmapdlog(LOG_ERR,
   1201 		"config/directory_based_mapping:  invalid value \"%s\" ignored",
   1202 		    s);
   1203 		(*errors)++;
   1204 	}
   1205 	free(s);
   1206 
   1207 	rc = get_val_int(handles, "list_size_limit",
   1208 	    &pgcfg->list_size_limit, SCF_TYPE_COUNT);
   1209 	if (rc != 0)
   1210 		(*errors)++;
   1211 
   1212 	rc = get_val_astring(handles, "domain_name",
   1213 	    &pgcfg->domain_name);
   1214 	if (rc != 0)
   1215 		(*errors)++;
   1216 	else {
   1217 		(void) ad_disc_set_DomainName(handles->ad_ctx,
   1218 		    pgcfg->domain_name);
   1219 		pgcfg->domain_name_auto_disc = B_FALSE;
   1220 	}
   1221 
   1222 	rc = get_val_astring(handles, "default_domain",
   1223 	    &pgcfg->default_domain);
   1224 	if (rc != 0) {
   1225 		/*
   1226 		 * SCF failures fetching config/default_domain we treat
   1227 		 * as fatal as they may leave ID mapping rules that
   1228 		 * match unqualified winnames flapping in the wind.
   1229 		 */
   1230 		return (-2);
   1231 	}
   1232 
   1233 	if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
   1234 		pgcfg->default_domain = strdup(pgcfg->domain_name);
   1235 	}
   1236 
   1237 	rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
   1238 	if (rc != 0)
   1239 		(*errors)++;
   1240 	if (pgcfg->machine_sid == NULL) {
   1241 		/* If machine_sid not configured, generate one */
   1242 		if (generate_machine_sid(&pgcfg->machine_sid) < 0)
   1243 			return (-2);
   1244 		rc = set_val_astring(handles, "machine_sid",
   1245 		    pgcfg->machine_sid);
   1246 		if (rc != 0)
   1247 			(*errors)++;
   1248 	}
   1249 
   1250 	rc = get_val_ds(handles, "domain_controller", 389,
   1251 	    &pgcfg->domain_controller);
   1252 	if (rc != 0)
   1253 		(*errors)++;
   1254 	else {
   1255 		(void) ad_disc_set_DomainController(handles->ad_ctx,
   1256 		    pgcfg->domain_controller);
   1257 		pgcfg->domain_controller_auto_disc = B_FALSE;
   1258 	}
   1259 
   1260 	rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
   1261 	if (rc != 0)
   1262 		(*errors)++;
   1263 	else {
   1264 		(void) ad_disc_set_ForestName(handles->ad_ctx,
   1265 		    pgcfg->forest_name);
   1266 		pgcfg->forest_name_auto_disc = B_FALSE;
   1267 	}
   1268 
   1269 	rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
   1270 	if (rc != 0)
   1271 		(*errors)++;
   1272 	else
   1273 		(void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
   1274 
   1275 	rc = get_val_ds(handles, "global_catalog", 3268,
   1276 	    &pgcfg->global_catalog);
   1277 	if (rc != 0)
   1278 		(*errors)++;
   1279 	else {
   1280 		(void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
   1281 		    pgcfg->global_catalog);
   1282 		pgcfg->global_catalog_auto_disc = B_FALSE;
   1283 	}
   1284 
   1285 	/* Unless we're doing directory-based name mapping, we're done. */
   1286 	if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
   1287 		return (0);
   1288 
   1289 	rc = get_val_astring(handles, "ad_unixuser_attr",
   1290 	    &pgcfg->ad_unixuser_attr);
   1291 	if (rc != 0)
   1292 		return (-2);
   1293 	if (pgcfg->ad_unixuser_attr != NULL &&
   1294 	    !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
   1295 		idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
   1296 		    "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
   1297 		return (-3);
   1298 	}
   1299 
   1300 	rc = get_val_astring(handles, "ad_unixgroup_attr",
   1301 	    &pgcfg->ad_unixgroup_attr);
   1302 	if (rc != 0)
   1303 		return (-2);
   1304 	if (pgcfg->ad_unixgroup_attr != NULL &&
   1305 	    !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
   1306 		idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
   1307 		    "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
   1308 		return (-3);
   1309 	}
   1310 
   1311 	rc = get_val_astring(handles, "nldap_winname_attr",
   1312 	    &pgcfg->nldap_winname_attr);
   1313 	if (rc != 0)
   1314 		return (-2);
   1315 	if (pgcfg->nldap_winname_attr != NULL &&
   1316 	    !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
   1317 		idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
   1318 		    "valid LDAP attribute name", pgcfg->nldap_winname_attr);
   1319 		return (-3);
   1320 	}
   1321 	if (pgcfg->ad_unixuser_attr == NULL &&
   1322 	    pgcfg->ad_unixgroup_attr == NULL &&
   1323 	    pgcfg->nldap_winname_attr == NULL) {
   1324 		idmapdlog(LOG_ERR,
   1325 		    "If config/directory_based_mapping property is set to "
   1326 		    "\"name\" then at least one of the following name mapping "
   1327 		    "attributes must be specified. (config/ad_unixuser_attr OR "
   1328 		    "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
   1329 		return (-3);
   1330 	}
   1331 
   1332 	return (rc);
   1333 
   1334 }
   1335 
   1336 
   1337 /*
   1338  * This is the half of idmap_cfg_load() that auto-discovers values of
   1339  * discoverable properties that weren't already set via SMF properties.
   1340  *
   1341  * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
   1342  * needs to be careful not to overwrite any properties set in SMF.
   1343  */
   1344 static
   1345 void
   1346 idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
   1347 {
   1348 	ad_disc_t ad_ctx = handles->ad_ctx;
   1349 	ad_disc_t trusted_ctx;
   1350 	int i, j, k, l;
   1351 	char *forestname;
   1352 	int num_trusteddomains;
   1353 	boolean_t new_forest;
   1354 	char *trusteddomain;
   1355 	idmap_ad_disc_ds_t *globalcatalog;
   1356 	idmap_trustedforest_t *trustedforests;
   1357 	ad_disc_domainsinforest_t *domainsinforest;
   1358 
   1359 	ad_disc_refresh(ad_ctx);
   1360 
   1361 	if (pgcfg->default_domain == NULL)
   1362 		pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx,
   1363 		    NULL);
   1364 
   1365 	if (pgcfg->domain_name == NULL)
   1366 		pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx,
   1367 		    &pgcfg->domain_name_auto_disc);
   1368 
   1369 	if (pgcfg->domain_controller == NULL)
   1370 		pgcfg->domain_controller =
   1371 		    ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE,
   1372 		    &pgcfg->domain_controller_auto_disc);
   1373 
   1374 	if (pgcfg->forest_name == NULL)
   1375 		pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx,
   1376 		    &pgcfg->forest_name_auto_disc);
   1377 
   1378 	if (pgcfg->site_name == NULL)
   1379 		pgcfg->site_name = ad_disc_get_SiteName(ad_ctx,
   1380 		    &pgcfg->site_name_auto_disc);
   1381 
   1382 	if (pgcfg->global_catalog == NULL)
   1383 		pgcfg->global_catalog =
   1384 		    ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE,
   1385 		    &pgcfg->global_catalog_auto_disc);
   1386 
   1387 	pgcfg->domains_in_forest =
   1388 	    ad_disc_get_DomainsInForest(ad_ctx, NULL);
   1389 
   1390 	pgcfg->trusted_domains =
   1391 	    ad_disc_get_TrustedDomains(ad_ctx, NULL);
   1392 
   1393 	if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL &&
   1394 	    pgcfg->trusted_domains[0].domain[0] != '\0') {
   1395 		/*
   1396 		 * We have trusted domains.  We need to go through every
   1397 		 * one and find its forest. If it is a new forest we then need
   1398 		 * to find its Global Catalog and the domains in the forest
   1399 		 */
   1400 		for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
   1401 			continue;
   1402 		num_trusteddomains = i;
   1403 
   1404 		trustedforests = calloc(num_trusteddomains,
   1405 		    sizeof (idmap_trustedforest_t));
   1406 		j = 0;
   1407 		for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) {
   1408 			trusteddomain = pgcfg->trusted_domains[i].domain;
   1409 			trusted_ctx = ad_disc_init();
   1410 			ad_disc_set_DomainName(trusted_ctx,
   1411 			    trusteddomain);
   1412 			forestname =
   1413 			    ad_disc_get_ForestName(trusted_ctx, NULL);
   1414 			if (forestname == NULL) {
   1415 				idmapdlog(LOG_DEBUG, "unable to discover "
   1416 				    "Forest Name for the trusted domain %s",
   1417 				    trusteddomain);
   1418 				ad_disc_fini(trusted_ctx);
   1419 				continue;
   1420 			}
   1421 
   1422 			if (strcasecmp(forestname, pgcfg->forest_name) == 0) {
   1423 				/*
   1424 				 * Ignore the domain as it is part of
   1425 				 * the primary forest
   1426 				 */
   1427 				free(forestname);
   1428 				ad_disc_fini(trusted_ctx);
   1429 				continue;
   1430 			}
   1431 
   1432 			/* Is this a new forest? */
   1433 			new_forest = B_TRUE;
   1434 			for (k = 0; k < j; k++) {
   1435 				if (strcasecmp(forestname,
   1436 				    trustedforests[k].forest_name) == 0) {
   1437 					new_forest = B_FALSE;
   1438 					domainsinforest =
   1439 					    trustedforests[k].domains_in_forest;
   1440 					break;
   1441 				}
   1442 			}
   1443 			if (!new_forest) {
   1444 				/* Mark the domain as trusted */
   1445 				for (l = 0;
   1446 				    domainsinforest[l].domain[0] != '\0'; l++) {
   1447 					if (domain_eq(trusteddomain,
   1448 					    domainsinforest[l].domain)) {
   1449 						domainsinforest[l].trusted =
   1450 						    TRUE;
   1451 						break;
   1452 					}
   1453 				}
   1454 				free(forestname);
   1455 				ad_disc_fini(trusted_ctx);
   1456 				continue;
   1457 			}
   1458 
   1459 			/*
   1460 			 * Get the Global Catalog and the domains in
   1461 			 * this new forest.
   1462 			 */
   1463 			globalcatalog =
   1464 			    ad_disc_get_GlobalCatalog(trusted_ctx,
   1465 			    AD_DISC_PREFER_SITE, NULL);
   1466 			if (globalcatalog == NULL) {
   1467 				idmapdlog(LOG_DEBUG,
   1468 				    "unable to discover Global "
   1469 				    "Catalog for the trusted domain %s",
   1470 				    trusteddomain);
   1471 				free(forestname);
   1472 				ad_disc_fini(trusted_ctx);
   1473 				continue;
   1474 			}
   1475 			domainsinforest =
   1476 			    ad_disc_get_DomainsInForest(trusted_ctx,
   1477 			    NULL);
   1478 			if (domainsinforest == NULL) {
   1479 				idmapdlog(LOG_DEBUG,
   1480 				    "unable to discover Domains in the Forest "
   1481 				    "for the trusted domain %s",
   1482 				    trusteddomain);
   1483 				free(globalcatalog);
   1484 				free(forestname);
   1485 				ad_disc_fini(trusted_ctx);
   1486 				continue;
   1487 			}
   1488 
   1489 			trustedforests[j].forest_name = forestname;
   1490 			trustedforests[j].global_catalog = globalcatalog;
   1491 			trustedforests[j].domains_in_forest = domainsinforest;
   1492 			j++;
   1493 			/* Mark the domain as trusted */
   1494 			for (l = 0; domainsinforest[l].domain[0] != '\0';
   1495 			    l++) {
   1496 				if (domain_eq(trusteddomain,
   1497 				    domainsinforest[l].domain)) {
   1498 					domainsinforest[l].trusted = TRUE;
   1499 					break;
   1500 				}
   1501 			}
   1502 			ad_disc_fini(trusted_ctx);
   1503 		}
   1504 		if (j > 0) {
   1505 			pgcfg->num_trusted_forests = j;
   1506 			pgcfg->trusted_forests = trustedforests;
   1507 		} else {
   1508 			free(trustedforests);
   1509 		}
   1510 	}
   1511 
   1512 	if (pgcfg->domain_name == NULL)
   1513 		idmapdlog(LOG_DEBUG, "unable to discover Domain Name");
   1514 	if (pgcfg->domain_controller == NULL)
   1515 		idmapdlog(LOG_DEBUG, "unable to discover Domain Controller");
   1516 	if (pgcfg->forest_name == NULL)
   1517 		idmapdlog(LOG_DEBUG, "unable to discover Forest Name");
   1518 	if (pgcfg->site_name == NULL)
   1519 		idmapdlog(LOG_DEBUG, "unable to discover Site Name");
   1520 	if (pgcfg->global_catalog == NULL)
   1521 		idmapdlog(LOG_DEBUG, "unable to discover Global Catalog");
   1522 	if (pgcfg->domains_in_forest == NULL)
   1523 		idmapdlog(LOG_DEBUG,
   1524 		    "unable to discover Domains in the Forest");
   1525 	if (pgcfg->trusted_domains == NULL)
   1526 		idmapdlog(LOG_DEBUG, "unable to discover Trusted Domains");
   1527 }
   1528 
   1529 
   1530 /*
   1531  * idmap_cfg_load() is called at startup, and periodically via the
   1532  * update thread when the auto-discovery TTLs expire, as well as part of
   1533  * the refresh method, to update the current configuration.  It always
   1534  * reads from SMF, but you still have to refresh the service after
   1535  * changing the config pg in order for the changes to take effect.
   1536  *
   1537  * There are two flags:
   1538  *
   1539  *  - CFG_DISCOVER
   1540  *  - CFG_LOG
   1541  *
   1542  * If CFG_DISCOVER is set then idmap_cfg_load() calls
   1543  * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
   1544  * values that weren't set in SMF.
   1545  *
   1546  * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE)
   1547  * whether the configuration changed.  This should be used only from the
   1548  * refresh method.
   1549  *
   1550  * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
   1551  * reading from SMF.
   1552  */
   1553 int
   1554 idmap_cfg_load(idmap_cfg_t *cfg, int flags)
   1555 {
   1556 	int rc = 0;
   1557 	int errors;
   1558 	int changed = 0;
   1559 	int ad_reload_required = 0;
   1560 	idmap_pg_config_t new_pgcfg, *live_pgcfg;
   1561 
   1562 	live_pgcfg = &cfg->pgcfg;
   1563 	(void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
   1564 
   1565 	pthread_mutex_lock(&cfg->handles.mutex);
   1566 
   1567 	if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
   1568 		goto err;
   1569 
   1570 	if (flags & CFG_DISCOVER)
   1571 		idmap_cfg_discover(&cfg->handles, &new_pgcfg);
   1572 
   1573 	WRLOCK_CONFIG();
   1574 	if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) {
   1575 		idmapdlog(LOG_INFO, "change list_size=%d",
   1576 		    new_pgcfg.list_size_limit);
   1577 		live_pgcfg->list_size_limit = new_pgcfg.list_size_limit;
   1578 	}
   1579 
   1580 	/* Non-discoverable props updated here */
   1581 	changed += update_string(&live_pgcfg->machine_sid,
   1582 	    &new_pgcfg.machine_sid, "machine_sid");
   1583 
   1584 	changed += update_bool(&live_pgcfg->eph_map_unres_sids,
   1585 	    &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
   1586 
   1587 	changed += update_enum(&live_pgcfg->directory_based_mapping,
   1588 	    &new_pgcfg.directory_based_mapping, "directory_based_mapping",
   1589 	    directory_mapping_map);
   1590 
   1591 	changed += update_string(&live_pgcfg->ad_unixuser_attr,
   1592 	    &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
   1593 
   1594 	changed += update_string(&live_pgcfg->ad_unixgroup_attr,
   1595 	    &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
   1596 
   1597 	changed += update_string(&live_pgcfg->nldap_winname_attr,
   1598 	    &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
   1599 
   1600 	/* Props that can be discovered and set in SMF updated here */
   1601 	changed += update_string(&live_pgcfg->default_domain,
   1602 	    &new_pgcfg.default_domain, "default_domain");
   1603 
   1604 	changed += update_string(&live_pgcfg->domain_name,
   1605 	    &new_pgcfg.domain_name, "domain_name");
   1606 	live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc;
   1607 
   1608 	changed += update_dirs(&live_pgcfg->domain_controller,
   1609 	    &new_pgcfg.domain_controller, "domain_controller");
   1610 	live_pgcfg->domain_controller_auto_disc =
   1611 	    new_pgcfg.domain_controller_auto_disc;
   1612 
   1613 	changed += update_string(&live_pgcfg->forest_name,
   1614 	    &new_pgcfg.forest_name, "forest_name");
   1615 	live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc;
   1616 
   1617 	changed += update_string(&live_pgcfg->site_name,
   1618 	    &new_pgcfg.site_name, "site_name");
   1619 	live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc;
   1620 
   1621 	if (update_dirs(&live_pgcfg->global_catalog,
   1622 	    &new_pgcfg.global_catalog, "global_catalog")) {
   1623 		changed++;
   1624 		if (live_pgcfg->global_catalog != NULL &&
   1625 		    live_pgcfg->global_catalog[0].host[0] != '\0')
   1626 			ad_reload_required = TRUE;
   1627 	}
   1628 	live_pgcfg->global_catalog_auto_disc =
   1629 	    new_pgcfg.global_catalog_auto_disc;
   1630 
   1631 	if (update_domains_in_forest(&live_pgcfg->domains_in_forest,
   1632 	    &new_pgcfg.domains_in_forest, "domains_in_forest")) {
   1633 		changed++;
   1634 		ad_reload_required = TRUE;
   1635 	}
   1636 
   1637 	if (update_trusted_domains(&live_pgcfg->trusted_domains,
   1638 	    &new_pgcfg.trusted_domains, "trusted_domains")) {
   1639 		changed++;
   1640 		if (live_pgcfg->trusted_domains != NULL &&
   1641 		    live_pgcfg->trusted_domains[0].domain[0] != '\0')
   1642 			ad_reload_required = TRUE;
   1643 	}
   1644 
   1645 	if (update_trusted_forest(&live_pgcfg->trusted_forests,
   1646 	    &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests,
   1647 	    &new_pgcfg.num_trusted_forests, "trusted_forest")) {
   1648 		changed++;
   1649 		if (live_pgcfg->trusted_forests != NULL)
   1650 			ad_reload_required = TRUE;
   1651 	}
   1652 
   1653 	if (ad_reload_required)
   1654 		reload_ad();
   1655 
   1656 	idmap_cfg_unload(&new_pgcfg);
   1657 
   1658 	if (flags & CFG_LOG) {
   1659 		/*
   1660 		 * If the config changes as a result of a refresh of the
   1661 		 * service, then logging about it can provide useful
   1662 		 * feedback to the sysadmin.
   1663 		 */
   1664 		idmapdlog(LOG_NOTICE, "Configuration %schanged",
   1665 		    changed ? "" : "un");
   1666 	}
   1667 
   1668 	UNLOCK_CONFIG();
   1669 
   1670 err:
   1671 	pthread_mutex_unlock(&cfg->handles.mutex);
   1672 
   1673 	if (rc < -1)
   1674 		return (rc);
   1675 
   1676 	return ((errors == 0) ? 0 : -1);
   1677 }
   1678 
   1679 /*
   1680  * Initialize 'cfg'.
   1681  */
   1682 idmap_cfg_t *
   1683 idmap_cfg_init()
   1684 {
   1685 	idmap_cfg_handles_t *handles;
   1686 
   1687 	/* First the smf repository handles: */
   1688 	idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
   1689 	if (!cfg) {
   1690 		idmapdlog(LOG_ERR, "Out of memory");
   1691 		return (NULL);
   1692 	}
   1693 	handles = &cfg->handles;
   1694 
   1695 	(void) pthread_mutex_init(&handles->mutex, NULL);
   1696 
   1697 	if (!(handles->main = scf_handle_create(SCF_VERSION))) {
   1698 		idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
   1699 		    scf_strerror(scf_error()));
   1700 		goto error;
   1701 	}
   1702 
   1703 	if (scf_handle_bind(handles->main) < 0) {
   1704 		idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
   1705 		    scf_strerror(scf_error()));
   1706 		goto error;
   1707 	}
   1708 
   1709 	if (!(handles->service = scf_service_create(handles->main)) ||
   1710 	    !(handles->instance = scf_instance_create(handles->main)) ||
   1711 	    !(handles->config_pg = scf_pg_create(handles->main)) ||
   1712 	    !(handles->general_pg = scf_pg_create(handles->main))) {
   1713 		idmapdlog(LOG_ERR, "scf handle creation failed: %s",
   1714 		    scf_strerror(scf_error()));
   1715 		goto error;
   1716 	}
   1717 
   1718 	if (scf_handle_decode_fmri(handles->main,
   1719 	    FMRI_BASE "/:properties/" CONFIG_PG,
   1720 	    NULL,				/* scope */
   1721 	    handles->service,		/* service */
   1722 	    handles->instance,		/* instance */
   1723 	    handles->config_pg,		/* pg */
   1724 	    NULL,				/* prop */
   1725 	    SCF_DECODE_FMRI_EXACT) < 0) {
   1726 		idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
   1727 		    scf_strerror(scf_error()));
   1728 		goto error;
   1729 	}
   1730 
   1731 	if (scf_service_get_pg(handles->service,
   1732 	    GENERAL_PG, handles->general_pg) < 0) {
   1733 		idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s",
   1734 		    scf_strerror(scf_error()));
   1735 		goto error;
   1736 	}
   1737 
   1738 	if (check_smf_debug_mode(handles) != 0)
   1739 		goto error;
   1740 
   1741 	/* Initialize AD Auto Discovery context */
   1742 	handles->ad_ctx = ad_disc_init();
   1743 	if (handles->ad_ctx == NULL)
   1744 		goto error;
   1745 
   1746 	return (cfg);
   1747 
   1748 error:
   1749 	(void) idmap_cfg_fini(cfg);
   1750 	return (NULL);
   1751 }
   1752 
   1753 void
   1754 idmap_cfg_unload(idmap_pg_config_t *pgcfg)
   1755 {
   1756 
   1757 	if (pgcfg->default_domain) {
   1758 		free(pgcfg->default_domain);
   1759 		pgcfg->default_domain = NULL;
   1760 	}
   1761 	if (pgcfg->domain_name) {
   1762 		free(pgcfg->domain_name);
   1763 		pgcfg->domain_name = NULL;
   1764 	}
   1765 	if (pgcfg->machine_sid) {
   1766 		free(pgcfg->machine_sid);
   1767 		pgcfg->machine_sid = NULL;
   1768 	}
   1769 	if (pgcfg->domain_controller) {
   1770 		free(pgcfg->domain_controller);
   1771 		pgcfg->domain_controller = NULL;
   1772 	}
   1773 	if (pgcfg->forest_name) {
   1774 		free(pgcfg->forest_name);
   1775 		pgcfg->forest_name = NULL;
   1776 	}
   1777 	if (pgcfg->site_name) {
   1778 		free(pgcfg->site_name);
   1779 		pgcfg->site_name = NULL;
   1780 	}
   1781 	if (pgcfg->global_catalog) {
   1782 		free(pgcfg->global_catalog);
   1783 		pgcfg->global_catalog = NULL;
   1784 	}
   1785 	if (pgcfg->trusted_domains) {
   1786 		free(pgcfg->trusted_domains);
   1787 		pgcfg->trusted_domains = NULL;
   1788 	}
   1789 	if (pgcfg->trusted_forests)
   1790 		free_trusted_forests(&pgcfg->trusted_forests,
   1791 		    &pgcfg->num_trusted_forests);
   1792 
   1793 	if (pgcfg->ad_unixuser_attr) {
   1794 		free(pgcfg->ad_unixuser_attr);
   1795 		pgcfg->ad_unixuser_attr = NULL;
   1796 	}
   1797 	if (pgcfg->ad_unixgroup_attr) {
   1798 		free(pgcfg->ad_unixgroup_attr);
   1799 		pgcfg->ad_unixgroup_attr = NULL;
   1800 	}
   1801 	if (pgcfg->nldap_winname_attr) {
   1802 		free(pgcfg->nldap_winname_attr);
   1803 		pgcfg->nldap_winname_attr = NULL;
   1804 	}
   1805 }
   1806 
   1807 int
   1808 idmap_cfg_fini(idmap_cfg_t *cfg)
   1809 {
   1810 	idmap_cfg_handles_t *handles = &cfg->handles;
   1811 	idmap_cfg_unload(&cfg->pgcfg);
   1812 
   1813 	(void) pthread_mutex_destroy(&handles->mutex);
   1814 	scf_pg_destroy(handles->config_pg);
   1815 	scf_pg_destroy(handles->general_pg);
   1816 	scf_instance_destroy(handles->instance);
   1817 	scf_service_destroy(handles->service);
   1818 	scf_handle_destroy(handles->main);
   1819 	if (handles->ad_ctx != NULL)
   1820 		ad_disc_fini(handles->ad_ctx);
   1821 	free(cfg);
   1822 
   1823 	return (0);
   1824 }
   1825 
   1826 void
   1827 idmap_cfg_poke_updates(void)
   1828 {
   1829 	if (idmapd_ev_port != -1)
   1830 		(void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
   1831 }
   1832 
   1833 /*ARGSUSED*/
   1834 void
   1835 idmap_cfg_hup_handler(int sig)
   1836 {
   1837 	if (idmapd_ev_port >= 0)
   1838 		(void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
   1839 }
   1840 
   1841 /*
   1842  * Upgrade the DS mapping flags.
   1843  *
   1844  * If the old ds_name_mapping_enabled flag is present, then
   1845  *     if the new directory_based_mapping value is present, then
   1846  *         if the two are compatible, delete the old and note it
   1847  *         else delete the old and warn
   1848  *     else
   1849  *         set the new based on the old, and note it
   1850  *         delete the old
   1851  */
   1852 static
   1853 int
   1854 upgrade_directory_mapping(idmap_cfg_handles_t *handles)
   1855 {
   1856 	boolean_t legacy_ds_name_mapping_present;
   1857 	const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
   1858 	const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
   1859 	int rc;
   1860 
   1861 	rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
   1862 	    &legacy_ds_name_mapping_present);
   1863 
   1864 	if (rc != 0)
   1865 		return (rc);
   1866 
   1867 	if (!legacy_ds_name_mapping_present)
   1868 		return (0);
   1869 
   1870 	boolean_t legacy_ds_name_mapping_enabled;
   1871 	rc = get_val_int(handles, DS_NAME_MAPPING_ENABLED,
   1872 	    &legacy_ds_name_mapping_enabled, SCF_TYPE_BOOLEAN);
   1873 	if (rc != 0)
   1874 		return (rc);
   1875 
   1876 	char *legacy_mode;
   1877 	char *legacy_bool_string;
   1878 	if (legacy_ds_name_mapping_enabled) {
   1879 		legacy_mode = "name";
   1880 		legacy_bool_string = "true";
   1881 	} else {
   1882 		legacy_mode = "none";
   1883 		legacy_bool_string = "false";
   1884 	}
   1885 
   1886 	char *directory_based_mapping;
   1887 	rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
   1888 	    &directory_based_mapping);
   1889 	if (rc != 0)
   1890 		return (rc);
   1891 
   1892 	if (directory_based_mapping == NULL) {
   1893 		idmapdlog(LOG_INFO,
   1894 		    "Upgrading old %s=%s setting\n"
   1895 		    "to %s=%s.",
   1896 		    DS_NAME_MAPPING_ENABLED, legacy_bool_string,
   1897 		    DIRECTORY_BASED_MAPPING, legacy_mode);
   1898 		rc = set_val_astring(handles, DIRECTORY_BASED_MAPPING,
   1899 		    legacy_mode);
   1900 		if (rc != 0)
   1901 			return (rc);
   1902 	} else {
   1903 		boolean_t new_name_mapping;
   1904 		if (strcasecmp(directory_based_mapping, "name") == 0)
   1905 			new_name_mapping = B_TRUE;
   1906 		else
   1907 			new_name_mapping = B_FALSE;
   1908 
   1909 		if (legacy_ds_name_mapping_enabled == new_name_mapping) {
   1910 			idmapdlog(LOG_INFO,
   1911 			    "Automatically removing old %s=%s setting\n"
   1912 			    "in favor of %s=%s.",
   1913 			    DS_NAME_MAPPING_ENABLED, legacy_bool_string,
   1914 			    DIRECTORY_BASED_MAPPING, directory_based_mapping);
   1915 		} else {
   1916 			idmapdlog(LOG_WARNING,
   1917 			    "Removing conflicting %s=%s setting\n"
   1918 			    "in favor of %s=%s.",
   1919 			    DS_NAME_MAPPING_ENABLED, legacy_bool_string,
   1920 			    DIRECTORY_BASED_MAPPING, directory_based_mapping);
   1921 		}
   1922 		free(directory_based_mapping);
   1923 	}
   1924 
   1925 	rc = del_val(handles, DS_NAME_MAPPING_ENABLED);
   1926 	if (rc != 0)
   1927 		return (rc);
   1928 
   1929 	return (0);
   1930 }
   1931 
   1932 /*
   1933  * Do whatever is necessary to upgrade idmap's configuration before
   1934  * we load it.
   1935  */
   1936 int
   1937 idmap_cfg_upgrade(idmap_cfg_t *cfg)
   1938 {
   1939 	int rc;
   1940 
   1941 	rc = upgrade_directory_mapping(&cfg->handles);
   1942 	if (rc != 0)
   1943 		return (rc);
   1944 
   1945 	return (0);
   1946 }
   1947