xref: /illumos-gate/usr/src/uts/common/idmap/idmap_kapi.c (revision a194faf8907a6722dcf10ad16c6ca72c9b7bd0ba)
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 			status = results.ids.ids_val[0].retcode;
562 			id = &results.ids.ids_val[0].id;
563 			*sid_prefix = kidmap_find_sid_prefix(
564 			    id->idmap_id_u.sid.prefix);
565 			*rid = id->idmap_id_u.sid.rid;
566 			if (status == IDMAP_SUCCESS) {
567 				kidmap_cache_add_sidbyuid(&idmap_cache,
568 				    *sid_prefix, *rid, uid);
569 			}
570 		} else {
571 			status = IDMAP_ERR_NOMAPPING;
572 			*rid = 0;
573 			*sid_prefix = NULL;
574 		}
575 		xdr_free(xdr_idmap_ids_res, (char *)&results);
576 	} else {
577 		/* Door call failed */
578 		status = IDMAP_ERR_NOMAPPING;
579 		*rid = 0;
580 		*sid_prefix = NULL;
581 	}
582 	return (status);
583 }
584 
585 
586 /*
587  * Given GID, get Domain SID and RID
588  *
589  * Input:
590  * gid - Posix GID
591  *
592  * Output:
593  * sid_prefix	- Domain SID if return == IDMAP_SUCCESS
594  * rid	- RID if return == IDMAP_SUCCESS
595  *
596  * Return:
597  * Success return IDMAP_SUCCESS else IDMAP error
598  */
599 idmap_stat
600 kidmap_getsidbygid(gid_t gid, const char **sid_prefix, uint32_t *rid)
601 {
602 	idmap_mapping_batch	args;
603 	idmap_mapping		mapping;
604 	idmap_ids_res		results;
605 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
606 	idmap_stat		status;
607 	idmap_id		*id;
608 
609 	if (sid_prefix == NULL || rid == NULL)
610 		return (IDMAP_ERR_ARG);
611 
612 	if (kidmap_cache_lookup_sidbygid(&idmap_cache, sid_prefix, rid, gid)
613 	    == IDMAP_SUCCESS) {
614 		return (IDMAP_SUCCESS);
615 	}
616 
617 	bzero(&mapping, sizeof (idmap_mapping));
618 	mapping.id1.idtype = IDMAP_GID;
619 	mapping.id1.idmap_id_u.uid = gid;
620 	mapping.id2.idtype = IDMAP_SID;
621 
622 	bzero(&results, sizeof (idmap_ids_res));
623 
624 	args.idmap_mapping_batch_len = 1;
625 	args.idmap_mapping_batch_val = &mapping;
626 
627 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
628 	    (caddr_t)&args, xdr_idmap_ids_res,
629 	    (caddr_t)&results) == 0) {
630 		/* Door call succeded */
631 		if (results.ids.ids_len >= 1 &&
632 		    results.ids.ids_val[0].id.idtype == IDMAP_SID) {
633 			status = results.ids.ids_val[0].retcode;
634 			id = &results.ids.ids_val[0].id;
635 			*sid_prefix = kidmap_find_sid_prefix(
636 			    id->idmap_id_u.sid.prefix);
637 			*rid = id->idmap_id_u.sid.rid;
638 			if (status == IDMAP_SUCCESS) {
639 				kidmap_cache_add_sidbygid(&idmap_cache,
640 				    *sid_prefix, *rid, gid);
641 			}
642 		} else {
643 			status = IDMAP_ERR_NOMAPPING;
644 			*rid = 0;
645 			*sid_prefix = NULL;
646 		}
647 		xdr_free(xdr_idmap_ids_res, (char *)&results);
648 	} else {
649 		/* Door call failed */
650 		status = IDMAP_ERR_NOMAPPING;
651 		*rid = 0;
652 		*sid_prefix = NULL;
653 	}
654 	return (status);
655 }
656 
657 /*
658  * Create handle to get SID to UID/GID mapping entries
659  *
660  * Input:
661  * 	none
662  * Return:
663  *	get_handle
664  *
665  */
666 idmap_get_handle_t *
667 kidmap_get_create(void)
668 {
669 	idmap_get_handle_t *handle;
670 #define	INIT_MAPPING_SIZE	6
671 
672 	handle = kmem_zalloc(sizeof (idmap_get_handle_t), KM_SLEEP);
673 
674 	handle->mapping = kmem_zalloc((sizeof (idmap_mapping)) *
675 	    INIT_MAPPING_SIZE, KM_SLEEP);
676 
677 	handle->result = kmem_zalloc((sizeof (idmap_get_res)) *
678 	    INIT_MAPPING_SIZE, KM_SLEEP);
679 	handle->mapping_size = INIT_MAPPING_SIZE;
680 	handle->cache = &idmap_cache;
681 
682 	return (handle);
683 }
684 
685 /*
686  * Internal routine to extend a "get_handle"
687  */
688 static void
689 kidmap_get_extend(idmap_get_handle_t *get_handle)
690 {
691 	idmap_mapping *mapping;
692 	idmap_get_res *result;
693 	int new_size = get_handle->mapping_size + INIT_MAPPING_SIZE;
694 
695 	mapping = kmem_zalloc((sizeof (idmap_mapping)) *
696 	    new_size, KM_SLEEP);
697 	(void) memcpy(mapping, get_handle->mapping,
698 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
699 
700 	result = kmem_zalloc((sizeof (idmap_get_res)) *
701 	    new_size, KM_SLEEP);
702 	(void) memcpy(result, get_handle->result,
703 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
704 
705 	kmem_free(get_handle->mapping,
706 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
707 	get_handle->mapping = mapping;
708 
709 	kmem_free(get_handle->result,
710 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
711 	get_handle->result = result;
712 
713 	get_handle->mapping_size = new_size;
714 }
715 
716 
717 /*
718  * Given Domain SID and RID, get UID
719  *
720  * Input:
721  * sid_prefix	- Domain SID in canonical form
722  * rid	- RID
723  *
724  * Output:
725  * stat - status of the get request
726  * uid  - POSIX UID if stat == IDMAP_SUCCESS
727  *
728  * Note: The output parameters will be set by idmap_get_mappings()
729  */
730 idmap_stat
731 kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
732 			uint32_t rid, uid_t *uid, idmap_stat *stat)
733 {
734 	idmap_mapping	*mapping;
735 	idmap_get_res 	*result;
736 
737 	if (get_handle == NULL || sid_prefix == NULL ||
738 	    uid == NULL || stat == NULL)
739 		return (IDMAP_ERR_ARG);
740 
741 	if (kidmap_cache_lookup_uidbysid(get_handle->cache, sid_prefix,
742 	    rid, uid) == IDMAP_SUCCESS) {
743 		*stat = IDMAP_SUCCESS;
744 		return (IDMAP_SUCCESS);
745 	}
746 
747 	if (get_handle->mapping_num >= get_handle->mapping_size)
748 		kidmap_get_extend(get_handle);
749 
750 	mapping = &get_handle->mapping[get_handle->mapping_num];
751 	mapping->flag = 0;
752 	mapping->id1.idtype = IDMAP_SID;
753 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
754 	mapping->id1.idmap_id_u.sid.rid = rid;
755 	mapping->id2.idtype = IDMAP_UID;
756 
757 	result = &get_handle->result[get_handle->mapping_num];
758 	result->idtype = IDMAP_UID;
759 	result->uid = uid;
760 	result->gid = NULL;
761 	result->pid = NULL;
762 	result->sid_prefix = NULL;
763 	result->rid = NULL;
764 	result->is_user = NULL;
765 	result->stat = stat;
766 
767 	get_handle->mapping_num++;
768 
769 	return (IDMAP_SUCCESS);
770 }
771 
772 
773 /*
774  * Given Domain SID and RID, get GID
775  *
776  * Input:
777  * sid_prefix	- Domain SID in canonical form
778  * rid	- RID
779  *
780  * Output:
781  * stat - status of the get request
782  * gid  - POSIX GID if stat == IDMAP_SUCCESS
783  *
784  * Note: The output parameters will be set by idmap_get_mappings()
785  */
786 idmap_stat
787 kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
788 			uint32_t rid, uid_t *gid, idmap_stat *stat)
789 {
790 	idmap_mapping	*mapping;
791 	idmap_get_res 	*result;
792 
793 	if (get_handle == NULL || sid_prefix == NULL ||
794 	    gid == NULL || stat == NULL)
795 		return (IDMAP_ERR_ARG);
796 
797 	if (kidmap_cache_lookup_gidbysid(get_handle->cache, sid_prefix,
798 	    rid, gid) == IDMAP_SUCCESS) {
799 		*stat = IDMAP_SUCCESS;
800 		return (IDMAP_SUCCESS);
801 	}
802 
803 	if (get_handle->mapping_num >= get_handle->mapping_size)
804 		kidmap_get_extend(get_handle);
805 
806 	mapping = &get_handle->mapping[get_handle->mapping_num];
807 	mapping->flag = 0;
808 	mapping->id1.idtype = IDMAP_SID;
809 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
810 	mapping->id1.idmap_id_u.sid.rid = rid;
811 	mapping->id2.idtype = IDMAP_GID;
812 
813 	result = &get_handle->result[get_handle->mapping_num];
814 	result->idtype = IDMAP_GID;
815 	result->uid = NULL;
816 	result->gid = gid;
817 	result->pid = NULL;
818 	result->sid_prefix = NULL;
819 	result->rid = NULL;
820 	result->is_user = NULL;
821 	result->stat = stat;
822 
823 	get_handle->mapping_num++;
824 
825 	return (IDMAP_SUCCESS);
826 }
827 
828 
829 /*
830  * Given Domain SID and RID, get Posix ID
831  *
832  * Input:
833  * sid_prefix	- Domain SID in canonical form
834  * rid	- RID
835  *
836  * Output:
837  * stat    - status of the get request
838  * is_user - user or group
839  * pid     - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
840  *           POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
841  *
842  * Note: The output parameters will be set by idmap_get_mappings()
843  */
844 idmap_stat
845 kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
846 		uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
847 {
848 	idmap_mapping	*mapping;
849 	idmap_get_res 	*result;
850 
851 	if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
852 	    is_user == NULL || stat == NULL)
853 		return (IDMAP_ERR_ARG);
854 
855 	if (kidmap_cache_lookup_pidbysid(get_handle->cache, sid_prefix,
856 	    rid, pid, is_user) == IDMAP_SUCCESS) {
857 		*stat = IDMAP_SUCCESS;
858 		return (IDMAP_SUCCESS);
859 	}
860 
861 
862 	if (get_handle->mapping_num >= get_handle->mapping_size)
863 		kidmap_get_extend(get_handle);
864 
865 	mapping = &get_handle->mapping[get_handle->mapping_num];
866 	mapping->flag = 0;
867 	mapping->id1.idtype = IDMAP_SID;
868 	mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
869 	mapping->id1.idmap_id_u.sid.rid = rid;
870 	mapping->id2.idtype = IDMAP_POSIXID;
871 
872 	result = &get_handle->result[get_handle->mapping_num];
873 	result->idtype = IDMAP_POSIXID;
874 	result->uid = NULL;
875 	result->gid = NULL;
876 	result->pid = pid;
877 	result->sid_prefix = NULL;
878 	result->rid = NULL;
879 	result->is_user = is_user;
880 	result->stat = stat;
881 
882 	get_handle->mapping_num++;
883 
884 	return (IDMAP_SUCCESS);
885 }
886 
887 
888 /*
889  * Given UID, get SID and RID
890  *
891  * Input:
892  * uid  - POSIX UID
893  *
894  * Output:
895  * stat - status of the get request
896  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
897  * rid	- RID (if stat == IDMAP_SUCCESS)
898  *
899  * Note: The output parameters will be set by idmap_get_mappings()
900  */
901 idmap_stat
902 kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
903 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
904 {
905 	idmap_mapping	*mapping;
906 	idmap_get_res 	*result;
907 
908 	if (get_handle == NULL || sid_prefix == NULL ||
909 	    rid == NULL || stat == NULL)
910 		return (IDMAP_ERR_ARG);
911 
912 	if (kidmap_cache_lookup_sidbyuid(get_handle->cache, sid_prefix,
913 	    rid, uid) == IDMAP_SUCCESS) {
914 		*stat = IDMAP_SUCCESS;
915 		return (IDMAP_SUCCESS);
916 	}
917 
918 	if (get_handle->mapping_num >= get_handle->mapping_size)
919 		kidmap_get_extend(get_handle);
920 
921 	mapping = &get_handle->mapping[get_handle->mapping_num];
922 	mapping->flag = 0;
923 	mapping->id1.idtype = IDMAP_UID;
924 	mapping->id1.idmap_id_u.uid = uid;
925 	mapping->id2.idtype = IDMAP_SID;
926 
927 	result = &get_handle->result[get_handle->mapping_num];
928 	result->idtype = IDMAP_SID;
929 	result->uid = NULL;
930 	result->gid = NULL;
931 	result->pid = NULL;
932 	result->sid_prefix = sid_prefix;
933 	result->rid = rid;
934 	result->is_user = NULL;
935 	result->stat = stat;
936 
937 	get_handle->mapping_num++;
938 
939 	return (IDMAP_SUCCESS);
940 }
941 
942 
943 /*
944  * Given GID, get SID and RID
945  *
946  * Input:
947  * gid  - POSIX GID
948  *
949  * Output:
950  * stat - status of the get request
951  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
952  * rid	- RID (if stat == IDMAP_SUCCESS)
953  *
954  * Note: The output parameters will be set by idmap_get_mappings()
955  */
956 idmap_stat
957 kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
958 		const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
959 {
960 	idmap_mapping	*mapping;
961 	idmap_get_res 	*result;
962 
963 	if (get_handle == NULL || sid_prefix == NULL ||
964 	    rid == NULL || stat == NULL)
965 		return (IDMAP_ERR_ARG);
966 
967 	if (kidmap_cache_lookup_sidbygid(get_handle->cache, sid_prefix,
968 	    rid, gid) == IDMAP_SUCCESS) {
969 		*stat = IDMAP_SUCCESS;
970 		return (IDMAP_SUCCESS);
971 	}
972 
973 	if (get_handle->mapping_num >= get_handle->mapping_size)
974 		kidmap_get_extend(get_handle);
975 
976 	mapping = &get_handle->mapping[get_handle->mapping_num];
977 	mapping->flag = 0;
978 	mapping->id1.idtype = IDMAP_GID;
979 	mapping->id1.idmap_id_u.gid = gid;
980 	mapping->id2.idtype = IDMAP_SID;
981 
982 	result = &get_handle->result[get_handle->mapping_num];
983 	result->idtype = IDMAP_SID;
984 	result->uid = NULL;
985 	result->gid = NULL;
986 	result->pid = NULL;
987 	result->sid_prefix = sid_prefix;
988 	result->rid = rid;
989 	result->is_user = NULL;
990 	result->stat = stat;
991 
992 	get_handle->mapping_num++;
993 
994 	return (IDMAP_SUCCESS);
995 }
996 
997 
998 /*
999  * Process the batched "get mapping" requests. The results (i.e.
1000  * status and identity) will be available in the data areas
1001  * provided by individual requests.
1002  *
1003  * If the door call fails the status IDMAP_ERR_NOMAPPING is
1004  * return and the UID or UID result is set to "nobody"
1005  */
1006 
1007 idmap_stat
1008 kidmap_get_mappings(idmap_get_handle_t *get_handle)
1009 {
1010 	idmap_mapping_batch	args;
1011 	idmap_ids_res		results;
1012 	uint32_t		op = IDMAP_GET_MAPPED_IDS;
1013 	idmap_mapping		*mapping;
1014 	idmap_get_res		*result;
1015 	idmap_id		*id;
1016 	int			status;
1017 	int			i;
1018 	const char		*sid_prefix;
1019 	int			is_user;
1020 
1021 	if (get_handle == NULL)
1022 		return (IDMAP_ERR_ARG);
1023 
1024 	if (get_handle->mapping_num == 0)
1025 		return (IDMAP_SUCCESS);
1026 
1027 	bzero(&results, sizeof (idmap_ids_res));
1028 
1029 	args.idmap_mapping_batch_len = get_handle->mapping_num;
1030 	args.idmap_mapping_batch_val = get_handle->mapping;
1031 
1032 	if (kidmap_rpc_call(op, xdr_idmap_mapping_batch,
1033 	    (caddr_t)&args, xdr_idmap_ids_res,
1034 	    (caddr_t)&results) == 0) {
1035 		/* Door call succeded */
1036 		status = IDMAP_SUCCESS;
1037 		for (i = 0; i < get_handle->mapping_num; i++) {
1038 			mapping = &get_handle->mapping[i];
1039 			result =  &get_handle->result[i];
1040 
1041 			if (i > results.ids.ids_len) {
1042 				*result->stat =	IDMAP_ERR_NOMAPPING;
1043 				if (result->uid)
1044 					*result->uid = UID_NOBODY;
1045 				if (result->gid)
1046 					*result->gid = GID_NOBODY;
1047 				if (result->pid)
1048 					*result->pid = UID_NOBODY;
1049 				if (result->is_user)
1050 					*result->is_user = 1;
1051 				if (result->sid_prefix)
1052 					*result->sid_prefix = NULL;
1053 				if (result->rid)
1054 					*result->rid = 0;
1055 				continue;
1056 			}
1057 			*result->stat = results.ids.ids_val[i].retcode;
1058 
1059 			id = &results.ids.ids_val[i].id;
1060 			switch (id->idtype) {
1061 			case IDMAP_UID:
1062 				if (result->uid)
1063 					*result->uid = id->idmap_id_u.uid;
1064 				if (result->pid)
1065 					*result->pid = id->idmap_id_u.uid;
1066 				if (result->is_user)
1067 					*result->is_user = 1;
1068 				sid_prefix = kidmap_find_sid_prefix(
1069 				    mapping->id1.idmap_id_u.sid.prefix);
1070 				if (*result->stat == IDMAP_SUCCESS &&
1071 				    result->uid)
1072 					kidmap_cache_add_uidbysid(
1073 					    get_handle->cache,
1074 					    sid_prefix,
1075 					    mapping->id1.idmap_id_u.sid.rid,
1076 					    id->idmap_id_u.uid);
1077 				else if (*result->stat == IDMAP_SUCCESS &&
1078 				    result->pid)
1079 					kidmap_cache_add_pidbysid(
1080 					    get_handle->cache,
1081 					    sid_prefix,
1082 					    mapping->id1.idmap_id_u.sid.rid,
1083 					    id->idmap_id_u.uid, 1);
1084 				break;
1085 
1086 			case IDMAP_GID:
1087 				if (result->gid)
1088 					*result->gid = id->idmap_id_u.gid;
1089 				if (result->pid)
1090 					*result->pid = id->idmap_id_u.gid;
1091 				if (result->is_user)
1092 					*result->is_user = 0;
1093 				sid_prefix = kidmap_find_sid_prefix(
1094 				    mapping->id1.idmap_id_u.sid.prefix);
1095 				if (*result->stat == IDMAP_SUCCESS &&
1096 				    result->gid)
1097 					kidmap_cache_add_gidbysid(
1098 					    get_handle->cache,
1099 					    sid_prefix,
1100 					    mapping->id1.idmap_id_u.sid.rid,
1101 					    id->idmap_id_u.gid);
1102 				else if (*result->stat == IDMAP_SUCCESS &&
1103 				    result->pid)
1104 					kidmap_cache_add_pidbysid(
1105 					    get_handle->cache,
1106 					    sid_prefix,
1107 					    mapping->id1.idmap_id_u.sid.rid,
1108 					    id->idmap_id_u.gid, 0);
1109 				break;
1110 
1111 			case IDMAP_SID:
1112 				sid_prefix = kidmap_find_sid_prefix(
1113 				    id->idmap_id_u.sid.prefix);
1114 				if (result->sid_prefix && result->rid) {
1115 					*result->sid_prefix = sid_prefix;
1116 					*result->rid = id->idmap_id_u.sid.rid;
1117 				}
1118 				if (*result->stat == IDMAP_SUCCESS &&
1119 				    mapping->id1.idtype == IDMAP_UID)
1120 					kidmap_cache_add_sidbyuid(
1121 					    get_handle->cache,
1122 					    sid_prefix,
1123 					    id->idmap_id_u.sid.rid,
1124 					    mapping->id1.idmap_id_u.uid);
1125 				else if (*result->stat == IDMAP_SUCCESS &&
1126 				    mapping->id1.idtype == IDMAP_GID)
1127 					kidmap_cache_add_sidbygid(
1128 					    get_handle->cache,
1129 					    sid_prefix,
1130 					    id->idmap_id_u.sid.rid,
1131 					    mapping->id1.idmap_id_u.gid);
1132 				break;
1133 
1134 			default:
1135 				*result->stat = IDMAP_ERR_NORESULT;
1136 				if (result->uid)
1137 					*result->uid = UID_NOBODY;
1138 				if (result->gid)
1139 					*result->gid = GID_NOBODY;
1140 				if (result->pid)
1141 					*result->pid = UID_NOBODY;
1142 				if (result->is_user)
1143 					*result->is_user = 1;
1144 				if (result->sid_prefix)
1145 					*result->sid_prefix = NULL;
1146 				if (result->rid)
1147 					*result->rid = 0;
1148 				break;
1149 			}
1150 		}
1151 		xdr_free(xdr_idmap_ids_res, (char *)&results);
1152 	} else {
1153 		/* Door call failed */
1154 		status = IDMAP_ERR_NOMAPPING;
1155 		for (i = 0; i < get_handle->mapping_num; i++) {
1156 			result =  &get_handle->result[i];
1157 
1158 			*result->stat = IDMAP_ERR_NOMAPPING;
1159 			if (result->uid)
1160 				*result->uid = UID_NOBODY;
1161 			if (result->gid)
1162 				*result->gid = GID_NOBODY;
1163 			if (result->pid)
1164 				*result->pid = UID_NOBODY;
1165 			if (result->is_user)
1166 				*result->is_user = 1;
1167 			if (result->sid_prefix)
1168 				*result->sid_prefix = NULL;
1169 			if (result->rid)
1170 				*result->rid = 0;
1171 		}
1172 	}
1173 
1174 	/* Reset get_handle for new resquests */
1175 	get_handle->mapping_num = 0;
1176 	return (status);
1177 }
1178 
1179 
1180 /*
1181  * Destroy the "get mapping" handle
1182  */
1183 void
1184 kidmap_get_destroy(idmap_get_handle_t *get_handle)
1185 {
1186 	if (get_handle == NULL)
1187 		return;
1188 
1189 	kmem_free(get_handle->mapping,
1190 	    (sizeof (idmap_mapping)) * get_handle->mapping_size);
1191 	get_handle->mapping = NULL;
1192 
1193 	kmem_free(get_handle->result,
1194 	    (sizeof (idmap_get_res)) * get_handle->mapping_size);
1195 	get_handle->result = NULL;
1196 
1197 	kmem_free(get_handle, sizeof (idmap_get_handle_t));
1198 }
1199 
1200 
1201 static int
1202 kidmap_rpc_call(uint32_t op, xdrproc_t xdr_args, caddr_t args,
1203 		xdrproc_t xdr_res, caddr_t res)
1204 {
1205 	XDR		xdr_ctx;
1206 	struct	rpc_msg reply_msg;
1207 	char		*inbuf_ptr = NULL;
1208 	size_t		inbuf_size = 4096;
1209 	char		*outbuf_ptr = NULL;
1210 	size_t 		outbuf_size = 4096;
1211 	size_t		size;
1212 	int		status = 0;
1213 	door_arg_t	params;
1214 	int 		retry = 0;
1215 
1216 	params.rbuf = NULL;
1217 	params.rsize = 0;
1218 
1219 retry:
1220 	inbuf_ptr = kmem_alloc(inbuf_size, KM_SLEEP);
1221 	outbuf_ptr = kmem_alloc(outbuf_size, KM_SLEEP);
1222 
1223 	xdrmem_create(&xdr_ctx, inbuf_ptr, inbuf_size, XDR_ENCODE);
1224 	atomic_inc_32(&call_msg.rm_xid);
1225 	if (!xdr_callhdr(&xdr_ctx, &call_msg)) {
1226 #ifdef	DEBUG
1227 		cmn_err(CE_WARN, "idmap: xdr encoding header error");
1228 #endif	/* DEBUG */
1229 		status = -1;
1230 		goto exit;
1231 	}
1232 
1233 	if (!xdr_uint32(&xdr_ctx, &op) ||
1234 	    /* Auth none */
1235 	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1236 	    !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1237 	    /* RPC args */
1238 	    !xdr_args(&xdr_ctx, args)) {
1239 #ifdef	DEBUG
1240 		cmn_err(CE_WARN, "idmap: xdr encoding error");
1241 #endif	/* DEBUG */
1242 		if (retry > 2) {
1243 			status = -1;
1244 			goto exit;
1245 		}
1246 		retry++;
1247 		if (inbuf_ptr) {
1248 			kmem_free(inbuf_ptr, inbuf_size);
1249 			inbuf_ptr = NULL;
1250 		}
1251 		if (outbuf_ptr) {
1252 			kmem_free(outbuf_ptr, outbuf_size);
1253 			outbuf_ptr = NULL;
1254 		}
1255 		if ((size = xdr_sizeof(xdr_args, args)) == 0) {
1256 #ifdef	DEBUG
1257 			cmn_err(CE_WARN, "idmap: xdr_sizeof error");
1258 #endif	/* DEBUG */
1259 			status = -1;
1260 			goto exit;
1261 		}
1262 		inbuf_size = size + 1024;
1263 		outbuf_size = size + 1024;
1264 		goto retry;
1265 	}
1266 
1267 	params.data_ptr = inbuf_ptr;
1268 	params.data_size = XDR_GETPOS(&xdr_ctx);
1269 	params.desc_ptr = NULL;
1270 	params.desc_num = 0;
1271 	params.rbuf = outbuf_ptr;
1272 	params.rsize = outbuf_size;
1273 
1274 	if (kidmap_call_door(&params) != 0) {
1275 		status = -1;
1276 		goto exit;
1277 	}
1278 
1279 	reply_msg.acpted_rply.ar_verf = _null_auth;
1280 	reply_msg.acpted_rply.ar_results.where = res;
1281 	reply_msg.acpted_rply.ar_results.proc = xdr_res;
1282 	xdrmem_create(&xdr_ctx, params.data_ptr, params.data_size, XDR_DECODE);
1283 	if (xdr_replymsg(&xdr_ctx, &reply_msg)) {
1284 		if (reply_msg.rm_reply.rp_stat != MSG_ACCEPTED ||
1285 		    reply_msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
1286 			status = -1;
1287 			goto exit;
1288 		}
1289 	} else {
1290 #ifdef	DEBUG
1291 		cmn_err(CE_WARN, "idmap: xdr decoding reply message error");
1292 #endif	/* DEBUG */
1293 		status = -1;
1294 	}
1295 
1296 exit:
1297 	if (outbuf_ptr != params.rbuf && params.rbuf != NULL)
1298 		kmem_free(params.rbuf, params.rsize);
1299 	if (inbuf_ptr)
1300 		kmem_free(inbuf_ptr, inbuf_size);
1301 	if (outbuf_ptr)
1302 		kmem_free(outbuf_ptr, outbuf_size);
1303 	return (status);
1304 }
1305