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