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  * Service routines
     29  */
     30 
     31 #include "idmapd.h"
     32 #include "idmap_priv.h"
     33 #include "nldaputils.h"
     34 #include <signal.h>
     35 #include <thread.h>
     36 #include <string.h>
     37 #include <strings.h>
     38 #include <errno.h>
     39 #include <assert.h>
     40 #include <sys/types.h>
     41 #include <sys/stat.h>
     42 #include <ucred.h>
     43 #include <pwd.h>
     44 #include <auth_attr.h>
     45 #include <secdb.h>
     46 #include <sys/u8_textprep.h>
     47 #include <note.h>
     48 
     49 #define	_VALIDATE_LIST_CB_DATA(col, val, siz)\
     50 	retcode = validate_list_cb_data(cb_data, argc, argv, col,\
     51 			(uchar_t **)val, siz);\
     52 	if (retcode == IDMAP_NEXT) {\
     53 		result->retcode = IDMAP_NEXT;\
     54 		return (0);\
     55 	} else if (retcode < 0) {\
     56 		result->retcode = retcode;\
     57 		return (1);\
     58 	}
     59 
     60 #define	PROCESS_LIST_SVC_SQL(rcode, db, dbname, sql, limit, flag, cb, res, len)\
     61 	rcode = process_list_svc_sql(db, dbname, sql, limit, flag, cb, res);\
     62 	if (rcode == IDMAP_ERR_BUSY)\
     63 		res->retcode = IDMAP_ERR_BUSY;\
     64 	else if (rcode == IDMAP_SUCCESS && len == 0)\
     65 		res->retcode = IDMAP_ERR_NOTFOUND;
     66 
     67 
     68 #define	STRDUP_OR_FAIL(to, from) \
     69 	if ((from) == NULL) \
     70 		to = NULL; \
     71 	else { \
     72 		if ((to = strdup(from)) == NULL) \
     73 			return (1); \
     74 	}
     75 
     76 #define	STRDUP_CHECK(to, from) \
     77 	if ((from) != NULL) { \
     78 		to = strdup(from); \
     79 		if (to == NULL) { \
     80 			result->retcode = IDMAP_ERR_MEMORY; \
     81 			goto out; \
     82 		} \
     83 	}
     84 
     85 /* ARGSUSED */
     86 bool_t
     87 idmap_null_1_svc(void *result, struct svc_req *rqstp)
     88 {
     89 	return (TRUE);
     90 }
     91 
     92 /*
     93  * RPC layer allocates empty strings to replace NULL char *.
     94  * This utility function frees these empty strings.
     95  */
     96 static
     97 void
     98 sanitize_mapping_request(idmap_mapping *req)
     99 {
    100 	if (EMPTY_STRING(req->id1name)) {
    101 		free(req->id1name);
    102 		req->id1name = NULL;
    103 	}
    104 	if (EMPTY_STRING(req->id1domain)) {
    105 		free(req->id1domain);
    106 		req->id1domain = NULL;
    107 	}
    108 	if (EMPTY_STRING(req->id2name)) {
    109 		free(req->id2name);
    110 		req->id2name = NULL;
    111 	}
    112 	if (EMPTY_STRING(req->id2domain)) {
    113 		free(req->id2domain);
    114 		req->id2domain = NULL;
    115 	}
    116 	req->direction = _IDMAP_F_DONE;
    117 }
    118 
    119 static
    120 int
    121 validate_mapped_id_by_name_req(idmap_mapping *req)
    122 {
    123 	int e;
    124 
    125 	if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req))
    126 		return (IDMAP_SUCCESS);
    127 
    128 	if (IS_REQUEST_SID(*req, 1)) {
    129 		if (!EMPTY_STRING(req->id1name) &&
    130 		    u8_validate(req->id1name, strlen(req->id1name),
    131 		    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
    132 			return (IDMAP_ERR_BAD_UTF8);
    133 		if (!EMPTY_STRING(req->id1domain) &&
    134 		    u8_validate(req->id1domain, strlen(req->id1domain),
    135 		    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
    136 			return (IDMAP_ERR_BAD_UTF8);
    137 	}
    138 
    139 	return (IDMAP_SUCCESS);
    140 }
    141 
    142 static
    143 int
    144 validate_rule(idmap_namerule *rule)
    145 {
    146 	int e;
    147 
    148 	if (!EMPTY_STRING(rule->winname) &&
    149 	    u8_validate(rule->winname, strlen(rule->winname),
    150 	    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
    151 		return (IDMAP_ERR_BAD_UTF8);
    152 
    153 	if (!EMPTY_STRING(rule->windomain) &&
    154 	    u8_validate(rule->windomain, strlen(rule->windomain),
    155 	    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
    156 		return (IDMAP_ERR_BAD_UTF8);
    157 
    158 	return (IDMAP_SUCCESS);
    159 
    160 }
    161 
    162 static
    163 bool_t
    164 validate_rules(idmap_update_batch *batch)
    165 {
    166 	idmap_update_op	*up;
    167 	int i;
    168 
    169 	for (i = 0; i < batch->idmap_update_batch_len; i++) {
    170 		up = &(batch->idmap_update_batch_val[i]);
    171 		if (validate_rule(&(up->idmap_update_op_u.rule))
    172 		    != IDMAP_SUCCESS)
    173 			return (IDMAP_ERR_BAD_UTF8);
    174 	}
    175 
    176 	return (IDMAP_SUCCESS);
    177 }
    178 
    179 /* ARGSUSED */
    180 bool_t
    181 idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch,
    182 		idmap_ids_res *result, struct svc_req *rqstp)
    183 {
    184 	sqlite		*cache = NULL, *db = NULL;
    185 	lookup_state_t	state;
    186 	idmap_retcode	retcode;
    187 	uint_t		i;
    188 
    189 	/* Init */
    190 	(void) memset(result, 0, sizeof (*result));
    191 	(void) memset(&state, 0, sizeof (state));
    192 
    193 	/* Return success if nothing was requested */
    194 	if (batch.idmap_mapping_batch_len < 1)
    195 		goto out;
    196 
    197 	/* Get cache handle */
    198 	result->retcode = get_cache_handle(&cache);
    199 	if (result->retcode != IDMAP_SUCCESS)
    200 		goto out;
    201 	state.cache = cache;
    202 
    203 	/* Get db handle */
    204 	result->retcode = get_db_handle(&db);
    205 	if (result->retcode != IDMAP_SUCCESS)
    206 		goto out;
    207 	state.db = db;
    208 
    209 	/* Allocate result array */
    210 	result->ids.ids_val = calloc(batch.idmap_mapping_batch_len,
    211 	    sizeof (idmap_id_res));
    212 	if (result->ids.ids_val == NULL) {
    213 		idmapdlog(LOG_ERR, "Out of memory");
    214 		result->retcode = IDMAP_ERR_MEMORY;
    215 		goto out;
    216 	}
    217 	result->ids.ids_len = batch.idmap_mapping_batch_len;
    218 
    219 	/* Allocate hash table to check for duplicate sids */
    220 	state.sid_history = calloc(batch.idmap_mapping_batch_len,
    221 	    sizeof (*state.sid_history));
    222 	if (state.sid_history == NULL) {
    223 		idmapdlog(LOG_ERR, "Out of memory");
    224 		result->retcode = IDMAP_ERR_MEMORY;
    225 		goto out;
    226 	}
    227 	state.sid_history_size = batch.idmap_mapping_batch_len;
    228 	for (i = 0; i < state.sid_history_size; i++) {
    229 		state.sid_history[i].key = state.sid_history_size;
    230 		state.sid_history[i].next = state.sid_history_size;
    231 	}
    232 	state.batch = &batch;
    233 	state.result = result;
    234 
    235 	/* Get directory-based name mapping info */
    236 	result->retcode = load_cfg_in_state(&state);
    237 	if (result->retcode != IDMAP_SUCCESS)
    238 		goto out;
    239 
    240 	/* Init our 'done' flags */
    241 	state.sid2pid_done = state.pid2sid_done = TRUE;
    242 
    243 	/* First stage */
    244 	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
    245 		state.curpos = i;
    246 		(void) sanitize_mapping_request(
    247 		    &batch.idmap_mapping_batch_val[i]);
    248 		if (IS_BATCH_SID(batch, i)) {
    249 			retcode = sid2pid_first_pass(
    250 			    &state,
    251 			    &batch.idmap_mapping_batch_val[i],
    252 			    &result->ids.ids_val[i]);
    253 		} else if (IS_BATCH_UID(batch, i)) {
    254 			retcode = pid2sid_first_pass(
    255 			    &state,
    256 			    &batch.idmap_mapping_batch_val[i],
    257 			    &result->ids.ids_val[i], 1);
    258 		} else if (IS_BATCH_GID(batch, i)) {
    259 			retcode = pid2sid_first_pass(
    260 			    &state,
    261 			    &batch.idmap_mapping_batch_val[i],
    262 			    &result->ids.ids_val[i], 0);
    263 		} else {
    264 			result->ids.ids_val[i].retcode = IDMAP_ERR_IDTYPE;
    265 			continue;
    266 		}
    267 		if (IDMAP_FATAL_ERROR(retcode)) {
    268 			result->retcode = retcode;
    269 			goto out;
    270 		}
    271 	}
    272 
    273 	/* Check if we are done */
    274 	if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
    275 		goto out;
    276 
    277 	/*
    278 	 * native LDAP lookups:
    279 	 *  pid2sid:
    280 	 *	- nldap or mixed mode. Lookup nldap by pid or unixname to get
    281 	 *	  winname.
    282 	 *  sid2pid:
    283 	 *	- nldap mode. Got winname and sid (either given or found in
    284 	 *	  name_cache). Lookup nldap by winname to get pid and
    285 	 *	  unixname.
    286 	 */
    287 	if (state.nldap_nqueries) {
    288 		retcode = nldap_lookup_batch(&state, &batch, result);
    289 		if (IDMAP_FATAL_ERROR(retcode)) {
    290 			result->retcode = retcode;
    291 			goto out;
    292 		}
    293 	}
    294 
    295 	/*
    296 	 * AD lookups:
    297 	 *  pid2sid:
    298 	 *	- nldap or mixed mode. Got winname from nldap lookup.
    299 	 *	  winname2sid could not be resolved locally. Lookup AD
    300 	 *	  by winname to get sid.
    301 	 *	- ad mode. Got unixname. Lookup AD by unixname to get
    302 	 *	  winname and sid.
    303 	 *  sid2pid:
    304 	 *	- ad or mixed mode. Lookup AD by sid or winname to get
    305 	 *	  winname, sid and unixname.
    306 	 *	- any mode. Got either sid or winname but not both. Lookup
    307 	 *	  AD by sid or winname to get winname, sid.
    308 	 */
    309 	if (state.ad_nqueries) {
    310 		retcode = ad_lookup_batch(&state, &batch, result);
    311 		if (IDMAP_FATAL_ERROR(retcode)) {
    312 			result->retcode = retcode;
    313 			goto out;
    314 		}
    315 	}
    316 
    317 	/*
    318 	 * native LDAP lookups:
    319 	 *  sid2pid:
    320 	 *	- nldap mode. Got winname and sid from AD lookup. Lookup nldap
    321 	 *	  by winname to get pid and unixname.
    322 	 */
    323 	if (state.nldap_nqueries) {
    324 		retcode = nldap_lookup_batch(&state, &batch, result);
    325 		if (IDMAP_FATAL_ERROR(retcode)) {
    326 			result->retcode = retcode;
    327 			goto out;
    328 		}
    329 	}
    330 
    331 	/* Reset 'done' flags */
    332 	state.sid2pid_done = state.pid2sid_done = TRUE;
    333 
    334 	/* Second stage */
    335 	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
    336 		state.curpos = i;
    337 		if (IS_BATCH_SID(batch, i)) {
    338 			retcode = sid2pid_second_pass(
    339 			    &state,
    340 			    &batch.idmap_mapping_batch_val[i],
    341 			    &result->ids.ids_val[i]);
    342 		} else if (IS_BATCH_UID(batch, i)) {
    343 			retcode = pid2sid_second_pass(
    344 			    &state,
    345 			    &batch.idmap_mapping_batch_val[i],
    346 			    &result->ids.ids_val[i], 1);
    347 		} else if (IS_BATCH_GID(batch, i)) {
    348 			retcode = pid2sid_second_pass(
    349 			    &state,
    350 			    &batch.idmap_mapping_batch_val[i],
    351 			    &result->ids.ids_val[i], 0);
    352 		} else {
    353 			/* First stage has already set the error */
    354 			continue;
    355 		}
    356 		if (IDMAP_FATAL_ERROR(retcode)) {
    357 			result->retcode = retcode;
    358 			goto out;
    359 		}
    360 	}
    361 
    362 	/* Check if we are done */
    363 	if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
    364 		goto out;
    365 
    366 	/* Reset our 'done' flags */
    367 	state.sid2pid_done = state.pid2sid_done = TRUE;
    368 
    369 	/* Update cache in a single transaction */
    370 	if (sql_exec_no_cb(cache, IDMAP_CACHENAME, "BEGIN TRANSACTION;")
    371 	    != IDMAP_SUCCESS)
    372 		goto out;
    373 
    374 	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
    375 		state.curpos = i;
    376 		if (IS_BATCH_SID(batch, i)) {
    377 			(void) update_cache_sid2pid(
    378 			    &state,
    379 			    &batch.idmap_mapping_batch_val[i],
    380 			    &result->ids.ids_val[i]);
    381 		} else if ((IS_BATCH_UID(batch, i)) ||
    382 		    (IS_BATCH_GID(batch, i))) {
    383 			(void) update_cache_pid2sid(
    384 			    &state,
    385 			    &batch.idmap_mapping_batch_val[i],
    386 			    &result->ids.ids_val[i]);
    387 		}
    388 	}
    389 
    390 	/* Commit if we have at least one successful update */
    391 	if (state.sid2pid_done == FALSE || state.pid2sid_done == FALSE)
    392 		(void) sql_exec_no_cb(cache, IDMAP_CACHENAME,
    393 		    "COMMIT TRANSACTION;");
    394 	else
    395 		(void) sql_exec_no_cb(cache, IDMAP_CACHENAME,
    396 		    "END TRANSACTION;");
    397 
    398 out:
    399 	cleanup_lookup_state(&state);
    400 	if (IDMAP_ERROR(result->retcode)) {
    401 		xdr_free(xdr_idmap_ids_res, (caddr_t)result);
    402 		result->ids.ids_len = 0;
    403 		result->ids.ids_val = NULL;
    404 	}
    405 	result->retcode = idmap_stat4prot(result->retcode);
    406 	return (TRUE);
    407 }
    408 
    409 
    410 /* ARGSUSED */
    411 static
    412 int
    413 list_mappings_cb(void *parg, int argc, char **argv, char **colnames)
    414 {
    415 	list_cb_data_t		*cb_data;
    416 	char			*str;
    417 	idmap_mappings_res	*result;
    418 	idmap_retcode		retcode;
    419 	int			w2u, u2w;
    420 	char			*end;
    421 	static int		validated_column_names = 0;
    422 	idmap_how		*how;
    423 
    424 	cb_data = (list_cb_data_t *)parg;
    425 
    426 	if (!validated_column_names) {
    427 		assert(strcmp(colnames[0], "rowid") == 0);
    428 		assert(strcmp(colnames[1], "sidprefix") == 0);
    429 		assert(strcmp(colnames[2], "rid") == 0);
    430 		assert(strcmp(colnames[3], "pid") == 0);
    431 		assert(strcmp(colnames[4], "w2u") == 0);
    432 		assert(strcmp(colnames[5], "u2w") == 0);
    433 		assert(strcmp(colnames[6], "windomain") == 0);
    434 		assert(strcmp(colnames[7], "canon_winname") == 0);
    435 		assert(strcmp(colnames[8], "unixname") == 0);
    436 		assert(strcmp(colnames[9], "is_user") == 0);
    437 		assert(strcmp(colnames[10], "is_wuser") == 0);
    438 		assert(strcmp(colnames[11], "map_type") == 0);
    439 		assert(strcmp(colnames[12], "map_dn") == 0);
    440 		assert(strcmp(colnames[13], "map_attr") == 0);
    441 		assert(strcmp(colnames[14], "map_value") == 0);
    442 		assert(strcmp(colnames[15], "map_windomain") == 0);
    443 		assert(strcmp(colnames[16], "map_winname") == 0);
    444 		assert(strcmp(colnames[17], "map_unixname") == 0);
    445 		assert(strcmp(colnames[18], "map_is_nt4") == 0);
    446 		validated_column_names = 1;
    447 	}
    448 
    449 	result = (idmap_mappings_res *)cb_data->result;
    450 
    451 	_VALIDATE_LIST_CB_DATA(19, &result->mappings.mappings_val,
    452 	    sizeof (idmap_mapping));
    453 
    454 	result->mappings.mappings_len++;
    455 
    456 	if ((str = strdup(argv[1])) == NULL)
    457 		return (1);
    458 	result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.prefix =
    459 	    str;
    460 	result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.rid =
    461 	    strtoul(argv[2], &end, 10);
    462 	result->mappings.mappings_val[cb_data->next].id1.idtype =
    463 	    strtol(argv[10], &end, 10) ? IDMAP_USID : IDMAP_GSID;
    464 
    465 	result->mappings.mappings_val[cb_data->next].id2.idmap_id_u.uid =
    466 	    strtoul(argv[3], &end, 10);
    467 	result->mappings.mappings_val[cb_data->next].id2.idtype =
    468 	    strtol(argv[9], &end, 10) ? IDMAP_UID : IDMAP_GID;
    469 
    470 	w2u = argv[4] ? strtol(argv[4], &end, 10) : 0;
    471 	u2w = argv[5] ? strtol(argv[5], &end, 10) : 0;
    472 
    473 	if (w2u > 0 && u2w == 0)
    474 		result->mappings.mappings_val[cb_data->next].direction =
    475 		    IDMAP_DIRECTION_W2U;
    476 	else if (w2u == 0 && u2w > 0)
    477 		result->mappings.mappings_val[cb_data->next].direction =
    478 		    IDMAP_DIRECTION_U2W;
    479 	else
    480 		result->mappings.mappings_val[cb_data->next].direction =
    481 		    IDMAP_DIRECTION_BI;
    482 
    483 	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id1domain,
    484 	    argv[6]);
    485 
    486 	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id1name,
    487 	    argv[7]);
    488 
    489 	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id2name,
    490 	    argv[8]);
    491 
    492 	if (cb_data->flag & IDMAP_REQ_FLG_MAPPING_INFO) {
    493 		how = &result->mappings.mappings_val[cb_data->next].info.how;
    494 		how->map_type = strtoul(argv[11], &end, 10);
    495 		switch (how->map_type) {
    496 		case IDMAP_MAP_TYPE_DS_AD:
    497 			how->idmap_how_u.ad.dn =
    498 			    strdup(argv[12]);
    499 			how->idmap_how_u.ad.attr =
    500 			    strdup(argv[13]);
    501 			how->idmap_how_u.ad.value =
    502 			    strdup(argv[14]);
    503 			break;
    504 
    505 		case IDMAP_MAP_TYPE_DS_NLDAP:
    506 			how->idmap_how_u.nldap.dn =
    507 			    strdup(argv[12]);
    508 			how->idmap_how_u.nldap.attr =
    509 			    strdup(argv[13]);
    510 			how->idmap_how_u.nldap.value =
    511 			    strdup(argv[14]);
    512 			break;
    513 
    514 		case IDMAP_MAP_TYPE_RULE_BASED:
    515 			how->idmap_how_u.rule.windomain =
    516 			    strdup(argv[15]);
    517 			how->idmap_how_u.rule.winname =
    518 			    strdup(argv[16]);
    519 			how->idmap_how_u.rule.unixname =
    520 			    strdup(argv[17]);
    521 			how->idmap_how_u.rule.is_nt4 =
    522 			    strtoul(argv[18], &end, 10);
    523 			how->idmap_how_u.rule.is_user =
    524 			    strtol(argv[9], &end, 10);
    525 			how->idmap_how_u.rule.is_wuser =
    526 			    strtol(argv[10], &end, 10);
    527 			break;
    528 
    529 		case IDMAP_MAP_TYPE_EPHEMERAL:
    530 			break;
    531 
    532 		case IDMAP_MAP_TYPE_LOCAL_SID:
    533 			break;
    534 
    535 		case IDMAP_MAP_TYPE_IDMU:
    536 			how->idmap_how_u.idmu.dn =
    537 			    strdup(argv[12]);
    538 			how->idmap_how_u.idmu.attr =
    539 			    strdup(argv[13]);
    540 			how->idmap_how_u.idmu.value =
    541 			    strdup(argv[14]);
    542 			break;
    543 
    544 		default:
    545 			/* Unknown mapping type */
    546 			assert(FALSE);
    547 		}
    548 
    549 	}
    550 
    551 	result->lastrowid = strtoll(argv[0], &end, 10);
    552 	cb_data->next++;
    553 	result->retcode = IDMAP_SUCCESS;
    554 	return (0);
    555 }
    556 
    557 
    558 /* ARGSUSED */
    559 bool_t
    560 idmap_list_mappings_1_svc(int64_t lastrowid, uint64_t limit, int32_t flag,
    561     idmap_mappings_res *result, struct svc_req *rqstp)
    562 {
    563 	sqlite		*cache = NULL;
    564 	char		lbuf[30], rbuf[30];
    565 	uint64_t	maxlimit;
    566 	idmap_retcode	retcode;
    567 	char		*sql = NULL;
    568 	time_t		curtime;
    569 
    570 	(void) memset(result, 0, sizeof (*result));
    571 
    572 	/* Current time */
    573 	errno = 0;
    574 	if ((curtime = time(NULL)) == (time_t)-1) {
    575 		idmapdlog(LOG_ERR, "Failed to get current time (%s)",
    576 		    strerror(errno));
    577 		retcode = IDMAP_ERR_INTERNAL;
    578 		goto out;
    579 	}
    580 
    581 	RDLOCK_CONFIG();
    582 	maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
    583 	UNLOCK_CONFIG();
    584 
    585 	/* Get cache handle */
    586 	result->retcode = get_cache_handle(&cache);
    587 	if (result->retcode != IDMAP_SUCCESS)
    588 		goto out;
    589 
    590 	result->retcode = IDMAP_ERR_INTERNAL;
    591 
    592 	/* Create LIMIT expression. */
    593 	if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
    594 		limit = maxlimit;
    595 	if (limit > 0)
    596 		(void) snprintf(lbuf, sizeof (lbuf),
    597 		    "LIMIT %" PRIu64, limit + 1ULL);
    598 	else
    599 		lbuf[0] = '\0';
    600 
    601 	(void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
    602 
    603 	/*
    604 	 * Combine all the above into a giant SELECT statement that
    605 	 * will return the requested mappings
    606 	 */
    607 
    608 	sql = sqlite_mprintf("SELECT rowid, sidprefix, rid, pid, w2u, "
    609 	    "u2w, windomain, canon_winname, unixname, is_user, is_wuser, "
    610 	    "map_type, map_dn, map_attr, map_value, map_windomain, "
    611 	    "map_winname, map_unixname, map_is_nt4 "
    612 	    "FROM idmap_cache WHERE %s AND "
    613 	    "(pid >= 2147483648 OR (expiration = 0 OR "
    614 	    "expiration ISNULL  OR expiration > %d)) "
    615 	    "%s;",
    616 	    rbuf, curtime, lbuf);
    617 	if (sql == NULL) {
    618 		result->retcode = IDMAP_ERR_MEMORY;
    619 		idmapdlog(LOG_ERR, "Out of memory");
    620 		goto out;
    621 	}
    622 
    623 	/* Execute the SQL statement and update the return buffer */
    624 	PROCESS_LIST_SVC_SQL(retcode, cache, IDMAP_CACHENAME, sql, limit,
    625 	    flag, list_mappings_cb, result, result->mappings.mappings_len);
    626 
    627 out:
    628 	if (sql)
    629 		sqlite_freemem(sql);
    630 	if (IDMAP_ERROR(result->retcode))
    631 		(void) xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
    632 	result->retcode = idmap_stat4prot(result->retcode);
    633 	return (TRUE);
    634 }
    635 
    636 
    637 /* ARGSUSED */
    638 static
    639 int
    640 list_namerules_cb(void *parg, int argc, char **argv, char **colnames)
    641 {
    642 	list_cb_data_t		*cb_data;
    643 	idmap_namerules_res	*result;
    644 	idmap_retcode		retcode;
    645 	int			w2u_order, u2w_order;
    646 	char			*end;
    647 	static int		validated_column_names = 0;
    648 
    649 	if (!validated_column_names) {
    650 		assert(strcmp(colnames[0], "rowid") == 0);
    651 		assert(strcmp(colnames[1], "is_user") == 0);
    652 		assert(strcmp(colnames[2], "is_wuser") == 0);
    653 		assert(strcmp(colnames[3], "windomain") == 0);
    654 		assert(strcmp(colnames[4], "winname_display") == 0);
    655 		assert(strcmp(colnames[5], "is_nt4") == 0);
    656 		assert(strcmp(colnames[6], "unixname") == 0);
    657 		assert(strcmp(colnames[7], "w2u_order") == 0);
    658 		assert(strcmp(colnames[8], "u2w_order") == 0);
    659 		validated_column_names = 1;
    660 	}
    661 
    662 	cb_data = (list_cb_data_t *)parg;
    663 	result = (idmap_namerules_res *)cb_data->result;
    664 
    665 	_VALIDATE_LIST_CB_DATA(9, &result->rules.rules_val,
    666 	    sizeof (idmap_namerule));
    667 
    668 	result->rules.rules_len++;
    669 
    670 	result->rules.rules_val[cb_data->next].is_user =
    671 	    strtol(argv[1], &end, 10);
    672 
    673 	result->rules.rules_val[cb_data->next].is_wuser =
    674 	    strtol(argv[2], &end, 10);
    675 
    676 	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].windomain,
    677 	    argv[3]);
    678 
    679 	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].winname,
    680 	    argv[4]);
    681 
    682 	result->rules.rules_val[cb_data->next].is_nt4 =
    683 	    strtol(argv[5], &end, 10);
    684 
    685 	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].unixname,
    686 	    argv[6]);
    687 
    688 	w2u_order = argv[7] ? strtol(argv[7], &end, 10) : 0;
    689 	u2w_order = argv[8] ? strtol(argv[8], &end, 10) : 0;
    690 
    691 	if (w2u_order > 0 && u2w_order == 0)
    692 		result->rules.rules_val[cb_data->next].direction =
    693 		    IDMAP_DIRECTION_W2U;
    694 	else if (w2u_order == 0 && u2w_order > 0)
    695 		result->rules.rules_val[cb_data->next].direction =
    696 		    IDMAP_DIRECTION_U2W;
    697 	else
    698 		result->rules.rules_val[cb_data->next].direction =
    699 		    IDMAP_DIRECTION_BI;
    700 
    701 	result->lastrowid = strtoll(argv[0], &end, 10);
    702 	cb_data->next++;
    703 	result->retcode = IDMAP_SUCCESS;
    704 	return (0);
    705 }
    706 
    707 
    708 /* ARGSUSED */
    709 bool_t
    710 idmap_list_namerules_1_svc(idmap_namerule rule, uint64_t lastrowid,
    711 		uint64_t limit, idmap_namerules_res *result,
    712 		struct svc_req *rqstp)
    713 {
    714 
    715 	sqlite		*db = NULL;
    716 	char		lbuf[30], rbuf[30];
    717 	char		*sql = NULL;
    718 	char		*expr = NULL;
    719 	uint64_t	maxlimit;
    720 	idmap_retcode	retcode;
    721 
    722 	(void) memset(result, 0, sizeof (*result));
    723 
    724 	result->retcode = validate_rule(&rule);
    725 	if (result->retcode != IDMAP_SUCCESS)
    726 		goto out;
    727 
    728 	RDLOCK_CONFIG();
    729 	maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
    730 	UNLOCK_CONFIG();
    731 
    732 	/* Get db handle */
    733 	result->retcode = get_db_handle(&db);
    734 	if (result->retcode != IDMAP_SUCCESS)
    735 		goto out;
    736 
    737 	result->retcode = gen_sql_expr_from_rule(&rule, &expr);
    738 	if (result->retcode != IDMAP_SUCCESS)
    739 		goto out;
    740 
    741 	/* Create LIMIT expression. */
    742 	if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
    743 		limit = maxlimit;
    744 	if (limit > 0)
    745 		(void) snprintf(lbuf, sizeof (lbuf),
    746 		    "LIMIT %" PRIu64, limit + 1ULL);
    747 	else
    748 		lbuf[0] = '\0';
    749 
    750 	(void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
    751 
    752 	/*
    753 	 * Combine all the above into a giant SELECT statement that
    754 	 * will return the requested rules
    755 	 */
    756 	sql = sqlite_mprintf("SELECT rowid, is_user, is_wuser, windomain, "
    757 	    "winname_display, is_nt4, unixname, w2u_order, u2w_order "
    758 	    "FROM namerules WHERE "
    759 	    " %s %s %s;",
    760 	    rbuf, expr, lbuf);
    761 
    762 	if (sql == NULL) {
    763 		result->retcode = IDMAP_ERR_MEMORY;
    764 		idmapdlog(LOG_ERR, "Out of memory");
    765 		goto out;
    766 	}
    767 
    768 	/* Execute the SQL statement and update the return buffer */
    769 	PROCESS_LIST_SVC_SQL(retcode, db, IDMAP_DBNAME, sql, limit,
    770 	    0, list_namerules_cb, result, result->rules.rules_len);
    771 
    772 out:
    773 	if (expr)
    774 		sqlite_freemem(expr);
    775 	if (sql)
    776 		sqlite_freemem(sql);
    777 	if (IDMAP_ERROR(result->retcode))
    778 		(void) xdr_free(xdr_idmap_namerules_res, (caddr_t)result);
    779 	result->retcode = idmap_stat4prot(result->retcode);
    780 	return (TRUE);
    781 }
    782 
    783 #define	IDMAP_RULES_AUTH	"solaris.admin.idmap.rules"
    784 static int
    785 verify_rules_auth(struct svc_req *rqstp)
    786 {
    787 	ucred_t		*uc = NULL;
    788 	uid_t		uid;
    789 	char		buf[1024];
    790 	struct passwd	pwd;
    791 
    792 	if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
    793 		idmapdlog(LOG_ERR, "svc_getcallerucred failed during "
    794 		    "authorization (%s)", strerror(errno));
    795 		return (-1);
    796 	}
    797 
    798 	uid = ucred_geteuid(uc);
    799 	if (uid == (uid_t)-1) {
    800 		idmapdlog(LOG_ERR, "ucred_geteuid failed during "
    801 		    "authorization (%s)", strerror(errno));
    802 		ucred_free(uc);
    803 		return (-1);
    804 	}
    805 
    806 	if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
    807 		idmapdlog(LOG_ERR, "getpwuid_r(%u) failed during "
    808 		    "authorization (%s)", uid, strerror(errno));
    809 		ucred_free(uc);
    810 		return (-1);
    811 	}
    812 
    813 	if (chkauthattr(IDMAP_RULES_AUTH, pwd.pw_name) != 1) {
    814 		idmapdlog(LOG_INFO, "%s is not authorized (%s)",
    815 		    pwd.pw_name, IDMAP_RULES_AUTH);
    816 		ucred_free(uc);
    817 		return (-1);
    818 	}
    819 
    820 	ucred_free(uc);
    821 	return (1);
    822 }
    823 
    824 /*
    825  * Meaning of the return values is the following: For retcode ==
    826  * IDMAP_SUCCESS, everything went OK and error_index is
    827  * undefined. Otherwise, error_index >=0 shows the failed batch
    828  * element. errro_index == -1 indicates failure at the beginning,
    829  * error_index == -2 at the end.
    830  */
    831 
    832 /* ARGSUSED */
    833 bool_t
    834 idmap_update_1_svc(idmap_update_batch batch, idmap_update_res *res,
    835 		struct svc_req *rqstp)
    836 {
    837 	sqlite		*db = NULL;
    838 	idmap_update_op	*up;
    839 	int		i;
    840 	int		trans = FALSE;
    841 
    842 	res->error_index = -1;
    843 	(void) memset(&res->error_rule, 0, sizeof (res->error_rule));
    844 	(void) memset(&res->conflict_rule, 0, sizeof (res->conflict_rule));
    845 
    846 	if (verify_rules_auth(rqstp) < 0) {
    847 		res->retcode = IDMAP_ERR_PERMISSION_DENIED;
    848 		goto out;
    849 	}
    850 
    851 	if (batch.idmap_update_batch_len == 0 ||
    852 	    batch.idmap_update_batch_val == NULL) {
    853 		res->retcode = IDMAP_SUCCESS;
    854 		goto out;
    855 	}
    856 
    857 	res->retcode = validate_rules(&batch);
    858 	if (res->retcode != IDMAP_SUCCESS)
    859 		goto out;
    860 
    861 	/* Get db handle */
    862 	res->retcode = get_db_handle(&db);
    863 	if (res->retcode != IDMAP_SUCCESS)
    864 		goto out;
    865 
    866 	res->retcode = sql_exec_no_cb(db, IDMAP_DBNAME, "BEGIN TRANSACTION;");
    867 	if (res->retcode != IDMAP_SUCCESS)
    868 		goto out;
    869 	trans = TRUE;
    870 
    871 	for (i = 0; i < batch.idmap_update_batch_len; i++) {
    872 		up = &batch.idmap_update_batch_val[i];
    873 		switch (up->opnum) {
    874 		case OP_NONE:
    875 			res->retcode = IDMAP_SUCCESS;
    876 			break;
    877 		case OP_ADD_NAMERULE:
    878 			res->retcode = add_namerule(db,
    879 			    &up->idmap_update_op_u.rule);
    880 			break;
    881 		case OP_RM_NAMERULE:
    882 			res->retcode = rm_namerule(db,
    883 			    &up->idmap_update_op_u.rule);
    884 			break;
    885 		case OP_FLUSH_NAMERULES:
    886 			res->retcode = flush_namerules(db);
    887 			break;
    888 		default:
    889 			res->retcode = IDMAP_ERR_NOTSUPPORTED;
    890 			break;
    891 		};
    892 
    893 		if (res->retcode != IDMAP_SUCCESS) {
    894 			res->error_index = i;
    895 			if (up->opnum == OP_ADD_NAMERULE ||
    896 			    up->opnum == OP_RM_NAMERULE) {
    897 				idmap_stat r2 =
    898 				    idmap_namerule_cpy(&res->error_rule,
    899 				    &up->idmap_update_op_u.rule);
    900 				if (r2 != IDMAP_SUCCESS)
    901 					res->retcode = r2;
    902 			}
    903 			goto out;
    904 		}
    905 	}
    906 
    907 out:
    908 	if (trans) {
    909 		if (res->retcode == IDMAP_SUCCESS) {
    910 			res->retcode =
    911 			    sql_exec_no_cb(db, IDMAP_DBNAME,
    912 			    "COMMIT TRANSACTION;");
    913 			if (res->retcode !=  IDMAP_SUCCESS)
    914 				res->error_index = -2;
    915 		}
    916 		else
    917 			(void) sql_exec_no_cb(db, IDMAP_DBNAME,
    918 			    "ROLLBACK TRANSACTION;");
    919 	}
    920 
    921 	res->retcode = idmap_stat4prot(res->retcode);
    922 
    923 	return (TRUE);
    924 }
    925 
    926 static
    927 int
    928 copy_string(char **to, char *from)
    929 {
    930 	if (EMPTY_STRING(from)) {
    931 		*to = NULL;
    932 	} else {
    933 		*to = strdup(from);
    934 		if (*to == NULL) {
    935 			idmapdlog(LOG_ERR, "Out of memory");
    936 			return (IDMAP_ERR_MEMORY);
    937 		}
    938 	}
    939 	return (IDMAP_SUCCESS);
    940 }
    941 
    942 static
    943 int
    944 copy_id(idmap_id *to, idmap_id *from)
    945 {
    946 	(void) memset(to, 0, sizeof (*to));
    947 
    948 	to->idtype = from->idtype;
    949 	if (IS_ID_SID(*from)) {
    950 		idmap_retcode retcode;
    951 
    952 		to->idmap_id_u.sid.rid = from->idmap_id_u.sid.rid;
    953 		retcode = copy_string(&to->idmap_id_u.sid.prefix,
    954 		    from->idmap_id_u.sid.prefix);
    955 
    956 		return (retcode);
    957 	} else {
    958 		to->idmap_id_u.uid = from->idmap_id_u.uid;
    959 		return (IDMAP_SUCCESS);
    960 	}
    961 }
    962 
    963 static
    964 int
    965 copy_mapping(idmap_mapping *mapping, idmap_mapping *request)
    966 {
    967 	idmap_retcode retcode;
    968 
    969 	(void) memset(mapping, 0, sizeof (*mapping));
    970 
    971 	mapping->flag = request->flag;
    972 	mapping->direction = _IDMAP_F_DONE;
    973 
    974 	retcode = copy_id(&mapping->id1, &request->id1);
    975 	if (retcode != IDMAP_SUCCESS)
    976 		goto errout;
    977 
    978 	retcode = copy_string(&mapping->id1domain, request->id1domain);
    979 	if (retcode != IDMAP_SUCCESS)
    980 		goto errout;
    981 
    982 	retcode = copy_string(&mapping->id1name, request->id1name);
    983 	if (retcode != IDMAP_SUCCESS)
    984 		goto errout;
    985 
    986 	retcode = copy_id(&mapping->id2, &request->id2);
    987 	if (retcode != IDMAP_SUCCESS)
    988 		goto errout;
    989 
    990 	retcode = copy_string(&mapping->id2domain, request->id2domain);
    991 	if (retcode != IDMAP_SUCCESS)
    992 		goto errout;
    993 	retcode = copy_string(&mapping->id2name, request->id2name);
    994 	if (retcode != IDMAP_SUCCESS)
    995 		goto errout;
    996 
    997 	return (IDMAP_SUCCESS);
    998 
    999 errout:
   1000 	if (IS_ID_SID(mapping->id1))
   1001 		free(mapping->id1.idmap_id_u.sid.prefix);
   1002 	free(mapping->id1domain);
   1003 	free(mapping->id1name);
   1004 	if (IS_ID_SID(mapping->id2))
   1005 		free(mapping->id2.idmap_id_u.sid.prefix);
   1006 	free(mapping->id2domain);
   1007 	free(mapping->id2name);
   1008 
   1009 	(void) memset(mapping, 0, sizeof (*mapping));
   1010 	return (retcode);
   1011 }
   1012 
   1013 
   1014 /* ARGSUSED */
   1015 bool_t
   1016 idmap_get_mapped_id_by_name_1_svc(idmap_mapping request,
   1017 		idmap_mappings_res *result, struct svc_req *rqstp)
   1018 {
   1019 	idmap_mapping_batch batch_request;
   1020 	idmap_ids_res batch_result;
   1021 	idmap_mapping *map;
   1022 
   1023 	/* Clear out things we might want to xdr_free on error */
   1024 	(void) memset(&batch_result, 0, sizeof (batch_result));
   1025 	(void) memset(result, 0, sizeof (*result));
   1026 
   1027 	result->retcode = validate_mapped_id_by_name_req(&request);
   1028 	if (result->retcode != IDMAP_SUCCESS)
   1029 		goto out;
   1030 
   1031 	/*
   1032 	 * Copy the request.  We need to modify it, and
   1033 	 * what we have is a shallow copy.  Freeing pointers from
   1034 	 * our copy will lead to problems, since the RPC framework
   1035 	 * has its own copy of those pointers.  Besides, we need
   1036 	 * a copy to return.
   1037 	 */
   1038 	map = calloc(1, sizeof (idmap_mapping));
   1039 	if (map == NULL) {
   1040 		idmapdlog(LOG_ERR, "Out of memory");
   1041 		result->retcode = IDMAP_ERR_MEMORY;
   1042 		goto out;
   1043 	}
   1044 
   1045 	/*
   1046 	 * Set up to return the filled-in mapping structure.
   1047 	 * Note that we xdr_free result on error, and that'll take
   1048 	 * care of freeing the mapping structure.
   1049 	 */
   1050 	result->mappings.mappings_val = map;
   1051 	result->mappings.mappings_len = 1;
   1052 
   1053 	result->retcode = copy_mapping(map, &request);
   1054 	if (result->retcode != IDMAP_SUCCESS)
   1055 		goto out;
   1056 
   1057 	/* Set up for the request to the batch API */
   1058 	batch_request.idmap_mapping_batch_val = map;
   1059 	batch_request.idmap_mapping_batch_len = 1;
   1060 
   1061 	/* Do the real work. */
   1062 	(void) idmap_get_mapped_ids_1_svc(batch_request,
   1063 	    &batch_result, rqstp);
   1064 
   1065 	/* Copy what we need out of the batch response */
   1066 
   1067 	if (batch_result.retcode != IDMAP_SUCCESS) {
   1068 		result->retcode = batch_result.retcode;
   1069 		goto out;
   1070 	}
   1071 
   1072 	result->retcode = copy_id(&map->id2, &batch_result.ids.ids_val[0].id);
   1073 	if (result->retcode != IDMAP_SUCCESS)
   1074 		goto out;
   1075 
   1076 	map->direction = batch_result.ids.ids_val[0].direction;
   1077 
   1078 	result->retcode = batch_result.ids.ids_val[0].retcode;
   1079 
   1080 	if (map->flag & IDMAP_REQ_FLG_MAPPING_INFO ||
   1081 	    result->retcode != IDMAP_SUCCESS) {
   1082 		(void) idmap_info_mov(&map->info,
   1083 		    &batch_result.ids.ids_val[0].info);
   1084 	}
   1085 
   1086 out:
   1087 	if (IDMAP_FATAL_ERROR(result->retcode)) {
   1088 		xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
   1089 		result->mappings.mappings_len = 0;
   1090 		result->mappings.mappings_val = NULL;
   1091 	}
   1092 	result->retcode = idmap_stat4prot(result->retcode);
   1093 
   1094 	xdr_free(xdr_idmap_ids_res, (char *)&batch_result);
   1095 
   1096 	return (TRUE);
   1097 }
   1098 
   1099 /* ARGSUSED */
   1100 bool_t
   1101 idmap_get_prop_1_svc(idmap_prop_type request,
   1102 		idmap_prop_res *result, struct svc_req *rqstp)
   1103 {
   1104 	idmap_pg_config_t *pgcfg;
   1105 
   1106 	/* Init */
   1107 	(void) memset(result, 0, sizeof (*result));
   1108 	result->retcode = IDMAP_SUCCESS;
   1109 	result->value.prop = request;
   1110 
   1111 	RDLOCK_CONFIG();
   1112 
   1113 	/* Just shortcuts: */
   1114 	pgcfg = &_idmapdstate.cfg->pgcfg;
   1115 
   1116 
   1117 	switch (request) {
   1118 	case PROP_LIST_SIZE_LIMIT:
   1119 		result->value.idmap_prop_val_u.intval = pgcfg->list_size_limit;
   1120 		result->auto_discovered = FALSE;
   1121 		break;
   1122 	case PROP_DEFAULT_DOMAIN:
   1123 		result->auto_discovered = FALSE;
   1124 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1125 		    pgcfg->default_domain);
   1126 		break;
   1127 	case PROP_DOMAIN_NAME:
   1128 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1129 		    pgcfg->domain_name);
   1130 		result->auto_discovered =
   1131 		    pgcfg->domain_name_auto_disc;
   1132 		break;
   1133 	case PROP_MACHINE_SID:
   1134 		result->auto_discovered = FALSE;
   1135 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1136 		    pgcfg->machine_sid);
   1137 		break;
   1138 	case PROP_DOMAIN_CONTROLLER:
   1139 		if (pgcfg->domain_controller != NULL) {
   1140 			(void) memcpy(&result->value.idmap_prop_val_u.dsval,
   1141 			    pgcfg->domain_controller,
   1142 			    sizeof (idmap_ad_disc_ds_t));
   1143 		}
   1144 		result->auto_discovered = pgcfg->domain_controller_auto_disc;
   1145 		break;
   1146 	case PROP_FOREST_NAME:
   1147 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1148 		    pgcfg->forest_name);
   1149 		result->auto_discovered = pgcfg->forest_name_auto_disc;
   1150 		break;
   1151 	case PROP_SITE_NAME:
   1152 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1153 		    pgcfg->site_name);
   1154 		result->auto_discovered = pgcfg->site_name_auto_disc;
   1155 		break;
   1156 	case PROP_GLOBAL_CATALOG:
   1157 		if (pgcfg->global_catalog != NULL) {
   1158 			(void) memcpy(&result->value.idmap_prop_val_u.dsval,
   1159 			    pgcfg->global_catalog, sizeof (idmap_ad_disc_ds_t));
   1160 		}
   1161 		result->auto_discovered = pgcfg->global_catalog_auto_disc;
   1162 		break;
   1163 	case PROP_AD_UNIXUSER_ATTR:
   1164 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1165 		    pgcfg->ad_unixuser_attr);
   1166 		result->auto_discovered = FALSE;
   1167 		break;
   1168 	case PROP_AD_UNIXGROUP_ATTR:
   1169 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1170 		    pgcfg->ad_unixgroup_attr);
   1171 		result->auto_discovered = FALSE;
   1172 		break;
   1173 	case PROP_NLDAP_WINNAME_ATTR:
   1174 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1175 		    pgcfg->nldap_winname_attr);
   1176 		result->auto_discovered = FALSE;
   1177 		break;
   1178 	case PROP_DIRECTORY_BASED_MAPPING:
   1179 		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
   1180 		    enum_lookup(pgcfg->directory_based_mapping,
   1181 		    directory_mapping_map));
   1182 		result->auto_discovered = FALSE;
   1183 		break;
   1184 	default:
   1185 		result->retcode = IDMAP_ERR_PROP_UNKNOWN;
   1186 		break;
   1187 	}
   1188 
   1189 out:
   1190 	UNLOCK_CONFIG();
   1191 	if (IDMAP_FATAL_ERROR(result->retcode)) {
   1192 		xdr_free(xdr_idmap_prop_res, (caddr_t)result);
   1193 		result->value.prop = PROP_UNKNOWN;
   1194 	}
   1195 	result->retcode = idmap_stat4prot(result->retcode);
   1196 	return (TRUE);
   1197 }
   1198 
   1199 
   1200 /* ARGSUSED */
   1201 int
   1202 idmap_prog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
   1203 		caddr_t result)
   1204 {
   1205 	(void) xdr_free(xdr_result, result);
   1206 	return (TRUE);
   1207 }
   1208 
   1209 /*
   1210  * This function is called by rpc_svc.c when it encounters an error.
   1211  */
   1212 NOTE(PRINTFLIKE(1))
   1213 void
   1214 idmap_rpc_msgout(const char *fmt, ...)
   1215 {
   1216 	va_list va;
   1217 	char buf[1000];
   1218 
   1219 	va_start(va, fmt);
   1220 	(void) vsnprintf(buf, sizeof (buf), fmt, va);
   1221 	va_end(va);
   1222 
   1223 	idmapdlog(LOG_ERR, "idmap RPC:  %s", buf);
   1224 }
   1225