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