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