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