xref: /titanic_51/usr/src/uts/common/idmap/idmap_kapi.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Windows to Solaris Identity Mapping kernel API
29  * This module provides an API to map Windows SIDs to
30  * Solaris UID and GIDs.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include <sys/types.h>
36 #include <sys/ksynch.h>
37 #include <sys/door.h>
38 #include <rpc/rpc_msg.h>
39 #include <rpc/xdr.h>
40 #include <rpc/auth.h>
41 #include <rpc/rpc_sztypes.h>
42 #ifdef	DEBUG
43 #include <sys/cmn_err.h>
44 #endif	/* DEBUG */
45 #include <sys/proc.h>
46 #include <sys/sunddi.h>
47 #include <sys/param.h>
48 #include <sys/atomic.h>
49 #include <sys/sysmacros.h>
50 #include <sys/disp.h>
51 #include <sys/kidmap.h>
52 #include "idmap_prot.h"
53 #include "kidmap_priv.h"
54 
55 
56 static	kmutex_t	idmap_lock;
57 static	idmap_cache_t	idmap_cache;
58 
59 /*
60  * Used to hold RPC header, in particular the XID (not that XID matters
61  * in doors RPC)
62  */
63 static struct rpc_msg	call_msg;
64 
65 typedef struct idmap_get_res {
66 	idmap_id_type	idtype;
67 	uid_t		*uid;
68 	gid_t		*gid;
69 	uid_t		*pid;
70 	int		*is_user;
71 	const char	**sid_prefix;
72 	uint32_t	*rid;
73 	idmap_stat	*stat;
74 } idmap_get_res;
75 
76 /* Batch mapping handle structure */
77 struct idmap_get_handle {
78 	idmap_cache_t	*cache;
79 	int 		mapping_num;
80 	int 		mapping_size;
81 	idmap_mapping	*mapping;
82 	idmap_get_res	*result;
83 };
84 
85 static kmutex_t	idmap_mutex;
86 static int	idmap_stopped = 0;
87 
88 struct idmap_reg {
89 	door_handle_t 	idmap_door;
90 	int		idmap_invalid;
91 	int		idmap_invalidated;
92 	int		idmap_ref;
93 };
94 
95 static idmap_reg_t *idmap_ptr;
96 
97 
98 static int
99 kidmap_rpc_call(uint32_t op, xdrproc_t xdr_args, caddr_t args,
100 		xdrproc_t xdr_res, caddr_t res);
101 
102 static int	kidmap_call_door(door_arg_t *arg);
103 
104 static void
105 idmap_freeone(idmap_reg_t *p)
106 {
107 	ASSERT(p->idmap_ref == 0);
108 	ASSERT(MUTEX_HELD(&idmap_mutex));
109 
110 	door_ki_rele(p->idmap_door);
111 	if (idmap_ptr == p)
112 		idmap_ptr = NULL;
113 
114 	kmem_free(p, sizeof (*p));
115 }
116 
117 void
118 idmap_get_door(idmap_reg_t **state, door_handle_t *dh)
119 {
120 	idmap_reg_t *idmp;
121 
122 	*state = NULL;
123 	if (dh != NULL)
124 		*dh = NULL;
125 
126 	mutex_enter(&idmap_mutex);
127 	if ((idmp = idmap_ptr) == NULL || idmp->idmap_invalid) {
128 		mutex_exit(&idmap_mutex);
129 		return;
130 	}
131 
132 	idmap_ptr->idmap_ref++;
133 
134 	mutex_exit(&idmap_mutex);
135 
136 	*state = idmp;
137 	if (dh != NULL)
138 		*dh = idmp->idmap_door;
139 }
140 
141 void
142 idmap_release_door(idmap_reg_t *idmp)
143 {
144 	mutex_enter(&idmap_mutex);
145 
146 	/*
147 	 * Note we may decrement idmap_ref twice; if we do it's because
148 	 * we had EBADF, and rather than decrement the ref count where
149 	 * that happens we do it here to make sure that we do both
150 	 * decrements while holding idmap_mutex.
151 	 */
152 	if (idmp->idmap_invalid && !idmp->idmap_invalidated) {
153 		idmp->idmap_invalidated = 1;
154 		if (--idmp->idmap_ref == 0) {
155 			idmap_freeone(idmap_ptr);
156 			mutex_exit(&idmap_mutex);
157 			return;
158 		}
159 	}
160 
161 	if (--idmp->idmap_ref == 0)
162 		idmap_freeone(idmap_ptr);
163 
164 	mutex_exit(&idmap_mutex);
165 }
166 
167 int
168 idmap_reg_dh(door_handle_t dh)
169 {
170 	idmap_reg_t *idmp;
171 
172 	idmp = kmem_alloc(sizeof (*idmp), KM_SLEEP);
173 
174 	idmp->idmap_door = dh;
175 	mutex_enter(&idmap_mutex);
176 
177 
178 	if (idmap_stopped) {
179 		mutex_exit(&idmap_mutex);
180 		/*
181 		 * We're unloading the module.  Calling idmap_reg(2)
182 		 * again once we're done unloading should cause the
183 		 * module to be loaded again, so we return EAGAIN.
184 		 */
185 		return (EAGAIN);
186 	}
187 
188 	if (idmap_ptr != NULL) {
189 		if (--idmap_ptr->idmap_ref == 0)
190 			idmap_freeone(idmap_ptr);
191 	}
192 	idmp->idmap_invalid = 0;
193 	idmp->idmap_invalidated = 0;
194 	idmp->idmap_ref = 1;
195 	idmap_ptr = idmp;
196 
197 	call_msg.rm_xid = 1;
198 	call_msg.rm_call.cb_prog = IDMAP_PROG;
199 	call_msg.rm_call.cb_vers = IDMAP_V1;
200 
201 	mutex_exit(&idmap_mutex);
202 
203 	return (0);
204 }
205 
206 int
207 idmap_unreg_dh(door_handle_t dh)
208 {
209 	kidmap_cache_purge(&idmap_cache);
210 
211 	mutex_enter(&idmap_mutex);
212 	if (idmap_ptr == NULL || idmap_ptr->idmap_door != dh) {
213 		mutex_exit(&idmap_mutex);
214 		return (EINVAL);
215 	}
216 
217 	if (idmap_ptr->idmap_invalid) {
218 		mutex_exit(&idmap_mutex);
219 		return (EINVAL);
220 	}
221 	idmap_ptr->idmap_invalid = 1;
222 	idmap_ptr->idmap_invalidated = 1;
223 	if (--idmap_ptr->idmap_ref == 0)
224 		idmap_freeone(idmap_ptr);
225 	mutex_exit(&idmap_mutex);
226 	return (0);
227 }
228 
229 
230 static int
231 kidmap_call_door(door_arg_t *arg)
232 {
233 	int status = 0;
234 	door_handle_t	dh;
235 	idmap_reg_t	*reg;
236 
237 	idmap_get_door(&reg, &dh);
238 	if (reg == NULL || dh == NULL) {
239 		return (-1);
240 	}
241 
242 	status = door_ki_upcall(dh, arg);
243 
244 #ifdef	DEBUG
245 	if (status != 0)
246 		cmn_err(CE_WARN, "idmap: Door call failed %d\n", status);
247 #endif	/* DEBUG */
248 
249 	if (status == EBADF) {
250 		reg->idmap_invalid = 1;
251 	}
252 
253 	idmap_release_door(reg);
254 
255 	return (status);
256 }
257 
258 
259 int
260 kidmap_start(void)
261 {
262 	mutex_init(&idmap_lock, NULL, MUTEX_DEFAULT, NULL);
263 	kidmap_sid_prefix_store_init();
264 	kidmap_cache_create(&idmap_cache);
265 
266 	idmap_stopped = 0;
267 
268 	return (0);
269 }
270 
271 
272 int
273 kidmap_stop(void)
274 {
275 	mutex_enter(&idmap_mutex);
276 
277 	if (idmap_ptr != NULL) {
278 		mutex_exit(&idmap_mutex);
279 		return (EBUSY);
280 	}
281 
282 	idmap_stopped = 1;
283 
284 	mutex_exit(&idmap_mutex);
285 
286 	kidmap_cache_delete(&idmap_cache);
287 	mutex_destroy(&idmap_lock);
288 
289 	return (0);
290 }
291 
292 
293 /*
294  * Given Domain SID and RID, get UID
295  *
296  * Input:
297  * sid_prefix	- Domain SID in canonical form
298  * rid	- RID
299  *
300  * Output:
301  * uid  - POSIX UID if return == IDMAP_SUCCESS
302  *
303  * Return:
304  * Success return IDMAP_SUCCESS else IDMAP error
305  */
306 idmap_stat
307 kidmap_getuidbysid(const char *sid_prefix, uint32_t rid, uid_t *uid)
308 {
309 	idmap_mapping_batch	args;
310 	idmap_mapping		mapping;
311 	idmap_ids_res		results;
312 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
313 	const char		*new_sid_prefix;
314 	idmap_stat		status;
315 
316 	if (sid_prefix == NULL || uid == NULL)
317 		return (IDMAP_ERR_ARG);
318 
319 	if (kidmap_cache_lookup_uidbysid(&idmap_cache, sid_prefix, rid, uid)
320 	    == IDMAP_SUCCESS)
321 		return (IDMAP_SUCCESS);
322 
323 	bzero(&mapping, sizeof (idmap_mapping));
324 	mapping.id1.idtype = IDMAP_SID;
325 	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
326 	mapping.id1.idmap_id_u.sid.rid = rid;
327 	mapping.id2.idtype = IDMAP_UID;
328 
329 	bzero(&results, sizeof (idmap_ids_res));
330 
331 	args.idmap_mapping_batch_len = 1;
332 	args.idmap_mapping_batch_val = &mapping;
333 
334 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
335 	    (caddr_t)&args, xdr_idmap_ids_res,
336 	    (caddr_t)&results) == 0) {
337 		/* Door call succeded */
338 		if (results.ids.ids_len >= 1 &&
339 		    results.ids.ids_val[0].id.idtype == IDMAP_UID) {
340 			status = results.ids.ids_val[0].retcode;
341 			*uid = results.ids.ids_val[0].id.idmap_id_u.uid;
342 			if (status == IDMAP_SUCCESS) {
343 				new_sid_prefix = kidmap_find_sid_prefix(
344 				    sid_prefix);
345 				kidmap_cache_add_uidbysid(&idmap_cache,
346 				    new_sid_prefix, rid, *uid);
347 			}
348 		} else {
349 			status = IDMAP_ERR_NOMAPPING;
350 			*uid = UID_NOBODY;
351 		}
352 		xdr_free(xdr_idmap_ids_res, (char *)&results);
353 	} else {
354 		/* Door call failed */
355 		status = IDMAP_ERR_NOMAPPING;
356 		*uid = UID_NOBODY;
357 	}
358 	return (status);
359 }
360 
361 
362 /*
363  * Given Domain SID and RID, get GID
364  *
365  * Input:
366  * sid_prefix	- Domain SID in canonical form
367  * rid	- RID
368  *
369  * Output:
370  * gid  - POSIX UID if return == IDMAP_SUCCESS
371  *
372  * Return:
373  * Success return IDMAP_SUCCESS else IDMAP error
374  */
375 idmap_stat
376 kidmap_getgidbysid(const char *sid_prefix, uint32_t rid, gid_t *gid)
377 {
378 	idmap_mapping_batch	args;
379 	idmap_mapping		mapping;
380 	idmap_ids_res		results;
381 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
382 	const char		*new_sid_prefix;
383 	idmap_stat		status;
384 
385 	if (sid_prefix == NULL || gid == NULL)
386 		return (IDMAP_ERR_ARG);
387 
388 	if (kidmap_cache_lookup_gidbysid(&idmap_cache, sid_prefix, rid, gid)
389 	    == IDMAP_SUCCESS) {
390 		return (IDMAP_SUCCESS);
391 	}
392 
393 	bzero(&mapping, sizeof (idmap_mapping));
394 	mapping.id1.idtype = IDMAP_SID;
395 	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
396 	mapping.id1.idmap_id_u.sid.rid = rid;
397 	mapping.id2.idtype = IDMAP_GID;
398 
399 	bzero(&results, sizeof (idmap_ids_res));
400 
401 	args.idmap_mapping_batch_len = 1;
402 	args.idmap_mapping_batch_val = &mapping;
403 
404 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
405 	    (caddr_t)&args, xdr_idmap_ids_res,
406 	    (caddr_t)&results) == 0) {
407 		/* Door call succeded */
408 		if (results.ids.ids_len >= 1 &&
409 		    results.ids.ids_val[0].id.idtype == IDMAP_GID) {
410 			status = results.ids.ids_val[0].retcode;
411 			*gid = results.ids.ids_val[0].id.idmap_id_u.gid;
412 			if (status == IDMAP_SUCCESS) {
413 				new_sid_prefix = kidmap_find_sid_prefix(
414 				    sid_prefix);
415 				kidmap_cache_add_gidbysid(&idmap_cache,
416 				    new_sid_prefix, rid, *gid);
417 			}
418 		} else {
419 			status = IDMAP_ERR_NOMAPPING;
420 			*gid = GID_NOBODY;
421 		}
422 		xdr_free(xdr_idmap_ids_res, (char *)&results);
423 	} else {
424 		/* Door call failed */
425 		status = IDMAP_ERR_NOMAPPING;
426 		*gid = GID_NOBODY;
427 	}
428 	return (status);
429 }
430 
431 /*
432  * Given Domain SID and RID, get Posix ID
433  *
434  * Input:
435  * sid_prefix	- Domain SID in canonical form
436  * rid	- RID
437  *
438  * Output:
439  * pid  - POSIX ID if return == IDMAP_SUCCESS
440  * is_user - 1 == UID, 0 == GID  if return == IDMAP_SUCCESS
441  *
442  * Return:
443  * Success return IDMAP_SUCCESS else IDMAP error
444  */
445 idmap_stat
446 kidmap_getpidbysid(const char *sid_prefix, uint32_t rid, uid_t *pid,
447 		int *is_user)
448 {
449 	idmap_mapping_batch	args;
450 	idmap_mapping		mapping;
451 	idmap_ids_res		results;
452 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
453 	const char		*new_sid_prefix;
454 	idmap_stat		status;
455 
456 	if (sid_prefix == NULL || pid == NULL || is_user == NULL)
457 		return (IDMAP_ERR_ARG);
458 
459 	if (kidmap_cache_lookup_pidbysid(&idmap_cache, sid_prefix, rid, pid,
460 	    is_user) == IDMAP_SUCCESS) {
461 		return (IDMAP_SUCCESS);
462 	}
463 
464 	bzero(&mapping, sizeof (idmap_mapping));
465 	mapping.id1.idtype = IDMAP_SID;
466 	mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
467 	mapping.id1.idmap_id_u.sid.rid = rid;
468 	mapping.id2.idtype = IDMAP_POSIXID;
469 
470 	bzero(&results, sizeof (idmap_ids_res));
471 
472 	args.idmap_mapping_batch_len = 1;
473 	args.idmap_mapping_batch_val = &mapping;
474 
475 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
476 	    (caddr_t)&args, xdr_idmap_ids_res,
477 	    (caddr_t)&results) == 0) {
478 		/* Door call succeded */
479 		if (results.ids.ids_len >= 1 && (
480 		    results.ids.ids_val[0].id.idtype == IDMAP_UID ||
481 		    results.ids.ids_val[0].id.idtype == IDMAP_GID)) {
482 			status = results.ids.ids_val[0].retcode;
483 			if (results.ids.ids_val[0].id.idtype == IDMAP_UID) {
484 				*is_user = 1;
485 				*pid = results.ids.ids_val[0].id.idmap_id_u.uid;
486 			} else {
487 				*is_user = 0;
488 				*pid = results.ids.ids_val[0].id.idmap_id_u.gid;
489 			}
490 			if (status == IDMAP_SUCCESS) {
491 				new_sid_prefix = kidmap_find_sid_prefix(
492 				    sid_prefix);
493 				kidmap_cache_add_pidbysid(&idmap_cache,
494 				    new_sid_prefix, rid, *pid,
495 				    *is_user);
496 			}
497 		} else {
498 			status = IDMAP_ERR_NOMAPPING;
499 			*is_user = 1;
500 			*pid = UID_NOBODY;
501 		}
502 		xdr_free(xdr_idmap_ids_res, (char *)&results);
503 	} else {
504 		/* Door call failed */
505 		status = IDMAP_ERR_NOMAPPING;
506 		*is_user = 1;
507 		*pid = UID_NOBODY;
508 	}
509 	return (status);
510 }
511 
512 
513 /*
514  * Given UID, get Domain SID and RID
515  *
516  * Input:
517  * uid - Posix UID
518  *
519  * Output:
520  * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
521  * rid	- RID if return == IDMAP_SUCCESS
522  *
523  * Return:
524  * Success return IDMAP_SUCCESS else IDMAP error
525  */
526 idmap_stat
527 kidmap_getsidbyuid(uid_t uid, const char **sid_prefix, uint32_t *rid)
528 {
529 	idmap_mapping_batch	args;
530 	idmap_mapping		mapping;
531 	idmap_ids_res		results;
532 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
533 	idmap_stat		status;
534 	time_t			entry_ttl;
535 	idmap_id		*id;
536 
537 	if (sid_prefix == NULL || rid == NULL)
538 		return (IDMAP_ERR_ARG);
539 
540 	if (kidmap_cache_lookup_sidbyuid(&idmap_cache, sid_prefix, rid, uid)
541 	    == IDMAP_SUCCESS) {
542 		return (IDMAP_SUCCESS);
543 	}
544 
545 	bzero(&mapping, sizeof (idmap_mapping));
546 	mapping.id1.idtype = IDMAP_UID;
547 	mapping.id1.idmap_id_u.uid = uid;
548 	mapping.id2.idtype = IDMAP_SID;
549 
550 	bzero(&results, sizeof (idmap_ids_res));
551 
552 	args.idmap_mapping_batch_len = 1;
553 	args.idmap_mapping_batch_val = &mapping;
554 
555 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
556 	    (caddr_t)&args, xdr_idmap_ids_res,
557 	    (caddr_t)&results) == 0) {
558 		/* Door call succeded */
559 		if (results.ids.ids_len >= 1 &&
560 		    (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
561 		    results.ids.ids_val[0].id.idtype == IDMAP_USID ||
562 		    results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
563 			status = results.ids.ids_val[0].retcode;
564 			id = &results.ids.ids_val[0].id;
565 			*sid_prefix = kidmap_find_sid_prefix(
566 			    id->idmap_id_u.sid.prefix);
567 			*rid = id->idmap_id_u.sid.rid;
568 			if (status == IDMAP_SUCCESS) {
569 				kidmap_cache_add_sidbyuid(&idmap_cache,
570 				    *sid_prefix, *rid, uid);
571 			}
572 		} else {
573 			status = IDMAP_ERR_NOMAPPING;
574 			*rid = 0;
575 			*sid_prefix = NULL;
576 		}
577 		xdr_free(xdr_idmap_ids_res, (char *)&results);
578 	} else {
579 		/* Door call failed */
580 		status = IDMAP_ERR_NOMAPPING;
581 		*rid = 0;
582 		*sid_prefix = NULL;
583 	}
584 	return (status);
585 }
586 
587 
588 /*
589  * Given GID, get Domain SID and RID
590  *
591  * Input:
592  * gid - Posix GID
593  *
594  * Output:
595  * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
596  * rid	- RID if return == IDMAP_SUCCESS
597  *
598  * Return:
599  * Success return IDMAP_SUCCESS else IDMAP error
600  */
601 idmap_stat
602 kidmap_getsidbygid(gid_t gid, const char **sid_prefix, uint32_t *rid)
603 {
604 	idmap_mapping_batch	args;
605 	idmap_mapping		mapping;
606 	idmap_ids_res		results;
607 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
608 	idmap_stat		status;
609 	idmap_id		*id;
610 
611 	if (sid_prefix == NULL || rid == NULL)
612 		return (IDMAP_ERR_ARG);
613 
614 	if (kidmap_cache_lookup_sidbygid(&idmap_cache, sid_prefix, rid, gid)
615 	    == IDMAP_SUCCESS) {
616 		return (IDMAP_SUCCESS);
617 	}
618 
619 	bzero(&mapping, sizeof (idmap_mapping));
620 	mapping.id1.idtype = IDMAP_GID;
621 	mapping.id1.idmap_id_u.uid = gid;
622 	mapping.id2.idtype = IDMAP_SID;
623 
624 	bzero(&results, sizeof (idmap_ids_res));
625 
626 	args.idmap_mapping_batch_len = 1;
627 	args.idmap_mapping_batch_val = &mapping;
628 
629 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
630 	    (caddr_t)&args, xdr_idmap_ids_res,
631 	    (caddr_t)&results) == 0) {
632 		/* Door call succeded */
633 		if (results.ids.ids_len >= 1 &&
634 		    (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
635 		    results.ids.ids_val[0].id.idtype == IDMAP_USID ||
636 		    results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
637 			status = results.ids.ids_val[0].retcode;
638 			id = &results.ids.ids_val[0].id;
639 			*sid_prefix = kidmap_find_sid_prefix(
640 			    id->idmap_id_u.sid.prefix);
641 			*rid = id->idmap_id_u.sid.rid;
642 			if (status == IDMAP_SUCCESS) {
643 				kidmap_cache_add_sidbygid(&idmap_cache,
644 				    *sid_prefix, *rid, gid);
645 			}
646 		} else {
647 			status = IDMAP_ERR_NOMAPPING;
648 			*rid = 0;
649 			*sid_prefix = NULL;
650 		}
651 		xdr_free(xdr_idmap_ids_res, (char *)&results);
652 	} else {
653 		/* Door call failed */
654 		status = IDMAP_ERR_NOMAPPING;
655 		*rid = 0;
656 		*sid_prefix = NULL;
657 	}
658 	return (status);
659 }
660 
661 /*
662  * Create handle to get SID to UID/GID mapping entries
663  *
664  * Input:
665  * 	none
666  * Return:
667  *	get_handle
668  *
669  */
670 idmap_get_handle_t *
671 kidmap_get_create(void)
672 {
673 	idmap_get_handle_t *handle;
674 #define	INIT_MAPPING_SIZE	6
675 
676 	handle = kmem_zalloc(sizeof (idmap_get_handle_t), KM_SLEEP);
677 
678 	handle->mapping = kmem_zalloc((sizeof (idmap_mapping)) *
679 	    INIT_MAPPING_SIZE, KM_SLEEP);
680 
681 	handle->result = kmem_zalloc((sizeof (idmap_get_res)) *
682 	    INIT_MAPPING_SIZE, KM_SLEEP);
683 	handle->mapping_size = INIT_MAPPING_SIZE;
684 	handle->cache = &idmap_cache;
685 
686 	return (handle);
687 }
688 
689 /*
690  * Internal routine to extend a "get_handle"
691  */
692 static void
693 kidmap_get_extend(idmap_get_handle_t *get_handle)
694 {
695 	idmap_mapping *mapping;
696 	idmap_get_res *result;
697 	int new_size = get_handle->mapping_size + INIT_MAPPING_SIZE;
698 
699 	mapping = kmem_zalloc((sizeof (idmap_mapping)) *
700 	    new_size, KM_SLEEP);
701 	(void) memcpy(mapping, get_handle->mapping,
702 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
703 
704 	result = kmem_zalloc((sizeof (idmap_get_res)) *
705 	    new_size, KM_SLEEP);
706 	(void) memcpy(result, get_handle->result,
707 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
708 
709 	kmem_free(get_handle->mapping,
710 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
711 	get_handle->mapping = mapping;
712 
713 	kmem_free(get_handle->result,
714 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
715 	get_handle->result = result;
716 
717 	get_handle->mapping_size = new_size;
718 }
719 
720 
721 /*
722  * Given Domain SID and RID, get UID
723  *
724  * Input:
725  * sid_prefix	- Domain SID in canonical form
726  * rid	- RID
727  *
728  * Output:
729  * stat - status of the get request
730  * uid  - POSIX UID if stat == IDMAP_SUCCESS
731  *
732  * Note: The output parameters will be set by idmap_get_mappings()
733  */
734 idmap_stat
735 kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
736 			uint32_t rid, uid_t *uid, idmap_stat *stat)
737 {
738 	idmap_mapping	*mapping;
739 	idmap_get_res 	*result;
740 
741 	if (get_handle == NULL || sid_prefix == NULL ||
742 	    uid == NULL || stat == NULL)
743 		return (IDMAP_ERR_ARG);
744 
745 	if (kidmap_cache_lookup_uidbysid(get_handle->cache, sid_prefix,
746 	    rid, uid) == IDMAP_SUCCESS) {
747 		*stat = IDMAP_SUCCESS;
748 		return (IDMAP_SUCCESS);
749 	}
750 
751 	if (get_handle->mapping_num >= get_handle->mapping_size)
752 		kidmap_get_extend(get_handle);
753 
754 	mapping = &get_handle->mapping[get_handle->mapping_num];
755 	mapping->flag = 0;
756 	mapping->id1.idtype = IDMAP_SID;
757 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
758 	mapping->id1.idmap_id_u.sid.rid = rid;
759 	mapping->id2.idtype = IDMAP_UID;
760 
761 	result = &get_handle->result[get_handle->mapping_num];
762 	result->idtype = IDMAP_UID;
763 	result->uid = uid;
764 	result->gid = NULL;
765 	result->pid = NULL;
766 	result->sid_prefix = NULL;
767 	result->rid = NULL;
768 	result->is_user = NULL;
769 	result->stat = stat;
770 
771 	get_handle->mapping_num++;
772 
773 	return (IDMAP_SUCCESS);
774 }
775 
776 
777 /*
778  * Given Domain SID and RID, get GID
779  *
780  * Input:
781  * sid_prefix	- Domain SID in canonical form
782  * rid	- RID
783  *
784  * Output:
785  * stat - status of the get request
786  * gid  - POSIX GID if stat == IDMAP_SUCCESS
787  *
788  * Note: The output parameters will be set by idmap_get_mappings()
789  */
790 idmap_stat
791 kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
792 			uint32_t rid, uid_t *gid, idmap_stat *stat)
793 {
794 	idmap_mapping	*mapping;
795 	idmap_get_res 	*result;
796 
797 	if (get_handle == NULL || sid_prefix == NULL ||
798 	    gid == NULL || stat == NULL)
799 		return (IDMAP_ERR_ARG);
800 
801 	if (kidmap_cache_lookup_gidbysid(get_handle->cache, sid_prefix,
802 	    rid, gid) == IDMAP_SUCCESS) {
803 		*stat = IDMAP_SUCCESS;
804 		return (IDMAP_SUCCESS);
805 	}
806 
807 	if (get_handle->mapping_num >= get_handle->mapping_size)
808 		kidmap_get_extend(get_handle);
809 
810 	mapping = &get_handle->mapping[get_handle->mapping_num];
811 	mapping->flag = 0;
812 	mapping->id1.idtype = IDMAP_SID;
813 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
814 	mapping->id1.idmap_id_u.sid.rid = rid;
815 	mapping->id2.idtype = IDMAP_GID;
816 
817 	result = &get_handle->result[get_handle->mapping_num];
818 	result->idtype = IDMAP_GID;
819 	result->uid = NULL;
820 	result->gid = gid;
821 	result->pid = NULL;
822 	result->sid_prefix = NULL;
823 	result->rid = NULL;
824 	result->is_user = NULL;
825 	result->stat = stat;
826 
827 	get_handle->mapping_num++;
828 
829 	return (IDMAP_SUCCESS);
830 }
831 
832 
833 /*
834  * Given Domain SID and RID, get Posix ID
835  *
836  * Input:
837  * sid_prefix	- Domain SID in canonical form
838  * rid	- RID
839  *
840  * Output:
841  * stat    - status of the get request
842  * is_user - user or group
843  * pid     - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
844  *           POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
845  *
846  * Note: The output parameters will be set by idmap_get_mappings()
847  */
848 idmap_stat
849 kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
850 		uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
851 {
852 	idmap_mapping	*mapping;
853 	idmap_get_res 	*result;
854 
855 	if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
856 	    is_user == NULL || stat == NULL)
857 		return (IDMAP_ERR_ARG);
858 
859 	if (kidmap_cache_lookup_pidbysid(get_handle->cache, sid_prefix,
860 	    rid, pid, is_user) == IDMAP_SUCCESS) {
861 		*stat = IDMAP_SUCCESS;
862 		return (IDMAP_SUCCESS);
863 	}
864 
865 
866 	if (get_handle->mapping_num >= get_handle->mapping_size)
867 		kidmap_get_extend(get_handle);
868 
869 	mapping = &get_handle->mapping[get_handle->mapping_num];
870 	mapping->flag = 0;
871 	mapping->id1.idtype = IDMAP_SID;
872 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
873 	mapping->id1.idmap_id_u.sid.rid = rid;
874 	mapping->id2.idtype = IDMAP_POSIXID;
875 
876 	result = &get_handle->result[get_handle->mapping_num];
877 	result->idtype = IDMAP_POSIXID;
878 	result->uid = NULL;
879 	result->gid = NULL;
880 	result->pid = pid;
881 	result->sid_prefix = NULL;
882 	result->rid = NULL;
883 	result->is_user = is_user;
884 	result->stat = stat;
885 
886 	get_handle->mapping_num++;
887 
888 	return (IDMAP_SUCCESS);
889 }
890 
891 
892 /*
893  * Given UID, get SID and RID
894  *
895  * Input:
896  * uid  - POSIX UID
897  *
898  * Output:
899  * stat - status of the get request
900  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
901  * rid	- RID (if stat == IDMAP_SUCCESS)
902  *
903  * Note: The output parameters will be set by idmap_get_mappings()
904  */
905 idmap_stat
906 kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
907 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
908 {
909 	idmap_mapping	*mapping;
910 	idmap_get_res 	*result;
911 
912 	if (get_handle == NULL || sid_prefix == NULL ||
913 	    rid == NULL || stat == NULL)
914 		return (IDMAP_ERR_ARG);
915 
916 	if (kidmap_cache_lookup_sidbyuid(get_handle->cache, sid_prefix,
917 	    rid, uid) == IDMAP_SUCCESS) {
918 		*stat = IDMAP_SUCCESS;
919 		return (IDMAP_SUCCESS);
920 	}
921 
922 	if (get_handle->mapping_num >= get_handle->mapping_size)
923 		kidmap_get_extend(get_handle);
924 
925 	mapping = &get_handle->mapping[get_handle->mapping_num];
926 	mapping->flag = 0;
927 	mapping->id1.idtype = IDMAP_UID;
928 	mapping->id1.idmap_id_u.uid = uid;
929 	mapping->id2.idtype = IDMAP_SID;
930 
931 	result = &get_handle->result[get_handle->mapping_num];
932 	result->idtype = IDMAP_SID;
933 	result->uid = NULL;
934 	result->gid = NULL;
935 	result->pid = NULL;
936 	result->sid_prefix = sid_prefix;
937 	result->rid = rid;
938 	result->is_user = NULL;
939 	result->stat = stat;
940 
941 	get_handle->mapping_num++;
942 
943 	return (IDMAP_SUCCESS);
944 }
945 
946 
947 /*
948  * Given GID, get SID and RID
949  *
950  * Input:
951  * gid  - POSIX GID
952  *
953  * Output:
954  * stat - status of the get request
955  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
956  * rid	- RID (if stat == IDMAP_SUCCESS)
957  *
958  * Note: The output parameters will be set by idmap_get_mappings()
959  */
960 idmap_stat
961 kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
962 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
963 {
964 	idmap_mapping	*mapping;
965 	idmap_get_res 	*result;
966 
967 	if (get_handle == NULL || sid_prefix == NULL ||
968 	    rid == NULL || stat == NULL)
969 		return (IDMAP_ERR_ARG);
970 
971 	if (kidmap_cache_lookup_sidbygid(get_handle->cache, sid_prefix,
972 	    rid, gid) == IDMAP_SUCCESS) {
973 		*stat = IDMAP_SUCCESS;
974 		return (IDMAP_SUCCESS);
975 	}
976 
977 	if (get_handle->mapping_num >= get_handle->mapping_size)
978 		kidmap_get_extend(get_handle);
979 
980 	mapping = &get_handle->mapping[get_handle->mapping_num];
981 	mapping->flag = 0;
982 	mapping->id1.idtype = IDMAP_GID;
983 	mapping->id1.idmap_id_u.gid = gid;
984 	mapping->id2.idtype = IDMAP_SID;
985 
986 	result = &get_handle->result[get_handle->mapping_num];
987 	result->idtype = IDMAP_SID;
988 	result->uid = NULL;
989 	result->gid = NULL;
990 	result->pid = NULL;
991 	result->sid_prefix = sid_prefix;
992 	result->rid = rid;
993 	result->is_user = NULL;
994 	result->stat = stat;
995 
996 	get_handle->mapping_num++;
997 
998 	return (IDMAP_SUCCESS);
999 }
1000 
1001 
1002 /*
1003  * Process the batched "get mapping" requests. The results (i.e.
1004  * status and identity) will be available in the data areas
1005  * provided by individual requests.
1006  *
1007  * If the door call fails the status IDMAP_ERR_NOMAPPING is
1008  * return and the UID or UID result is set to "nobody"
1009  */
1010 
1011 idmap_stat
1012 kidmap_get_mappings(idmap_get_handle_t *get_handle)
1013 {
1014 	idmap_mapping_batch	args;
1015 	idmap_ids_res		results;
1016 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
1017 	idmap_mapping		*mapping;
1018 	idmap_get_res		*result;
1019 	idmap_id		*id;
1020 	int			status;
1021 	int			i;
1022 	const char		*sid_prefix;
1023 	int			is_user;
1024 
1025 	if (get_handle == NULL)
1026 		return (IDMAP_ERR_ARG);
1027 
1028 	if (get_handle->mapping_num == 0)
1029 		return (IDMAP_SUCCESS);
1030 
1031 	bzero(&results, sizeof (idmap_ids_res));
1032 
1033 	args.idmap_mapping_batch_len = get_handle->mapping_num;
1034 	args.idmap_mapping_batch_val = get_handle->mapping;
1035 
1036 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
1037 	    (caddr_t)&args, xdr_idmap_ids_res,
1038 	    (caddr_t)&results) == 0) {
1039 		/* Door call succeded */
1040 		status = IDMAP_SUCCESS;
1041 		for (i = 0; i < get_handle->mapping_num; i++) {
1042 			mapping = &get_handle->mapping[i];
1043 			result =  &get_handle->result[i];
1044 
1045 			if (i > results.ids.ids_len) {
1046 				*result->stat =	IDMAP_ERR_NOMAPPING;
1047 				if (result->uid)
1048 					*result->uid = UID_NOBODY;
1049 				if (result->gid)
1050 					*result->gid = GID_NOBODY;
1051 				if (result->pid)
1052 					*result->pid = UID_NOBODY;
1053 				if (result->is_user)
1054 					*result->is_user = 1;
1055 				if (result->sid_prefix)
1056 					*result->sid_prefix = NULL;
1057 				if (result->rid)
1058 					*result->rid = 0;
1059 				continue;
1060 			}
1061 			*result->stat = results.ids.ids_val[i].retcode;
1062 
1063 			id = &results.ids.ids_val[i].id;
1064 			switch (id->idtype) {
1065 			case IDMAP_UID:
1066 				if (result->uid)
1067 					*result->uid = id->idmap_id_u.uid;
1068 				if (result->pid)
1069 					*result->pid = id->idmap_id_u.uid;
1070 				if (result->is_user)
1071 					*result->is_user = 1;
1072 				sid_prefix = kidmap_find_sid_prefix(
1073 				    mapping->id1.idmap_id_u.sid.prefix);
1074 				if (*result->stat == IDMAP_SUCCESS &&
1075 				    result->uid)
1076 					kidmap_cache_add_uidbysid(
1077 					    get_handle->cache,
1078 					    sid_prefix,
1079 					    mapping->id1.idmap_id_u.sid.rid,
1080 					    id->idmap_id_u.uid);
1081 				else if (*result->stat == IDMAP_SUCCESS &&
1082 				    result->pid)
1083 					kidmap_cache_add_pidbysid(
1084 					    get_handle->cache,
1085 					    sid_prefix,
1086 					    mapping->id1.idmap_id_u.sid.rid,
1087 					    id->idmap_id_u.uid, 1);
1088 				break;
1089 
1090 			case IDMAP_GID:
1091 				if (result->gid)
1092 					*result->gid = id->idmap_id_u.gid;
1093 				if (result->pid)
1094 					*result->pid = id->idmap_id_u.gid;
1095 				if (result->is_user)
1096 					*result->is_user = 0;
1097 				sid_prefix = kidmap_find_sid_prefix(
1098 				    mapping->id1.idmap_id_u.sid.prefix);
1099 				if (*result->stat == IDMAP_SUCCESS &&
1100 				    result->gid)
1101 					kidmap_cache_add_gidbysid(
1102 					    get_handle->cache,
1103 					    sid_prefix,
1104 					    mapping->id1.idmap_id_u.sid.rid,
1105 					    id->idmap_id_u.gid);
1106 				else if (*result->stat == IDMAP_SUCCESS &&
1107 				    result->pid)
1108 					kidmap_cache_add_pidbysid(
1109 					    get_handle->cache,
1110 					    sid_prefix,
1111 					    mapping->id1.idmap_id_u.sid.rid,
1112 					    id->idmap_id_u.gid, 0);
1113 				break;
1114 
1115 			case IDMAP_SID:
1116 			case IDMAP_USID:
1117 			case IDMAP_GSID:
1118 				sid_prefix = kidmap_find_sid_prefix(
1119 				    id->idmap_id_u.sid.prefix);
1120 				if (result->sid_prefix && result->rid) {
1121 					*result->sid_prefix = sid_prefix;
1122 					*result->rid = id->idmap_id_u.sid.rid;
1123 				}
1124 				if (*result->stat == IDMAP_SUCCESS &&
1125 				    mapping->id1.idtype == IDMAP_UID)
1126 					kidmap_cache_add_sidbyuid(
1127 					    get_handle->cache,
1128 					    sid_prefix,
1129 					    id->idmap_id_u.sid.rid,
1130 					    mapping->id1.idmap_id_u.uid);
1131 				else if (*result->stat == IDMAP_SUCCESS &&
1132 				    mapping->id1.idtype == IDMAP_GID)
1133 					kidmap_cache_add_sidbygid(
1134 					    get_handle->cache,
1135 					    sid_prefix,
1136 					    id->idmap_id_u.sid.rid,
1137 					    mapping->id1.idmap_id_u.gid);
1138 				break;
1139 
1140 			default:
1141 				*result->stat = IDMAP_ERR_NORESULT;
1142 				if (result->uid)
1143 					*result->uid = UID_NOBODY;
1144 				if (result->gid)
1145 					*result->gid = GID_NOBODY;
1146 				if (result->pid)
1147 					*result->pid = UID_NOBODY;
1148 				if (result->is_user)
1149 					*result->is_user = 1;
1150 				if (result->sid_prefix)
1151 					*result->sid_prefix = NULL;
1152 				if (result->rid)
1153 					*result->rid = 0;
1154 				break;
1155 			}
1156 		}
1157 		xdr_free(xdr_idmap_ids_res, (char *)&results);
1158 	} else {
1159 		/* Door call failed */
1160 		status = IDMAP_ERR_NOMAPPING;
1161 		for (i = 0; i < get_handle->mapping_num; i++) {
1162 			result =  &get_handle->result[i];
1163 
1164 			*result->stat = IDMAP_ERR_NOMAPPING;
1165 			if (result->uid)
1166 				*result->uid = UID_NOBODY;
1167 			if (result->gid)
1168 				*result->gid = GID_NOBODY;
1169 			if (result->pid)
1170 				*result->pid = UID_NOBODY;
1171 			if (result->is_user)
1172 				*result->is_user = 1;
1173 			if (result->sid_prefix)
1174 				*result->sid_prefix = NULL;
1175 			if (result->rid)
1176 				*result->rid = 0;
1177 		}
1178 	}
1179 
1180 	/* Reset get_handle for new resquests */
1181 	get_handle->mapping_num = 0;
1182 	return (status);
1183 }
1184 
1185 
1186 /*
1187  * Destroy the "get mapping" handle
1188  */
1189 void
1190 kidmap_get_destroy(idmap_get_handle_t *get_handle)
1191 {
1192 	if (get_handle == NULL)
1193 		return;
1194 
1195 	kmem_free(get_handle->mapping,
1196 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
1197 	get_handle->mapping = NULL;
1198 
1199 	kmem_free(get_handle->result,
1200 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
1201 	get_handle->result = NULL;
1202 
1203 	kmem_free(get_handle, sizeof (idmap_get_handle_t));
1204 }
1205 
1206 
1207 static int
1208 kidmap_rpc_call(uint32_t op, xdrproc_t xdr_args, caddr_t args,
1209 		xdrproc_t xdr_res, caddr_t res)
1210 {
1211 	XDR		xdr_ctx;
1212 	struct	rpc_msg reply_msg;
1213 	char		*inbuf_ptr = NULL;
1214 	size_t		inbuf_size = 4096;
1215 	char		*outbuf_ptr = NULL;
1216 	size_t 		outbuf_size = 4096;
1217 	size_t		size;
1218 	int		status = 0;
1219 	door_arg_t	params;
1220 	int 		retry = 0;
1221 
1222 	params.rbuf = NULL;
1223 	params.rsize = 0;
1224 
1225 retry:
1226 	inbuf_ptr = kmem_alloc(inbuf_size, KM_SLEEP);
1227 	outbuf_ptr = kmem_alloc(outbuf_size, KM_SLEEP);
1228 
1229 	xdrmem_create(&xdr_ctx, inbuf_ptr, inbuf_size, XDR_ENCODE);
1230 	atomic_inc_32(&call_msg.rm_xid);
1231 	if (!xdr_callhdr(&xdr_ctx, &call_msg)) {
1232 #ifdef	DEBUG
1233 		cmn_err(CE_WARN, "idmap: xdr encoding header error");
1234 #endif	/* DEBUG */
1235 		status = -1;
1236 		goto exit;
1237 	}
1238 
1239 	if (!xdr_uint32(&xdr_ctx, &op) ||
1240 	    /* Auth none */
1241 	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1242 	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1243 	    /* RPC args */
1244 	    !xdr_args(&xdr_ctx, args)) {
1245 #ifdef	DEBUG
1246 		cmn_err(CE_WARN, "idmap: xdr encoding error");
1247 #endif	/* DEBUG */
1248 		if (retry > 2) {
1249 			status = -1;
1250 			goto exit;
1251 		}
1252 		retry++;
1253 		if (inbuf_ptr) {
1254 			kmem_free(inbuf_ptr, inbuf_size);
1255 			inbuf_ptr = NULL;
1256 		}
1257 		if (outbuf_ptr) {
1258 			kmem_free(outbuf_ptr, outbuf_size);
1259 			outbuf_ptr = NULL;
1260 		}
1261 		if ((size = xdr_sizeof(xdr_args, args)) == 0) {
1262 #ifdef	DEBUG
1263 			cmn_err(CE_WARN, "idmap: xdr_sizeof error");
1264 #endif	/* DEBUG */
1265 			status = -1;
1266 			goto exit;
1267 		}
1268 		inbuf_size = size + 1024;
1269 		outbuf_size = size + 1024;
1270 		goto retry;
1271 	}
1272 
1273 	params.data_ptr = inbuf_ptr;
1274 	params.data_size = XDR_GETPOS(&xdr_ctx);
1275 	params.desc_ptr = NULL;
1276 	params.desc_num = 0;
1277 	params.rbuf = outbuf_ptr;
1278 	params.rsize = outbuf_size;
1279 
1280 	if (kidmap_call_door(&params) != 0) {
1281 		status = -1;
1282 		goto exit;
1283 	}
1284 
1285 	reply_msg.acpted_rply.ar_verf = _null_auth;
1286 	reply_msg.acpted_rply.ar_results.where = res;
1287 	reply_msg.acpted_rply.ar_results.proc = xdr_res;
1288 	xdrmem_create(&xdr_ctx, params.data_ptr, params.data_size, XDR_DECODE);
1289 	if (xdr_replymsg(&xdr_ctx, &reply_msg)) {
1290 		if (reply_msg.rm_reply.rp_stat != MSG_ACCEPTED ||
1291 		    reply_msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
1292 			status = -1;
1293 			goto exit;
1294 		}
1295 	} else {
1296 #ifdef	DEBUG
1297 		cmn_err(CE_WARN, "idmap: xdr decoding reply message error");
1298 #endif	/* DEBUG */
1299 		status = -1;
1300 	}
1301 
1302 exit:
1303 	if (outbuf_ptr != params.rbuf && params.rbuf != NULL)
1304 		kmem_free(params.rbuf, params.rsize);
1305 	if (inbuf_ptr)
1306 		kmem_free(inbuf_ptr, inbuf_size);
1307 	if (outbuf_ptr)
1308 		kmem_free(outbuf_ptr, outbuf_size);
1309 	return (status);
1310 }
1311