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