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