xref: /illumos-gate/usr/src/uts/common/os/cred.c (revision f48205be)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*
30  * University Copyright- Copyright (c) 1982, 1986, 1988
31  * The Regents of the University of California
32  * All Rights Reserved
33  *
34  * University Acknowledgment- Portions of this document are derived from
35  * software developed by the University of California, Berkeley, and its
36  * contributors.
37  */
38 
39 #pragma ident	"%Z%%M%	%I%	%E% SMI"
40 
41 #include <sys/types.h>
42 #include <sys/sysmacros.h>
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/cred_impl.h>
46 #include <sys/policy.h>
47 #include <sys/vnode.h>
48 #include <sys/errno.h>
49 #include <sys/kmem.h>
50 #include <sys/user.h>
51 #include <sys/proc.h>
52 #include <sys/syscall.h>
53 #include <sys/debug.h>
54 #include <sys/atomic.h>
55 #include <sys/ucred.h>
56 #include <sys/prsystm.h>
57 #include <sys/modctl.h>
58 #include <sys/avl.h>
59 #include <c2/audit.h>
60 #include <sys/zone.h>
61 #include <sys/tsol/label.h>
62 #include <sys/sid.h>
63 
64 typedef struct ephidmap_data {
65 	uid_t		min_uid, last_uid;
66 	gid_t		min_gid, last_gid;
67 	cred_t		*nobody;
68 	kmutex_t	eph_lock;
69 } ephidmap_data_t;
70 
71 static struct kmem_cache *cred_cache;
72 static size_t crsize = 0;
73 static int audoff = 0;
74 uint32_t ucredsize;
75 cred_t *kcred;
76 static cred_t *dummycr;
77 
78 int rstlink;		/* link(2) restricted to files owned by user? */
79 
80 static int get_c2audit_load(void);
81 
82 #define	CR_AUINFO(c)	(auditinfo_addr_t *)((audoff == 0) ? NULL : \
83 			    ((char *)(c)) + audoff)
84 
85 #define	REMOTE_PEER_CRED(c)	((c)->cr_gid == -1)
86 
87 /*
88  * XXX: should be per-zone.
89  * Start with an invalid value for atomic increments.
90  */
91 static ephidmap_data_t ephemeral_data = {
92 	MAXUID, MAXUID, MAXUID, MAXUID
93 };
94 
95 static boolean_t hasephids = B_FALSE;
96 
97 /*
98  * Initialize credentials data structures.
99  */
100 
101 void
102 cred_init(void)
103 {
104 	priv_init();
105 
106 	crsize = sizeof (cred_t) + sizeof (gid_t) * (ngroups_max - 1);
107 	/*
108 	 * Make sure it's word-aligned.
109 	 */
110 	crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
111 
112 	if (get_c2audit_load() > 0) {
113 #ifdef _LP64
114 		/* assure audit context is 64-bit aligned */
115 		audoff = (crsize +
116 		    sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
117 #else	/* _LP64 */
118 		audoff = crsize;
119 #endif	/* _LP64 */
120 		crsize = audoff + sizeof (auditinfo_addr_t);
121 		crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
122 	}
123 
124 	cred_cache = kmem_cache_create("cred_cache", crsize, 0,
125 		NULL, NULL, NULL, NULL, NULL, 0);
126 
127 	/*
128 	 * dummycr is used to copy initial state for creds.
129 	 */
130 	dummycr = cralloc();
131 	bzero(dummycr, crsize);
132 	dummycr->cr_ref = 1;
133 	dummycr->cr_uid = (uid_t)-1;
134 	dummycr->cr_gid = (gid_t)-1;
135 	dummycr->cr_ruid = (uid_t)-1;
136 	dummycr->cr_rgid = (gid_t)-1;
137 	dummycr->cr_suid = (uid_t)-1;
138 	dummycr->cr_sgid = (gid_t)-1;
139 
140 
141 	/*
142 	 * kcred is used by anything that needs all privileges; it's
143 	 * also the template used for crget as it has all the compatible
144 	 * sets filled in.
145 	 */
146 	kcred = cralloc();
147 
148 	bzero(kcred, crsize);
149 	kcred->cr_ref = 1;
150 
151 	/* kcred is never freed, so we don't need zone_cred_hold here */
152 	kcred->cr_zone = &zone0;
153 
154 	priv_fillset(&CR_LPRIV(kcred));
155 	CR_IPRIV(kcred) = *priv_basic;
156 
157 	/* Not a basic privilege, if chown is not restricted add it to I0 */
158 	if (!rstchown)
159 		priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
160 
161 	/* Basic privilege, if link is restricted remove it from I0 */
162 	if (rstlink)
163 		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
164 
165 	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
166 
167 	CR_FLAGS(kcred) = NET_MAC_AWARE;
168 
169 	/*
170 	 * Set up credentials of p0.
171 	 */
172 	ttoproc(curthread)->p_cred = kcred;
173 	curthread->t_cred = kcred;
174 
175 	/*
176 	 * nobody is used to map SID containing CRs.
177 	 */
178 	ephemeral_data.nobody = crdup(kcred);
179 	(void) crsetugid(ephemeral_data.nobody, UID_NOBODY, GID_NOBODY);
180 	CR_FLAGS(kcred) = 0;
181 
182 	ucredsize = UCRED_SIZE;
183 }
184 
185 /*
186  * Allocate (nearly) uninitialized cred_t.
187  */
188 cred_t *
189 cralloc(void)
190 {
191 	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
192 	cr->cr_ref = 1;		/* So we can crfree() */
193 	cr->cr_zone = NULL;
194 	cr->cr_label = NULL;
195 	cr->cr_ksid = NULL;
196 	return (cr);
197 }
198 
199 /*
200  * As cralloc but prepared for ksid change (if appropriate).
201  */
202 cred_t *
203 cralloc_ksid(void)
204 {
205 	cred_t *cr = cralloc();
206 	if (hasephids)
207 		cr->cr_ksid = kcrsid_alloc();
208 	return (cr);
209 }
210 
211 /*
212  * Allocate a initialized cred structure and crhold() it.
213  * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
214  */
215 cred_t *
216 crget(void)
217 {
218 	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
219 
220 	bcopy(kcred, cr, crsize);
221 	cr->cr_ref = 1;
222 	zone_cred_hold(cr->cr_zone);
223 	if (cr->cr_label)
224 		label_hold(cr->cr_label);
225 	return (cr);
226 }
227 
228 /*
229  * Broadcast the cred to all the threads in the process.
230  * The current thread's credentials can be set right away, but other
231  * threads must wait until the start of the next system call or trap.
232  * This avoids changing the cred in the middle of a system call.
233  *
234  * The cred has already been held for the process and the thread (2 holds),
235  * and p->p_cred set.
236  *
237  * p->p_crlock shouldn't be held here, since p_lock must be acquired.
238  */
239 void
240 crset(proc_t *p, cred_t *cr)
241 {
242 	kthread_id_t	t;
243 	kthread_id_t	first;
244 	cred_t *oldcr;
245 
246 	ASSERT(p == curproc);	/* assumes p_lwpcnt can't change */
247 
248 	/*
249 	 * DTrace accesses t_cred in probe context.  t_cred must always be
250 	 * either NULL, or point to a valid, allocated cred structure.
251 	 */
252 	t = curthread;
253 	oldcr = t->t_cred;
254 	t->t_cred = cr;		/* the cred is held by caller for this thread */
255 	crfree(oldcr);		/* free the old cred for the thread */
256 
257 	/*
258 	 * Broadcast to other threads, if any.
259 	 */
260 	if (p->p_lwpcnt > 1) {
261 		mutex_enter(&p->p_lock);	/* to keep thread list safe */
262 		first = curthread;
263 		for (t = first->t_forw; t != first; t = t->t_forw)
264 			t->t_pre_sys = 1; /* so syscall will get new cred */
265 		mutex_exit(&p->p_lock);
266 	}
267 }
268 
269 /*
270  * Put a hold on a cred structure.
271  */
272 void
273 crhold(cred_t *cr)
274 {
275 	atomic_add_32(&cr->cr_ref, 1);
276 }
277 
278 /*
279  * Release previous hold on a cred structure.  Free it if refcnt == 0.
280  * If cred uses label different from zone label, free it.
281  */
282 void
283 crfree(cred_t *cr)
284 {
285 	if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) {
286 		ASSERT(cr != kcred);
287 		if (cr->cr_label)
288 			label_rele(cr->cr_label);
289 		if (cr->cr_zone)
290 			zone_cred_rele(cr->cr_zone);
291 		if (cr->cr_ksid)
292 			kcrsid_rele(cr->cr_ksid);
293 		kmem_cache_free(cred_cache, cr);
294 	}
295 }
296 
297 /*
298  * Copy a cred structure to a new one and free the old one.
299  *	The new cred will have two references.  One for the calling process,
300  * 	and one for the thread.
301  */
302 cred_t *
303 crcopy(cred_t *cr)
304 {
305 	cred_t *newcr;
306 
307 	newcr = cralloc();
308 	bcopy(cr, newcr, crsize);
309 	if (newcr->cr_zone)
310 		zone_cred_hold(newcr->cr_zone);
311 	if (newcr->cr_label)
312 		label_hold(cr->cr_label);
313 	if (newcr->cr_ksid)
314 		kcrsid_hold(cr->cr_ksid);
315 	crfree(cr);
316 	newcr->cr_ref = 2;		/* caller gets two references */
317 	return (newcr);
318 }
319 
320 /*
321  * Copy a cred structure to a new one and free the old one.
322  *	The new cred will have two references.  One for the calling process,
323  * 	and one for the thread.
324  * This variation on crcopy uses a pre-allocated structure for the
325  * "new" cred.
326  */
327 void
328 crcopy_to(cred_t *oldcr, cred_t *newcr)
329 {
330 	credsid_t *nkcr = newcr->cr_ksid;
331 
332 	bcopy(oldcr, newcr, crsize);
333 	if (newcr->cr_zone)
334 		zone_cred_hold(newcr->cr_zone);
335 	if (newcr->cr_label)
336 		label_hold(newcr->cr_label);
337 	if (nkcr) {
338 		newcr->cr_ksid = nkcr;
339 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
340 	} else if (newcr->cr_ksid)
341 		kcrsid_hold(newcr->cr_ksid);
342 	crfree(oldcr);
343 	newcr->cr_ref = 2;		/* caller gets two references */
344 }
345 
346 /*
347  * Dup a cred struct to a new held one.
348  *	The old cred is not freed.
349  */
350 cred_t *
351 crdup(cred_t *cr)
352 {
353 	cred_t *newcr;
354 
355 	newcr = cralloc();
356 	bcopy(cr, newcr, crsize);
357 	if (newcr->cr_zone)
358 		zone_cred_hold(newcr->cr_zone);
359 	if (newcr->cr_label)
360 		label_hold(newcr->cr_label);
361 	if (newcr->cr_ksid)
362 		kcrsid_hold(newcr->cr_ksid);
363 	newcr->cr_ref = 1;
364 	return (newcr);
365 }
366 
367 /*
368  * Dup a cred struct to a new held one.
369  *	The old cred is not freed.
370  * This variation on crdup uses a pre-allocated structure for the
371  * "new" cred.
372  */
373 void
374 crdup_to(cred_t *oldcr, cred_t *newcr)
375 {
376 	credsid_t *nkcr = newcr->cr_ksid;
377 
378 	bcopy(oldcr, newcr, crsize);
379 	if (newcr->cr_zone)
380 		zone_cred_hold(newcr->cr_zone);
381 	if (newcr->cr_label)
382 		label_hold(newcr->cr_label);
383 	if (nkcr) {
384 		newcr->cr_ksid = nkcr;
385 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
386 	} else if (newcr->cr_ksid)
387 		kcrsid_hold(newcr->cr_ksid);
388 	newcr->cr_ref = 1;
389 }
390 
391 /*
392  * Return the (held) credentials for the current running process.
393  */
394 cred_t *
395 crgetcred(void)
396 {
397 	cred_t *cr;
398 	proc_t *p;
399 
400 	p = ttoproc(curthread);
401 	mutex_enter(&p->p_crlock);
402 	crhold(cr = p->p_cred);
403 	mutex_exit(&p->p_crlock);
404 	return (cr);
405 }
406 
407 /*
408  * Backward compatibility check for suser().
409  * Accounting flag is now set in the policy functions; auditing is
410  * done through use of privilege in the audit trail.
411  */
412 int
413 suser(cred_t *cr)
414 {
415 	return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
416 	    == 0);
417 }
418 
419 /*
420  * Determine whether the supplied group id is a member of the group
421  * described by the supplied credentials.
422  */
423 int
424 groupmember(gid_t gid, const cred_t *cr)
425 {
426 	if (gid == cr->cr_gid)
427 		return (1);
428 	return (supgroupmember(gid, cr));
429 }
430 
431 /*
432  * As groupmember but only check against the supplemental groups.
433  */
434 int
435 supgroupmember(gid_t gid, const cred_t *cr)
436 {
437 	const gid_t *gp, *endgp;
438 
439 	endgp = &cr->cr_groups[cr->cr_ngroups];
440 	for (gp = cr->cr_groups; gp < endgp; gp++)
441 		if (*gp == gid)
442 			return (1);
443 	return (0);
444 }
445 
446 /*
447  * This function is called to check whether the credentials set
448  * "scrp" has permission to act on credentials set "tcrp".  It enforces the
449  * permission requirements needed to send a signal to a process.
450  * The same requirements are imposed by other system calls, however.
451  *
452  * The rules are:
453  * (1) if the credentials are the same, the check succeeds
454  * (2) if the zone ids don't match, and scrp is not in the global zone or
455  *     does not have the PRIV_PROC_ZONE privilege, the check fails
456  * (3) if the real or effective user id of scrp matches the real or saved
457  *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
458  *     succeeds
459  * (4) otherwise, the check fails
460  */
461 int
462 hasprocperm(const cred_t *tcrp, const cred_t *scrp)
463 {
464 	if (scrp == tcrp)
465 		return (1);
466 	if (scrp->cr_zone != tcrp->cr_zone &&
467 	    (scrp->cr_zone != global_zone ||
468 	    secpolicy_proc_zone(scrp) != 0))
469 		return (0);
470 	if (scrp->cr_uid == tcrp->cr_ruid ||
471 	    scrp->cr_ruid == tcrp->cr_ruid ||
472 	    scrp->cr_uid  == tcrp->cr_suid ||
473 	    scrp->cr_ruid == tcrp->cr_suid ||
474 	    !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
475 		return (1);
476 	return (0);
477 }
478 
479 /*
480  * This interface replaces hasprocperm; it works like hasprocperm but
481  * additionally returns success if the proc_t's match
482  * It is the preferred interface for most uses.
483  * And it will acquire pcrlock itself, so it assert's that it shouldn't
484  * be held.
485  */
486 int
487 prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
488 {
489 	int rets;
490 	cred_t *tcrp;
491 
492 	ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
493 
494 	if (tp == sp)
495 		return (1);
496 
497 	if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
498 		return (0);
499 
500 	mutex_enter(&tp->p_crlock);
501 	tcrp = tp->p_cred;
502 	rets = hasprocperm(tcrp, scrp);
503 	mutex_exit(&tp->p_crlock);
504 
505 	return (rets);
506 }
507 
508 /*
509  * This routine is used to compare two credentials to determine if
510  * they refer to the same "user".  If the pointers are equal, then
511  * they must refer to the same user.  Otherwise, the contents of
512  * the credentials are compared to see whether they are equivalent.
513  *
514  * This routine returns 0 if the credentials refer to the same user,
515  * 1 if they do not.
516  */
517 int
518 crcmp(const cred_t *cr1, const cred_t *cr2)
519 {
520 
521 	if (cr1 == cr2)
522 		return (0);
523 
524 	if (cr1->cr_uid == cr2->cr_uid &&
525 	    cr1->cr_gid == cr2->cr_gid &&
526 	    cr1->cr_ruid == cr2->cr_ruid &&
527 	    cr1->cr_rgid == cr2->cr_rgid &&
528 	    cr1->cr_ngroups == cr2->cr_ngroups &&
529 	    cr1->cr_zone == cr2->cr_zone &&
530 	    bcmp(cr1->cr_groups, cr2->cr_groups,
531 		    cr1->cr_ngroups * sizeof (gid_t)) == 0) {
532 		return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
533 	}
534 	return (1);
535 }
536 
537 /*
538  * Read access functions to cred_t.
539  */
540 uid_t
541 crgetuid(const cred_t *cr)
542 {
543 	return (cr->cr_uid);
544 }
545 
546 uid_t
547 crgetruid(const cred_t *cr)
548 {
549 	return (cr->cr_ruid);
550 }
551 
552 uid_t
553 crgetsuid(const cred_t *cr)
554 {
555 	return (cr->cr_suid);
556 }
557 
558 gid_t
559 crgetgid(const cred_t *cr)
560 {
561 	return (cr->cr_gid);
562 }
563 
564 gid_t
565 crgetrgid(const cred_t *cr)
566 {
567 	return (cr->cr_rgid);
568 }
569 
570 gid_t
571 crgetsgid(const cred_t *cr)
572 {
573 	return (cr->cr_sgid);
574 }
575 
576 const auditinfo_addr_t *
577 crgetauinfo(const cred_t *cr)
578 {
579 	return ((const auditinfo_addr_t *)CR_AUINFO(cr));
580 }
581 
582 auditinfo_addr_t *
583 crgetauinfo_modifiable(cred_t *cr)
584 {
585 	return (CR_AUINFO(cr));
586 }
587 
588 zoneid_t
589 crgetzoneid(const cred_t *cr)
590 {
591 	return (cr->cr_zone == NULL ?
592 	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
593 	    cr->cr_zone->zone_id);
594 }
595 
596 projid_t
597 crgetprojid(const cred_t *cr)
598 {
599 	return (cr->cr_projid);
600 }
601 
602 zone_t *
603 crgetzone(const cred_t *cr)
604 {
605 	return (cr->cr_zone);
606 }
607 
608 struct ts_label_s *
609 crgetlabel(const cred_t *cr)
610 {
611 	return (cr->cr_label ?
612 	    cr->cr_label :
613 	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
614 }
615 
616 boolean_t
617 crisremote(const cred_t *cr)
618 {
619 	return (REMOTE_PEER_CRED(cr));
620 }
621 
622 #define	BADUID(x)	((x) != -1 && !VALID_UID(x))
623 #define	BADGID(x)	((x) != -1 && !VALID_GID(x))
624 
625 int
626 crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
627 {
628 	ASSERT(cr->cr_ref <= 2);
629 
630 	if (BADUID(r) || BADUID(e) || BADUID(s))
631 		return (-1);
632 
633 	if (r != -1)
634 		cr->cr_ruid = r;
635 	if (e != -1)
636 		cr->cr_uid = e;
637 	if (s != -1)
638 		cr->cr_suid = s;
639 
640 	return (0);
641 }
642 
643 int
644 crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
645 {
646 	ASSERT(cr->cr_ref <= 2);
647 
648 	if (BADGID(r) || BADGID(e) || BADGID(s))
649 		return (-1);
650 
651 	if (r != -1)
652 		cr->cr_rgid = r;
653 	if (e != -1)
654 		cr->cr_gid = e;
655 	if (s != -1)
656 		cr->cr_sgid = s;
657 
658 	return (0);
659 }
660 
661 int
662 crsetugid(cred_t *cr, uid_t uid, gid_t gid)
663 {
664 	ASSERT(cr->cr_ref <= 2);
665 
666 	if (!VALID_UID(uid) || !VALID_GID(gid))
667 		return (-1);
668 
669 	cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
670 	cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
671 
672 	return (0);
673 }
674 
675 int
676 crsetgroups(cred_t *cr, int n, gid_t *grp)
677 {
678 	ASSERT(cr->cr_ref <= 2);
679 
680 	if (n > ngroups_max || n < 0)
681 		return (-1);
682 
683 	cr->cr_ngroups = n;
684 
685 	if (n > 0)
686 		bcopy(grp, cr->cr_groups, n * sizeof (gid_t));
687 
688 	return (0);
689 }
690 
691 void
692 crsetprojid(cred_t *cr, projid_t projid)
693 {
694 	ASSERT(projid >= 0 && projid <= MAXPROJID);
695 	cr->cr_projid = projid;
696 }
697 
698 /*
699  * This routine returns the pointer to the first element of the cr_groups
700  * array.  It can move around in an implementation defined way.
701  */
702 const gid_t *
703 crgetgroups(const cred_t *cr)
704 {
705 	return (cr->cr_groups);
706 }
707 
708 int
709 crgetngroups(const cred_t *cr)
710 {
711 	return (cr->cr_ngroups);
712 }
713 
714 void
715 cred2prcred(const cred_t *cr, prcred_t *pcrp)
716 {
717 	pcrp->pr_euid = cr->cr_uid;
718 	pcrp->pr_ruid = cr->cr_ruid;
719 	pcrp->pr_suid = cr->cr_suid;
720 	pcrp->pr_egid = cr->cr_gid;
721 	pcrp->pr_rgid = cr->cr_rgid;
722 	pcrp->pr_sgid = cr->cr_sgid;
723 	pcrp->pr_ngroups = MIN(cr->cr_ngroups, (uint_t)ngroups_max);
724 	pcrp->pr_groups[0] = 0;	/* in case ngroups == 0 */
725 
726 	if (pcrp->pr_ngroups != 0)
727 		bcopy(cr->cr_groups, pcrp->pr_groups,
728 		    sizeof (gid_t) * cr->cr_ngroups);
729 }
730 
731 static int
732 cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
733 {
734 	auditinfo_addr_t	*ai;
735 	au_tid_addr_t	tid;
736 
737 	if (secpolicy_audit_getattr(rcr) != 0)
738 		return (-1);
739 
740 	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
741 	tid = ai->ai_termid;
742 
743 	ainfo->ai_auid = ai->ai_auid;
744 	ainfo->ai_mask = ai->ai_mask;
745 	ainfo->ai_asid = ai->ai_asid;
746 
747 	ainfo->ai_termid.at_type = tid.at_type;
748 	bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
749 
750 	ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
751 	ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
752 
753 	return (0);
754 }
755 
756 void
757 cred2uclabel(const cred_t *cr, bslabel_t *labelp)
758 {
759 	ts_label_t	*tslp;
760 
761 	if ((tslp = crgetlabel(cr)) != NULL)
762 		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
763 }
764 
765 /*
766  * Convert a credential into a "ucred".  Allow the caller to specify
767  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
768  * memory and copy it twice.
769  *
770  * This function may call cred2ucaud(), which calls CRED(). Since this
771  * can be called from an interrupt thread, receiver's cred (rcr) is needed
772  * to determine whether audit info should be included.
773  */
774 struct ucred_s *
775 cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
776 {
777 	struct ucred_s *uc;
778 
779 	/* The structure isn't always completely filled in, so zero it */
780 	if (buf == NULL) {
781 		uc = kmem_zalloc(ucredsize, KM_SLEEP);
782 	} else {
783 		bzero(buf, ucredsize);
784 		uc = buf;
785 	}
786 	uc->uc_size = ucredsize;
787 	uc->uc_credoff = UCRED_CRED_OFF;
788 	uc->uc_privoff = UCRED_PRIV_OFF;
789 	uc->uc_audoff = UCRED_AUD_OFF;
790 	uc->uc_labeloff = UCRED_LABEL_OFF;
791 	uc->uc_pid = pid;
792 	uc->uc_projid = cr->cr_projid;
793 	uc->uc_zoneid = crgetzoneid(cr);
794 
795 	/*
796 	 * Note that cred2uclabel() call should not be factored out
797 	 * to the bottom of the if-else. UCXXX() macros depend on
798 	 * uc_xxxoff values to work correctly.
799 	 */
800 	if (REMOTE_PEER_CRED(cr)) {
801 		/*
802 		 * other than label, the rest of cred info about a
803 		 * remote peer isn't available.
804 		 */
805 		cred2uclabel(cr, UCLABEL(uc));
806 		uc->uc_credoff = 0;
807 		uc->uc_privoff = 0;
808 		uc->uc_audoff = 0;
809 	} else {
810 		cred2prcred(cr, UCCRED(uc));
811 		cred2prpriv(cr, UCPRIV(uc));
812 		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
813 			uc->uc_audoff = 0;
814 		cred2uclabel(cr, UCLABEL(uc));
815 	}
816 
817 	return (uc);
818 }
819 
820 /*
821  * Get the "ucred" of a process.
822  */
823 struct ucred_s *
824 pgetucred(proc_t *p)
825 {
826 	cred_t *cr;
827 	struct ucred_s *uc;
828 
829 	mutex_enter(&p->p_crlock);
830 	cr = p->p_cred;
831 	crhold(cr);
832 	mutex_exit(&p->p_crlock);
833 
834 	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
835 	crfree(cr);
836 
837 	return (uc);
838 }
839 
840 /*
841  * If the reply status is NFSERR_EACCES, it may be because we are
842  * root (no root net access).  Check the real uid, if it isn't root
843  * make that the uid instead and retry the call.
844  * Private interface for NFS.
845  */
846 cred_t *
847 crnetadjust(cred_t *cr)
848 {
849 	if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
850 		cr = crdup(cr);
851 		cr->cr_uid = cr->cr_ruid;
852 		return (cr);
853 	}
854 	return (NULL);
855 }
856 
857 /*
858  * The reference count is of interest when you want to check
859  * whether it is ok to modify the credential in place.
860  */
861 uint_t
862 crgetref(const cred_t *cr)
863 {
864 	return (cr->cr_ref);
865 }
866 
867 static int
868 get_c2audit_load(void)
869 {
870 	static int	gotit = 0;
871 	static int	c2audit_load;
872 	u_longlong_t	audit_load_val;
873 
874 	if (gotit)
875 		return (c2audit_load);
876 	audit_load_val = 0;		/* set default value once */
877 	(void) mod_sysvar("c2audit", "audit_load", &audit_load_val);
878 	c2audit_load = (int)audit_load_val;
879 	gotit++;
880 	return (c2audit_load);
881 }
882 
883 int
884 get_audit_ucrsize(void)
885 {
886 	return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
887 }
888 
889 /*
890  * Set zone pointer in credential to indicated value.  First adds a
891  * hold for the new zone, then drops the hold on previous zone (if any).
892  * This is done in this order in case the old and new zones are the
893  * same.
894  */
895 void
896 crsetzone(cred_t *cr, zone_t *zptr)
897 {
898 	zone_t *oldzptr = cr->cr_zone;
899 
900 	ASSERT(cr != kcred);
901 	ASSERT(cr->cr_ref <= 2);
902 	cr->cr_zone = zptr;
903 	zone_cred_hold(zptr);
904 	if (oldzptr)
905 		zone_cred_rele(oldzptr);
906 }
907 
908 /*
909  * Create a new cred based on the supplied label
910  */
911 cred_t *
912 newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
913 {
914 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
915 	cred_t *cr = NULL;
916 
917 	if (lbl != NULL) {
918 		if ((cr = kmem_cache_alloc(cred_cache, flags)) != NULL) {
919 			bcopy(dummycr, cr, crsize);
920 			cr->cr_label = lbl;
921 		} else {
922 			label_rele(lbl);
923 		}
924 	}
925 
926 	return (cr);
927 }
928 
929 /*
930  * Derive a new cred from the existing cred, but with a different label.
931  * To be used when a cred is being shared, but the label needs to be changed
932  * by a caller without affecting other users
933  */
934 cred_t *
935 copycred_from_bslabel(cred_t *cr, bslabel_t *blabel, uint32_t doi, int flags)
936 {
937 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
938 	cred_t *newcr = NULL;
939 
940 	if (lbl != NULL) {
941 		if ((newcr = kmem_cache_alloc(cred_cache, flags)) != NULL) {
942 			bcopy(cr, newcr, crsize);
943 			if (newcr->cr_zone)
944 				zone_cred_hold(newcr->cr_zone);
945 			newcr->cr_label = lbl;
946 			newcr->cr_ref = 1;
947 		} else {
948 			label_rele(lbl);
949 		}
950 	}
951 
952 	return (newcr);
953 }
954 
955 /*
956  * This function returns a pointer to the kcred-equivalent in the current zone.
957  */
958 cred_t *
959 zone_kcred(void)
960 {
961 	zone_t *zone;
962 
963 	if ((zone = CRED()->cr_zone) != NULL)
964 		return (zone->zone_kcred);
965 	else
966 		return (kcred);
967 }
968 
969 boolean_t
970 valid_ephemeral_uid(uid_t id)
971 {
972 	membar_consumer();
973 	return (id > ephemeral_data.min_uid && id <= ephemeral_data.last_uid);
974 }
975 
976 boolean_t
977 valid_ephemeral_gid(gid_t id)
978 {
979 	membar_consumer();
980 	return (id > ephemeral_data.min_gid && id <= ephemeral_data.last_gid);
981 }
982 
983 int
984 eph_uid_alloc(int flags, uid_t *start, int count)
985 {
986 	mutex_enter(&ephemeral_data.eph_lock);
987 
988 	/* Test for unsigned integer wrap around */
989 	if (ephemeral_data.last_uid + count < ephemeral_data.last_uid) {
990 		mutex_exit(&ephemeral_data.eph_lock);
991 		return (-1);
992 	}
993 
994 	/* first call or idmap crashed and state corrupted */
995 	if (flags != 0)
996 		ephemeral_data.min_uid = ephemeral_data.last_uid;
997 
998 	hasephids = B_TRUE;
999 	*start = ephemeral_data.last_uid + 1;
1000 	atomic_add_32(&ephemeral_data.last_uid, count);
1001 	mutex_exit(&ephemeral_data.eph_lock);
1002 	return (0);
1003 }
1004 
1005 int
1006 eph_gid_alloc(int flags, gid_t *start, int count)
1007 {
1008 	mutex_enter(&ephemeral_data.eph_lock);
1009 
1010 	/* Test for unsigned integer wrap around */
1011 	if (ephemeral_data.last_gid + count < ephemeral_data.last_gid) {
1012 		mutex_exit(&ephemeral_data.eph_lock);
1013 		return (-1);
1014 	}
1015 
1016 	/* first call or idmap crashed and state corrupted */
1017 	if (flags != 0)
1018 		ephemeral_data.min_gid = ephemeral_data.last_gid;
1019 
1020 	hasephids = B_TRUE;
1021 	*start = ephemeral_data.last_gid + 1;
1022 	atomic_add_32(&ephemeral_data.last_gid, count);
1023 	mutex_exit(&ephemeral_data.eph_lock);
1024 	return (0);
1025 }
1026 
1027 /*
1028  * If the credential contains any ephemeral IDs, map the credential
1029  * to nobody.
1030  */
1031 cred_t *
1032 crgetmapped(const cred_t *cr)
1033 {
1034 	if (cr->cr_ksid != NULL) {
1035 		int i;
1036 
1037 		for (i = 0; i < KSID_COUNT; i++)
1038 			if (cr->cr_ksid->kr_sidx[i].ks_id > MAXUID)
1039 				return (ephemeral_data.nobody);
1040 		if (cr->cr_ksid->kr_sidlist != NULL &&
1041 		    cr->cr_ksid->kr_sidlist->ksl_neid > 0) {
1042 				return (ephemeral_data.nobody);
1043 		}
1044 	}
1045 
1046 	return ((cred_t *)cr);
1047 }
1048 
1049 /* index should be in range for a ksidindex_t */
1050 void
1051 crsetsid(cred_t *cr, ksid_t *ksp, int index)
1052 {
1053 	ASSERT(cr->cr_ref <= 2);
1054 	ASSERT(index >= 0 && index < KSID_COUNT);
1055 	if (cr->cr_ksid == NULL && ksp == NULL)
1056 		return;
1057 	cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
1058 }
1059 
1060 void
1061 crsetsidlist(cred_t *cr, ksidlist_t *ksl)
1062 {
1063 	ASSERT(cr->cr_ref <= 2);
1064 	if (cr->cr_ksid == NULL && ksl == NULL)
1065 		return;
1066 	cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
1067 }
1068 
1069 ksid_t *
1070 crgetsid(const cred_t *cr, int i)
1071 {
1072 	ASSERT(i >= 0 && i < KSID_COUNT);
1073 	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
1074 		return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
1075 	return (NULL);
1076 }
1077 
1078 ksidlist_t *
1079 crgetsidlist(const cred_t *cr)
1080 {
1081 	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidlist != NULL)
1082 		return ((ksidlist_t *)&cr->cr_ksid->kr_sidlist);
1083 	return (NULL);
1084 }
1085