xref: /titanic_50/usr/src/cmd/idmap/idmapd/server.c (revision 2032ea7bd13069ba4884066ed18f83bf12b3e247)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Service routines
30  */
31 
32 #include "idmapd.h"
33 #include "idmap_priv.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 
47 #define	_VALIDATE_LIST_CB_DATA(col, val, siz)\
48 	retcode = validate_list_cb_data(cb_data, argc, argv, col,\
49 			(uchar_t **)val, siz);\
50 	if (retcode == IDMAP_NEXT) {\
51 		result->retcode = IDMAP_NEXT;\
52 		return (0);\
53 	} else if (retcode < 0) {\
54 		result->retcode = retcode;\
55 		return (1);\
56 	}
57 
58 #define	PROCESS_LIST_SVC_SQL(rcode, db, sql, limit, cb, res, len)\
59 	rcode = process_list_svc_sql(db, sql, limit, cb, res);\
60 	if (rcode == IDMAP_ERR_BUSY)\
61 		res->retcode = IDMAP_ERR_BUSY;\
62 	else if (rcode == IDMAP_SUCCESS && len == 0)\
63 		res->retcode = IDMAP_ERR_NOTFOUND;
64 
65 
66 #define	STRDUP_OR_FAIL(to, from) \
67 	if ((from) == NULL) \
68 		to = NULL; \
69 	else { \
70 		if ((to = strdup(from)) == NULL) \
71 			return (1); \
72 	}
73 
74 /* ARGSUSED */
75 bool_t
76 idmap_null_1_svc(void *result, struct svc_req *rqstp) {
77 	return (TRUE);
78 }
79 
80 #define	IS_BATCH_SID(batch, i)\
81 	batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_SID
82 
83 #define	IS_BATCH_UID(batch, i)\
84 	batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_UID
85 
86 #define	IS_BATCH_GID(batch, i)\
87 	batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_GID
88 
89 #define	IS_REQUEST_SID(request)\
90 	request.id1.idtype == IDMAP_SID
91 
92 #define	IS_REQUEST_UID(request)\
93 	request.id1.idtype == IDMAP_UID
94 
95 #define	IS_REQUEST_GID(request)\
96 	request.id1.idtype == IDMAP_GID
97 
98 /* ARGSUSED */
99 bool_t
100 idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch,
101 		idmap_ids_res *result, struct svc_req *rqstp) {
102 	sqlite		*cache = NULL, *db = NULL;
103 	lookup_state_t	state;
104 	idmap_retcode	retcode, winrc;
105 	uint_t		i;
106 
107 	/* Init */
108 	(void) memset(result, 0, sizeof (*result));
109 	(void) memset(&state, 0, sizeof (state));
110 
111 	/* Return success if nothing was requested */
112 	if (batch.idmap_mapping_batch_len < 1)
113 		goto out;
114 
115 	/* Get cache handle */
116 	result->retcode = get_cache_handle(&cache);
117 	if (result->retcode != IDMAP_SUCCESS)
118 		goto out;
119 
120 	/* Get db handle */
121 	result->retcode = get_db_handle(&db);
122 	if (result->retcode != IDMAP_SUCCESS)
123 		goto out;
124 
125 	/* Allocate result array */
126 	result->ids.ids_val = calloc(batch.idmap_mapping_batch_len,
127 			sizeof (idmap_id_res));
128 	if (result->ids.ids_val == NULL) {
129 		idmapdlog(LOG_ERR, "Out of memory");
130 		result->retcode = IDMAP_ERR_MEMORY;
131 		goto out;
132 	}
133 	result->ids.ids_len = batch.idmap_mapping_batch_len;
134 
135 	/* Allocate hash table to check for duplicate sids */
136 	state.sid_history = calloc(batch.idmap_mapping_batch_len,
137 			sizeof (*state.sid_history));
138 	if (state.sid_history == NULL) {
139 		idmapdlog(LOG_ERR, "Out of memory");
140 		result->retcode = IDMAP_ERR_MEMORY;
141 		goto out;
142 	}
143 	state.sid_history_size = batch.idmap_mapping_batch_len;
144 	for (i = 0; i < state.sid_history_size; i++) {
145 		state.sid_history[i].key = state.sid_history_size;
146 		state.sid_history[i].next = state.sid_history_size;
147 	}
148 	state.batch = &batch;
149 	state.result = result;
150 
151 	/* Init our 'done' flags */
152 	state.sid2pid_done = state.pid2sid_done = TRUE;
153 
154 	/* First stage */
155 	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
156 		state.curpos = i;
157 		if (IS_BATCH_SID(batch, i)) {
158 			retcode = sid2pid_first_pass(
159 				&state,
160 				cache,
161 				&batch.idmap_mapping_batch_val[i],
162 				&result->ids.ids_val[i]);
163 		} else if (IS_BATCH_UID(batch, i)) {
164 			retcode = pid2sid_first_pass(
165 				&state,
166 				cache,
167 				db,
168 				&batch.idmap_mapping_batch_val[i],
169 				&result->ids.ids_val[i], 1, 0);
170 		} else if (IS_BATCH_GID(batch, i)) {
171 			retcode = pid2sid_first_pass(
172 				&state,
173 				cache,
174 				db,
175 				&batch.idmap_mapping_batch_val[i],
176 				&result->ids.ids_val[i], 0, 0);
177 		} else {
178 			result->ids.ids_val[i].retcode = IDMAP_ERR_IDTYPE;
179 			continue;
180 		}
181 		if (IDMAP_FATAL_ERROR(retcode)) {
182 			result->retcode = retcode;
183 			goto out;
184 		}
185 	}
186 
187 	/* Check if we are done */
188 	if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
189 		goto out;
190 
191 	/* Process Windows server lookups for sid2name */
192 	if (state.ad_nqueries) {
193 		winrc = lookup_win_batch_sid2name(&state, &batch,
194 				result);
195 		if (IDMAP_FATAL_ERROR(winrc)) {
196 			result->retcode = winrc;
197 			goto out;
198 		}
199 	} else
200 		winrc = IDMAP_SUCCESS;
201 
202 	/* Reset sid2pid 'done' flag */
203 	state.sid2pid_done = TRUE;
204 
205 	/* Second stage */
206 	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
207 		state.curpos = i;
208 		/* Process sid to pid ONLY */
209 		if (IS_BATCH_SID(batch, i)) {
210 			if (IDMAP_ERROR(winrc))
211 				result->ids.ids_val[i].retcode = winrc;
212 			retcode = sid2pid_second_pass(
213 				&state,
214 				cache,
215 				db,
216 				&batch.idmap_mapping_batch_val[i],
217 				&result->ids.ids_val[i]);
218 			if (IDMAP_FATAL_ERROR(retcode)) {
219 				result->retcode = retcode;
220 				goto out;
221 			}
222 		}
223 	}
224 
225 	/* Check if we are done */
226 	if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
227 		goto out;
228 
229 	/* Reset our 'done' flags */
230 	state.sid2pid_done = state.pid2sid_done = TRUE;
231 
232 	/* Update cache in a single transaction */
233 	if (sql_exec_no_cb(cache, "BEGIN TRANSACTION;") != IDMAP_SUCCESS)
234 		goto out;
235 
236 	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
237 		state.curpos = i;
238 		if (IS_BATCH_SID(batch, i)) {
239 			(void) update_cache_sid2pid(
240 				&state,
241 				cache,
242 				&batch.idmap_mapping_batch_val[i],
243 				&result->ids.ids_val[i]);
244 		} else if ((IS_BATCH_UID(batch, i)) ||
245 				(IS_BATCH_GID(batch, i))) {
246 			(void) update_cache_pid2sid(
247 				&state,
248 				cache,
249 				&batch.idmap_mapping_batch_val[i],
250 				&result->ids.ids_val[i]);
251 		}
252 	}
253 
254 	/* Commit if we have atleast one successful update */
255 	if (state.sid2pid_done == FALSE || state.pid2sid_done == FALSE)
256 		(void) sql_exec_no_cb(cache, "COMMIT TRANSACTION;");
257 	else
258 		(void) sql_exec_no_cb(cache, "END TRANSACTION;");
259 
260 out:
261 	if (state.sid_history)
262 		free(state.sid_history);
263 	if (IDMAP_ERROR(result->retcode)) {
264 		xdr_free(xdr_idmap_ids_res, (caddr_t)result);
265 		result->ids.ids_len = 0;
266 		result->ids.ids_val = NULL;
267 	}
268 	result->retcode = idmap_stat4prot(result->retcode);
269 	return (TRUE);
270 }
271 
272 
273 /* ARGSUSED */
274 static int
275 list_mappings_cb(void *parg, int argc, char **argv, char **colnames) {
276 	list_cb_data_t		*cb_data;
277 	char			*str;
278 	idmap_mappings_res	*result;
279 	idmap_retcode		retcode;
280 	int			w2u, u2w;
281 	char			*end;
282 
283 	cb_data = (list_cb_data_t *)parg;
284 	result = (idmap_mappings_res *)cb_data->result;
285 
286 	_VALIDATE_LIST_CB_DATA(9, &result->mappings.mappings_val,
287 		sizeof (idmap_mapping));
288 
289 	result->mappings.mappings_len++;
290 
291 	if ((str = strdup(argv[1])) == NULL)
292 		return (1);
293 	result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.prefix =
294 		str;
295 	result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.rid =
296 		strtoul(argv[2], &end, 10);
297 	result->mappings.mappings_val[cb_data->next].id1.idtype = IDMAP_SID;
298 
299 	result->mappings.mappings_val[cb_data->next].id2.idmap_id_u.uid =
300 		strtoul(argv[3], &end, 10);
301 	result->mappings.mappings_val[cb_data->next].id2.idtype = IDMAP_UID;
302 
303 	w2u = argv[4]?strtol(argv[4], &end, 10):0;
304 	u2w = argv[5]?strtol(argv[5], &end, 10):0;
305 
306 	if (w2u > 0 && u2w == 0)
307 		result->mappings.mappings_val[cb_data->next].direction =
308 		    IDMAP_DIRECTION_W2U;
309 	else if (w2u == 0 && u2w > 0)
310 		result->mappings.mappings_val[cb_data->next].direction =
311 		    IDMAP_DIRECTION_U2W;
312 	else
313 		result->mappings.mappings_val[cb_data->next].direction =
314 		    IDMAP_DIRECTION_BI;
315 
316 	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id1domain,
317 	    argv[6]);
318 
319 	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id1name,
320 	    argv[7]);
321 
322 	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id2name,
323 	    argv[8]);
324 
325 
326 	result->lastrowid = strtoll(argv[0], &end, 10);
327 	cb_data->next++;
328 	result->retcode = IDMAP_SUCCESS;
329 	return (0);
330 }
331 
332 
333 /* ARGSUSED */
334 bool_t
335 idmap_list_mappings_1_svc(bool_t is_user, int64_t lastrowid,
336 		uint64_t limit, idmap_mappings_res *result,
337 		struct svc_req *rqstp) {
338 	sqlite		*cache = NULL;
339 	char		lbuf[30], rbuf[30];
340 	uint64_t	maxlimit;
341 	idmap_retcode	retcode;
342 	char		*sql = NULL;
343 
344 	(void) memset(result, 0, sizeof (*result));
345 	lbuf[0] = rbuf[0] = 0;
346 
347 	RDLOCK_CONFIG();
348 	maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
349 	UNLOCK_CONFIG();
350 
351 	/* Get cache handle */
352 	result->retcode = get_cache_handle(&cache);
353 	if (result->retcode != IDMAP_SUCCESS)
354 		goto out;
355 
356 	result->retcode = IDMAP_ERR_INTERNAL;
357 
358 	/* Create LIMIT expression. */
359 	if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
360 		limit = maxlimit;
361 	if (limit > 0)
362 		(void) snprintf(lbuf, sizeof (lbuf),
363 			"LIMIT %" PRIu64, limit + 1ULL);
364 
365 	(void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
366 
367 	/*
368 	 * Combine all the above into a giant SELECT statement that
369 	 * will return the requested mappings
370 	 */
371 	sql = sqlite_mprintf("SELECT rowid, sidprefix, rid, pid, w2u, u2w,"
372 			" windomain, winname, unixname"
373 			" FROM idmap_cache WHERE "
374 			" %s AND is_user = %d %s;",
375 			rbuf, is_user?1:0, lbuf);
376 	if (sql == NULL) {
377 		idmapdlog(LOG_ERR, "Out of memory");
378 		goto out;
379 	}
380 
381 	/* Execute the SQL statement and update the return buffer */
382 	PROCESS_LIST_SVC_SQL(retcode, cache, sql, limit, list_mappings_cb,
383 		result, result->mappings.mappings_len);
384 
385 out:
386 	if (sql)
387 		sqlite_freemem(sql);
388 	if (IDMAP_ERROR(result->retcode))
389 		(void) xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
390 	result->retcode = idmap_stat4prot(result->retcode);
391 	return (TRUE);
392 }
393 
394 
395 /* ARGSUSED */
396 static int
397 list_namerules_cb(void *parg, int argc, char **argv, char **colnames) {
398 	list_cb_data_t		*cb_data;
399 	idmap_namerules_res	*result;
400 	idmap_retcode		retcode;
401 	int			w2u_order, u2w_order;
402 	char			*end;
403 
404 	cb_data = (list_cb_data_t *)parg;
405 	result = (idmap_namerules_res *)cb_data->result;
406 
407 	_VALIDATE_LIST_CB_DATA(8, &result->rules.rules_val,
408 		sizeof (idmap_namerule));
409 
410 	result->rules.rules_len++;
411 
412 	result->rules.rules_val[cb_data->next].is_user =
413 		strtol(argv[1], &end, 10);
414 
415 	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].windomain,
416 	    argv[2]);
417 
418 	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].winname,
419 	    argv[3]);
420 
421 	result->rules.rules_val[cb_data->next].is_nt4 =
422 		strtol(argv[4], &end, 10);
423 
424 	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].unixname,
425 	    argv[5]);
426 
427 	w2u_order = argv[6]?strtol(argv[6], &end, 10):0;
428 	u2w_order = argv[7]?strtol(argv[7], &end, 10):0;
429 
430 	if (w2u_order > 0 && u2w_order == 0)
431 		result->rules.rules_val[cb_data->next].direction =
432 		    IDMAP_DIRECTION_W2U;
433 	else if (w2u_order == 0 && u2w_order > 0)
434 		result->rules.rules_val[cb_data->next].direction =
435 		    IDMAP_DIRECTION_U2W;
436 	else
437 		result->rules.rules_val[cb_data->next].direction =
438 		    IDMAP_DIRECTION_BI;
439 
440 	result->lastrowid = strtoll(argv[0], &end, 10);
441 	cb_data->next++;
442 	result->retcode = IDMAP_SUCCESS;
443 	return (0);
444 }
445 
446 
447 /* ARGSUSED */
448 bool_t
449 idmap_list_namerules_1_svc(idmap_namerule rule, uint64_t lastrowid,
450 		uint64_t limit, idmap_namerules_res *result,
451 		struct svc_req *rqstp) {
452 
453 	sqlite		*db = NULL;
454 	char		w2ubuf[15], u2wbuf[15];
455 	char		lbuf[30], rbuf[30];
456 	char		*sql = NULL;
457 	char		*s_windomain = NULL, *s_winname = NULL;
458 	char		*s_unixname = NULL;
459 	uint64_t	maxlimit;
460 	idmap_retcode	retcode;
461 
462 	(void) memset(result, 0, sizeof (*result));
463 	lbuf[0] = rbuf[0] = 0;
464 
465 	RDLOCK_CONFIG();
466 	maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
467 	UNLOCK_CONFIG();
468 
469 	/* Get db handle */
470 	result->retcode = get_db_handle(&db);
471 	if (result->retcode != IDMAP_SUCCESS)
472 		goto out;
473 
474 	result->retcode = IDMAP_ERR_INTERNAL;
475 
476 	if (rule.direction < 0) {
477 		w2ubuf[0] = u2wbuf[0] = 0;
478 	} else if (rule.direction == IDMAP_DIRECTION_BI) {
479 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "AND w2u_order > 0");
480 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "AND u2w_order > 0");
481 	} else if (rule.direction == IDMAP_DIRECTION_W2U) {
482 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "AND w2u_order > 0");
483 		(void) snprintf(u2wbuf, sizeof (u2wbuf),
484 				"AND (u2w_order = 0 OR u2w_order ISNULL)");
485 	} else if (rule.direction == IDMAP_DIRECTION_U2W) {
486 		(void) snprintf(w2ubuf, sizeof (w2ubuf),
487 				"AND (w2u_order = 0 OR w2u_order ISNULL)");
488 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "AND u2w_order > 0");
489 	}
490 
491 	/* Create where statement for windomain */
492 	if (!EMPTY_STRING(rule.windomain)) {
493 		if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
494 				rule.windomain,
495 				"", &s_windomain) != IDMAP_SUCCESS)
496 			goto out;
497 	}
498 
499 	/* Create where statement for winname */
500 	if (!EMPTY_STRING(rule.winname)) {
501 		if (gen_sql_expr_from_utf8str("AND", "winname", "=",
502 				rule.winname,
503 				"", &s_winname) != IDMAP_SUCCESS)
504 			goto out;
505 	}
506 
507 	/* Create where statement for unixname */
508 	if (!EMPTY_STRING(rule.unixname)) {
509 		if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
510 				rule.unixname,
511 				"", &s_unixname) != IDMAP_SUCCESS)
512 			goto out;
513 	}
514 
515 	/* Create LIMIT expression. */
516 	if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
517 		limit = maxlimit;
518 	if (limit > 0)
519 		(void) snprintf(lbuf, sizeof (lbuf),
520 			"LIMIT %" PRIu64, limit + 1ULL);
521 
522 	(void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
523 
524 	/*
525 	 * Combine all the above into a giant SELECT statement that
526 	 * will return the requested rules
527 	 */
528 	sql = sqlite_mprintf("SELECT rowid, is_user, windomain, winname, "
529 			"is_nt4, unixname, w2u_order, u2w_order "
530 			"FROM namerules WHERE "
531 			" %s AND is_user = %d %s %s %s %s %s %s;",
532 			rbuf, rule.is_user?1:0,
533 			s_windomain?s_windomain:"",
534 			s_winname?s_winname:"",
535 			s_unixname?s_unixname:"",
536 			w2ubuf, u2wbuf, lbuf);
537 	if (sql == NULL) {
538 		idmapdlog(LOG_ERR, "Out of memory");
539 		goto out;
540 	}
541 
542 	/* Execute the SQL statement and update the return buffer */
543 	PROCESS_LIST_SVC_SQL(retcode, db, sql, limit, list_namerules_cb,
544 		result, result->rules.rules_len);
545 
546 out:
547 	if (s_windomain)
548 		sqlite_freemem(s_windomain);
549 	if (s_winname)
550 		sqlite_freemem(s_winname);
551 	if (s_unixname)
552 		sqlite_freemem(s_unixname);
553 	if (sql)
554 		sqlite_freemem(sql);
555 	if (IDMAP_ERROR(result->retcode))
556 		(void) xdr_free(xdr_idmap_namerules_res, (caddr_t)result);
557 	result->retcode = idmap_stat4prot(result->retcode);
558 	return (TRUE);
559 }
560 
561 #define	IDMAP_RULES_AUTH	"solaris.admin.idmap.rules"
562 static int
563 verify_rules_auth(struct svc_req *rqstp) {
564 	ucred_t		*uc = NULL;
565 	uid_t		uid;
566 	char		buf[1024];
567 	struct passwd	pwd;
568 	const char	*me = "verify_rules_auth";
569 
570 	if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
571 		idmapdlog(LOG_ERR,
572 			"%s: svc_getcallerucred failed (errno=%d)",
573 			me, errno);
574 		return (-1);
575 	}
576 
577 	uid = ucred_geteuid(uc);
578 	if (uid == (uid_t)-1) {
579 		idmapdlog(LOG_ERR,
580 			"%s: ucred_geteuid failed (errno=%d)",
581 			me, errno);
582 		ucred_free(uc);
583 		return (-1);
584 	}
585 
586 	if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
587 		idmapdlog(LOG_ERR,
588 			"%s: getpwuid_r(%u) failed (errno=%d)",
589 			me, uid, errno);
590 		ucred_free(uc);
591 		return (-1);
592 	}
593 
594 	if (chkauthattr(IDMAP_RULES_AUTH, pwd.pw_name) != 1) {
595 		idmapdlog(LOG_INFO,
596 			"%s: %s does not have authorization.",
597 			me, pwd.pw_name);
598 		ucred_free(uc);
599 		return (-1);
600 	}
601 
602 	ucred_free(uc);
603 	return (1);
604 }
605 
606 /*
607  * Meaning of the return values is the following: For retcode ==
608  * IDMAP_SUCCESS, everything went OK and error_index is
609  * undefined. Otherwise, error_index >=0 shows the failed batch
610  * element. errro_index == -1 indicates failure at the beginning,
611  * error_index == -2 at the end.
612  */
613 
614 /* ARGSUSED */
615 bool_t
616 idmap_update_1_svc(idmap_update_batch batch, idmap_update_res *res,
617 		struct svc_req *rqstp) {
618 	sqlite		*db = NULL;
619 	idmap_update_op	*up;
620 	int		i;
621 	int		trans = FALSE;
622 
623 	res->error_index = -1;
624 	(void) memset(&res->error_rule, 0, sizeof (res->error_rule));
625 	(void) memset(&res->conflict_rule, 0, sizeof (res->conflict_rule));
626 
627 	if (verify_rules_auth(rqstp) < 0) {
628 		res->retcode = IDMAP_ERR_PERMISSION_DENIED;
629 		goto out;
630 	}
631 
632 	if (batch.idmap_update_batch_len == 0 ||
633 			batch.idmap_update_batch_val == NULL) {
634 		res->retcode = IDMAP_SUCCESS;
635 		goto out;
636 	}
637 
638 	/* Get db handle */
639 	res->retcode = get_db_handle(&db);
640 	if (res->retcode != IDMAP_SUCCESS)
641 		goto out;
642 
643 	res->retcode = sql_exec_no_cb(db, "BEGIN TRANSACTION;");
644 	if (res->retcode != IDMAP_SUCCESS)
645 		goto out;
646 	trans = TRUE;
647 
648 	for (i = 0; i < batch.idmap_update_batch_len; i++) {
649 		up = &batch.idmap_update_batch_val[i];
650 		switch (up->opnum) {
651 		case OP_NONE:
652 			res->retcode = IDMAP_SUCCESS;
653 			break;
654 		case OP_ADD_NAMERULE:
655 			res->retcode = add_namerule(db,
656 				&up->idmap_update_op_u.rule);
657 			break;
658 		case OP_RM_NAMERULE:
659 			res->retcode = rm_namerule(db,
660 				&up->idmap_update_op_u.rule);
661 			break;
662 		case OP_FLUSH_NAMERULES:
663 			res->retcode = flush_namerules(db,
664 				up->idmap_update_op_u.is_user);
665 			break;
666 		default:
667 			res->retcode = IDMAP_ERR_NOTSUPPORTED;
668 			break;
669 		};
670 
671 		if (res->retcode != IDMAP_SUCCESS) {
672 			res->error_index = i;
673 			if (up->opnum == OP_ADD_NAMERULE ||
674 			    up->opnum == OP_RM_NAMERULE) {
675 				idmap_stat r2 =
676 				    idmap_namerule_cpy(&res->error_rule,
677 					&up->idmap_update_op_u.rule);
678 				if (r2 != IDMAP_SUCCESS)
679 					res->retcode = r2;
680 			}
681 			goto out;
682 		}
683 	}
684 
685 out:
686 	if (trans) {
687 		if (res->retcode == IDMAP_SUCCESS) {
688 			res->retcode =
689 			    sql_exec_no_cb(db, "COMMIT TRANSACTION;");
690 			if (res->retcode !=  IDMAP_SUCCESS)
691 				res->error_index = -2;
692 		}
693 		else
694 			(void) sql_exec_no_cb(db, "ROLLBACK TRANSACTION;");
695 	}
696 
697 	res->retcode = idmap_stat4prot(res->retcode);
698 
699 	return (TRUE);
700 }
701 
702 
703 /* ARGSUSED */
704 bool_t
705 idmap_get_mapped_id_by_name_1_svc(idmap_mapping request,
706 		idmap_mappings_res *result, struct svc_req *rqstp) {
707 	sqlite		*cache = NULL, *db = NULL;
708 
709 	/* Init */
710 	(void) memset(result, 0, sizeof (*result));
711 
712 	/* Get cache handle */
713 	result->retcode = get_cache_handle(&cache);
714 	if (result->retcode != IDMAP_SUCCESS)
715 		goto out;
716 
717 	/* Get db handle */
718 	result->retcode = get_db_handle(&db);
719 	if (result->retcode != IDMAP_SUCCESS)
720 		goto out;
721 
722 	/* Allocate result */
723 	result->mappings.mappings_val = calloc(1, sizeof (idmap_mapping));
724 	if (result->mappings.mappings_val == NULL) {
725 		idmapdlog(LOG_ERR, "Out of memory");
726 		result->retcode = IDMAP_ERR_MEMORY;
727 		goto out;
728 	}
729 	result->mappings.mappings_len = 1;
730 
731 	if (IS_REQUEST_SID(request)) {
732 		result->retcode = get_w2u_mapping(
733 			cache,
734 			db,
735 			&request,
736 			result->mappings.mappings_val);
737 	} else if (IS_REQUEST_UID(request)) {
738 		result->retcode = get_u2w_mapping(
739 			cache,
740 			db,
741 			&request,
742 			result->mappings.mappings_val,
743 			1);
744 	} else if (IS_REQUEST_GID(request)) {
745 		result->retcode = get_u2w_mapping(
746 			cache,
747 			db,
748 			&request,
749 			result->mappings.mappings_val,
750 			0);
751 	} else {
752 		result->retcode = IDMAP_ERR_IDTYPE;
753 	}
754 
755 out:
756 	if (IDMAP_FATAL_ERROR(result->retcode)) {
757 		xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
758 		result->mappings.mappings_len = 0;
759 		result->mappings.mappings_val = NULL;
760 	}
761 	result->retcode = idmap_stat4prot(result->retcode);
762 	return (TRUE);
763 }
764 
765 
766 /* ARGSUSED */
767 int
768 idmap_prog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
769 		caddr_t result) {
770 	(void) xdr_free(xdr_result, result);
771 	return (TRUE);
772 }
773