xref: /illumos-gate/usr/src/uts/common/os/cred.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 (c) 2013, Ira Cooper.  All rights reserved.
23  */
24 /*
25  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California
34  * All Rights Reserved
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
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 <sys/door.h>
60 #include <c2/audit.h>
61 #include <sys/zone.h>
62 #include <sys/tsol/label.h>
63 #include <sys/sid.h>
64 #include <sys/idmap.h>
65 #include <sys/klpd.h>
66 #include <sys/varargs.h>
67 #include <sys/sysconf.h>
68 #include <util/qsort.h>
69 
70 
71 /* Ephemeral IDs Zones specific data */
72 typedef struct ephemeral_zsd {
73 	uid_t		min_uid;
74 	uid_t		last_uid;
75 	gid_t		min_gid;
76 	gid_t		last_gid;
77 	kmutex_t	eph_lock;
78 	cred_t		*eph_nobody;
79 } ephemeral_zsd_t;
80 
81 static void crgrphold(credgrp_t *);
82 
83 #define	CREDGRPSZ(ngrp)	(sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t)))
84 
85 static kmutex_t		ephemeral_zone_mutex;
86 static zone_key_t	ephemeral_zone_key;
87 
88 static struct kmem_cache *cred_cache;
89 static size_t		crsize = 0;
90 static int		audoff = 0;
91 uint32_t		ucredsize;
92 cred_t			*kcred;
93 static cred_t		*dummycr;
94 
95 int rstlink;		/* link(2) restricted to files owned by user? */
96 
97 static int get_c2audit_load(void);
98 
99 #define	CR_AUINFO(c)	(auditinfo_addr_t *)((audoff == 0) ? NULL : \
100 			    ((char *)(c)) + audoff)
101 
102 #define	REMOTE_PEER_CRED(c)	((c)->cr_gid == -1)
103 
104 #define	BIN_GROUP_SEARCH_CUTOFF	16
105 
106 static boolean_t hasephids = B_FALSE;
107 
108 static ephemeral_zsd_t *
109 get_ephemeral_zsd(zone_t *zone)
110 {
111 	ephemeral_zsd_t *eph_zsd;
112 
113 	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
114 	if (eph_zsd != NULL) {
115 		return (eph_zsd);
116 	}
117 
118 	mutex_enter(&ephemeral_zone_mutex);
119 	eph_zsd = zone_getspecific(ephemeral_zone_key, zone);
120 	if (eph_zsd == NULL) {
121 		eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP);
122 		eph_zsd->min_uid = MAXUID;
123 		eph_zsd->last_uid = IDMAP_WK__MAX_UID;
124 		eph_zsd->min_gid = MAXUID;
125 		eph_zsd->last_gid = IDMAP_WK__MAX_GID;
126 		mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL);
127 
128 		/*
129 		 * nobody is used to map SID containing CRs.
130 		 */
131 		eph_zsd->eph_nobody = crdup(zone->zone_kcred);
132 		(void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY);
133 		CR_FLAGS(eph_zsd->eph_nobody) = 0;
134 		eph_zsd->eph_nobody->cr_zone = zone;
135 
136 		(void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd);
137 	}
138 	mutex_exit(&ephemeral_zone_mutex);
139 	return (eph_zsd);
140 }
141 
142 static cred_t *crdup_flags(const cred_t *, int);
143 static cred_t *cralloc_flags(int);
144 
145 /*
146  * This function is called when a zone is destroyed
147  */
148 static void
149 /* ARGSUSED */
150 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg)
151 {
152 	ephemeral_zsd_t *eph_zsd = arg;
153 	if (eph_zsd != NULL) {
154 		mutex_destroy(&eph_zsd->eph_lock);
155 		crfree(eph_zsd->eph_nobody);
156 		kmem_free(eph_zsd, sizeof (ephemeral_zsd_t));
157 	}
158 }
159 
160 
161 
162 /*
163  * Initialize credentials data structures.
164  */
165 
166 void
167 cred_init(void)
168 {
169 	priv_init();
170 
171 	crsize = sizeof (cred_t);
172 
173 	if (get_c2audit_load() > 0) {
174 #ifdef _LP64
175 		/* assure audit context is 64-bit aligned */
176 		audoff = (crsize +
177 		    sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1);
178 #else	/* _LP64 */
179 		audoff = crsize;
180 #endif	/* _LP64 */
181 		crsize = audoff + sizeof (auditinfo_addr_t);
182 		crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1);
183 	}
184 
185 	cred_cache = kmem_cache_create("cred_cache", crsize, 0,
186 	    NULL, NULL, NULL, NULL, NULL, 0);
187 
188 	/*
189 	 * dummycr is used to copy initial state for creds.
190 	 */
191 	dummycr = cralloc();
192 	bzero(dummycr, crsize);
193 	dummycr->cr_ref = 1;
194 	dummycr->cr_uid = (uid_t)-1;
195 	dummycr->cr_gid = (gid_t)-1;
196 	dummycr->cr_ruid = (uid_t)-1;
197 	dummycr->cr_rgid = (gid_t)-1;
198 	dummycr->cr_suid = (uid_t)-1;
199 	dummycr->cr_sgid = (gid_t)-1;
200 
201 
202 	/*
203 	 * kcred is used by anything that needs all privileges; it's
204 	 * also the template used for crget as it has all the compatible
205 	 * sets filled in.
206 	 */
207 	kcred = cralloc();
208 
209 	bzero(kcred, crsize);
210 	kcred->cr_ref = 1;
211 
212 	/* kcred is never freed, so we don't need zone_cred_hold here */
213 	kcred->cr_zone = &zone0;
214 
215 	priv_fillset(&CR_LPRIV(kcred));
216 	CR_IPRIV(kcred) = *priv_basic;
217 
218 	priv_addset(&CR_IPRIV(kcred), PRIV_PROC_SECFLAGS);
219 
220 	/* Not a basic privilege, if chown is not restricted add it to I0 */
221 	if (!rstchown)
222 		priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF);
223 
224 	/* Basic privilege, if link is restricted remove it from I0 */
225 	if (rstlink)
226 		priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY);
227 
228 	CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred);
229 
230 	CR_FLAGS(kcred) = NET_MAC_AWARE;
231 
232 	/*
233 	 * Set up credentials of p0.
234 	 */
235 	ttoproc(curthread)->p_cred = kcred;
236 	curthread->t_cred = kcred;
237 
238 	ucredsize = UCRED_SIZE;
239 
240 	mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
241 	zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd);
242 }
243 
244 /*
245  * Allocate (nearly) uninitialized cred_t.
246  */
247 static cred_t *
248 cralloc_flags(int flgs)
249 {
250 	cred_t *cr = kmem_cache_alloc(cred_cache, flgs);
251 
252 	if (cr == NULL)
253 		return (NULL);
254 
255 	cr->cr_ref = 1;		/* So we can crfree() */
256 	cr->cr_zone = NULL;
257 	cr->cr_label = NULL;
258 	cr->cr_ksid = NULL;
259 	cr->cr_klpd = NULL;
260 	cr->cr_grps = NULL;
261 	return (cr);
262 }
263 
264 cred_t *
265 cralloc(void)
266 {
267 	return (cralloc_flags(KM_SLEEP));
268 }
269 
270 /*
271  * As cralloc but prepared for ksid change (if appropriate).
272  */
273 cred_t *
274 cralloc_ksid(void)
275 {
276 	cred_t *cr = cralloc();
277 	if (hasephids)
278 		cr->cr_ksid = kcrsid_alloc();
279 	return (cr);
280 }
281 
282 /*
283  * Allocate a initialized cred structure and crhold() it.
284  * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0
285  */
286 cred_t *
287 crget(void)
288 {
289 	cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP);
290 
291 	bcopy(kcred, cr, crsize);
292 	cr->cr_ref = 1;
293 	zone_cred_hold(cr->cr_zone);
294 	if (cr->cr_label)
295 		label_hold(cr->cr_label);
296 	ASSERT(cr->cr_klpd == NULL);
297 	ASSERT(cr->cr_grps == NULL);
298 	return (cr);
299 }
300 
301 /*
302  * Broadcast the cred to all the threads in the process.
303  * The current thread's credentials can be set right away, but other
304  * threads must wait until the start of the next system call or trap.
305  * This avoids changing the cred in the middle of a system call.
306  *
307  * The cred has already been held for the process and the thread (2 holds),
308  * and p->p_cred set.
309  *
310  * p->p_crlock shouldn't be held here, since p_lock must be acquired.
311  */
312 void
313 crset(proc_t *p, cred_t *cr)
314 {
315 	kthread_id_t	t;
316 	kthread_id_t	first;
317 	cred_t *oldcr;
318 
319 	ASSERT(p == curproc);	/* assumes p_lwpcnt can't change */
320 
321 	/*
322 	 * DTrace accesses t_cred in probe context.  t_cred must always be
323 	 * either NULL, or point to a valid, allocated cred structure.
324 	 */
325 	t = curthread;
326 	oldcr = t->t_cred;
327 	t->t_cred = cr;		/* the cred is held by caller for this thread */
328 	crfree(oldcr);		/* free the old cred for the thread */
329 
330 	/*
331 	 * Broadcast to other threads, if any.
332 	 */
333 	if (p->p_lwpcnt > 1) {
334 		mutex_enter(&p->p_lock);	/* to keep thread list safe */
335 		first = curthread;
336 		for (t = first->t_forw; t != first; t = t->t_forw)
337 			t->t_pre_sys = 1; /* so syscall will get new cred */
338 		mutex_exit(&p->p_lock);
339 	}
340 }
341 
342 /*
343  * Put a hold on a cred structure.
344  */
345 void
346 crhold(cred_t *cr)
347 {
348 	ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
349 	atomic_inc_32(&cr->cr_ref);
350 }
351 
352 /*
353  * Release previous hold on a cred structure.  Free it if refcnt == 0.
354  * If cred uses label different from zone label, free it.
355  */
356 void
357 crfree(cred_t *cr)
358 {
359 	ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0);
360 	if (atomic_dec_32_nv(&cr->cr_ref) == 0) {
361 		ASSERT(cr != kcred);
362 		if (cr->cr_label)
363 			label_rele(cr->cr_label);
364 		if (cr->cr_klpd)
365 			crklpd_rele(cr->cr_klpd);
366 		if (cr->cr_zone)
367 			zone_cred_rele(cr->cr_zone);
368 		if (cr->cr_ksid)
369 			kcrsid_rele(cr->cr_ksid);
370 		if (cr->cr_grps)
371 			crgrprele(cr->cr_grps);
372 
373 		kmem_cache_free(cred_cache, cr);
374 	}
375 }
376 
377 /*
378  * Copy a cred structure to a new one and free the old one.
379  *	The new cred will have two references.  One for the calling process,
380  * 	and one for the thread.
381  */
382 cred_t *
383 crcopy(cred_t *cr)
384 {
385 	cred_t *newcr;
386 
387 	newcr = cralloc();
388 	bcopy(cr, newcr, crsize);
389 	if (newcr->cr_zone)
390 		zone_cred_hold(newcr->cr_zone);
391 	if (newcr->cr_label)
392 		label_hold(newcr->cr_label);
393 	if (newcr->cr_ksid)
394 		kcrsid_hold(newcr->cr_ksid);
395 	if (newcr->cr_klpd)
396 		crklpd_hold(newcr->cr_klpd);
397 	if (newcr->cr_grps)
398 		crgrphold(newcr->cr_grps);
399 	crfree(cr);
400 	newcr->cr_ref = 2;		/* caller gets two references */
401 	return (newcr);
402 }
403 
404 /*
405  * Copy a cred structure to a new one and free the old one.
406  *	The new cred will have two references.  One for the calling process,
407  * 	and one for the thread.
408  * This variation on crcopy uses a pre-allocated structure for the
409  * "new" cred.
410  */
411 void
412 crcopy_to(cred_t *oldcr, cred_t *newcr)
413 {
414 	credsid_t *nkcr = newcr->cr_ksid;
415 
416 	bcopy(oldcr, newcr, crsize);
417 	if (newcr->cr_zone)
418 		zone_cred_hold(newcr->cr_zone);
419 	if (newcr->cr_label)
420 		label_hold(newcr->cr_label);
421 	if (newcr->cr_klpd)
422 		crklpd_hold(newcr->cr_klpd);
423 	if (newcr->cr_grps)
424 		crgrphold(newcr->cr_grps);
425 	if (nkcr) {
426 		newcr->cr_ksid = nkcr;
427 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
428 	} else if (newcr->cr_ksid)
429 		kcrsid_hold(newcr->cr_ksid);
430 	crfree(oldcr);
431 	newcr->cr_ref = 2;		/* caller gets two references */
432 }
433 
434 /*
435  * Dup a cred struct to a new held one.
436  *	The old cred is not freed.
437  */
438 static cred_t *
439 crdup_flags(const cred_t *cr, int flgs)
440 {
441 	cred_t *newcr;
442 
443 	newcr = cralloc_flags(flgs);
444 
445 	if (newcr == NULL)
446 		return (NULL);
447 
448 	bcopy(cr, newcr, crsize);
449 	if (newcr->cr_zone)
450 		zone_cred_hold(newcr->cr_zone);
451 	if (newcr->cr_label)
452 		label_hold(newcr->cr_label);
453 	if (newcr->cr_klpd)
454 		crklpd_hold(newcr->cr_klpd);
455 	if (newcr->cr_ksid)
456 		kcrsid_hold(newcr->cr_ksid);
457 	if (newcr->cr_grps)
458 		crgrphold(newcr->cr_grps);
459 	newcr->cr_ref = 1;
460 	return (newcr);
461 }
462 
463 cred_t *
464 crdup(cred_t *cr)
465 {
466 	return (crdup_flags(cr, KM_SLEEP));
467 }
468 
469 /*
470  * Dup a cred struct to a new held one.
471  *	The old cred is not freed.
472  * This variation on crdup uses a pre-allocated structure for the
473  * "new" cred.
474  */
475 void
476 crdup_to(cred_t *oldcr, cred_t *newcr)
477 {
478 	credsid_t *nkcr = newcr->cr_ksid;
479 
480 	bcopy(oldcr, newcr, crsize);
481 	if (newcr->cr_zone)
482 		zone_cred_hold(newcr->cr_zone);
483 	if (newcr->cr_label)
484 		label_hold(newcr->cr_label);
485 	if (newcr->cr_klpd)
486 		crklpd_hold(newcr->cr_klpd);
487 	if (newcr->cr_grps)
488 		crgrphold(newcr->cr_grps);
489 	if (nkcr) {
490 		newcr->cr_ksid = nkcr;
491 		kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid);
492 	} else if (newcr->cr_ksid)
493 		kcrsid_hold(newcr->cr_ksid);
494 	newcr->cr_ref = 1;
495 }
496 
497 /*
498  * Return the (held) credentials for the current running process.
499  */
500 cred_t *
501 crgetcred(void)
502 {
503 	cred_t *cr;
504 	proc_t *p;
505 
506 	p = ttoproc(curthread);
507 	mutex_enter(&p->p_crlock);
508 	crhold(cr = p->p_cred);
509 	mutex_exit(&p->p_crlock);
510 	return (cr);
511 }
512 
513 /*
514  * Backward compatibility check for suser().
515  * Accounting flag is now set in the policy functions; auditing is
516  * done through use of privilege in the audit trail.
517  */
518 int
519 suser(cred_t *cr)
520 {
521 	return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL)
522 	    == 0);
523 }
524 
525 /*
526  * Determine whether the supplied group id is a member of the group
527  * described by the supplied credentials.
528  */
529 int
530 groupmember(gid_t gid, const cred_t *cr)
531 {
532 	if (gid == cr->cr_gid)
533 		return (1);
534 	return (supgroupmember(gid, cr));
535 }
536 
537 /*
538  * As groupmember but only check against the supplemental groups.
539  */
540 int
541 supgroupmember(gid_t gid, const cred_t *cr)
542 {
543 	int hi, lo;
544 	credgrp_t *grps = cr->cr_grps;
545 	const gid_t *gp, *endgp;
546 
547 	if (grps == NULL)
548 		return (0);
549 
550 	/* For a small number of groups, use sequentials search. */
551 	if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) {
552 		endgp = &grps->crg_groups[grps->crg_ngroups];
553 		for (gp = grps->crg_groups; gp < endgp; gp++)
554 			if (*gp == gid)
555 				return (1);
556 		return (0);
557 	}
558 
559 	/* We use binary search when we have many groups. */
560 	lo = 0;
561 	hi = grps->crg_ngroups - 1;
562 	gp = grps->crg_groups;
563 
564 	do {
565 		int m = (lo + hi) / 2;
566 
567 		if (gid > gp[m])
568 			lo = m + 1;
569 		else if (gid < gp[m])
570 			hi = m - 1;
571 		else
572 			return (1);
573 	} while (lo <= hi);
574 
575 	return (0);
576 }
577 
578 /*
579  * This function is called to check whether the credentials set
580  * "scrp" has permission to act on credentials set "tcrp".  It enforces the
581  * permission requirements needed to send a signal to a process.
582  * The same requirements are imposed by other system calls, however.
583  *
584  * The rules are:
585  * (1) if the credentials are the same, the check succeeds
586  * (2) if the zone ids don't match, and scrp is not in the global zone or
587  *     does not have the PRIV_PROC_ZONE privilege, the check fails
588  * (3) if the real or effective user id of scrp matches the real or saved
589  *     user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check
590  *     succeeds
591  * (4) otherwise, the check fails
592  */
593 int
594 hasprocperm(const cred_t *tcrp, const cred_t *scrp)
595 {
596 	if (scrp == tcrp)
597 		return (1);
598 	if (scrp->cr_zone != tcrp->cr_zone &&
599 	    (scrp->cr_zone != global_zone ||
600 	    secpolicy_proc_zone(scrp) != 0))
601 		return (0);
602 	if (scrp->cr_uid == tcrp->cr_ruid ||
603 	    scrp->cr_ruid == tcrp->cr_ruid ||
604 	    scrp->cr_uid  == tcrp->cr_suid ||
605 	    scrp->cr_ruid == tcrp->cr_suid ||
606 	    !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm"))
607 		return (1);
608 	return (0);
609 }
610 
611 /*
612  * This interface replaces hasprocperm; it works like hasprocperm but
613  * additionally returns success if the proc_t's match
614  * It is the preferred interface for most uses.
615  * And it will acquire p_crlock itself, so it assert's that it shouldn't
616  * be held.
617  */
618 int
619 prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp)
620 {
621 	int rets;
622 	cred_t *tcrp;
623 
624 	ASSERT(MUTEX_NOT_HELD(&tp->p_crlock));
625 
626 	if (tp == sp)
627 		return (1);
628 
629 	if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0)
630 		return (0);
631 
632 	mutex_enter(&tp->p_crlock);
633 	crhold(tcrp = tp->p_cred);
634 	mutex_exit(&tp->p_crlock);
635 	rets = hasprocperm(tcrp, scrp);
636 	crfree(tcrp);
637 
638 	return (rets);
639 }
640 
641 /*
642  * This routine is used to compare two credentials to determine if
643  * they refer to the same "user".  If the pointers are equal, then
644  * they must refer to the same user.  Otherwise, the contents of
645  * the credentials are compared to see whether they are equivalent.
646  *
647  * This routine returns 0 if the credentials refer to the same user,
648  * 1 if they do not.
649  */
650 int
651 crcmp(const cred_t *cr1, const cred_t *cr2)
652 {
653 	credgrp_t *grp1, *grp2;
654 
655 	if (cr1 == cr2)
656 		return (0);
657 
658 	if (cr1->cr_uid == cr2->cr_uid &&
659 	    cr1->cr_gid == cr2->cr_gid &&
660 	    cr1->cr_ruid == cr2->cr_ruid &&
661 	    cr1->cr_rgid == cr2->cr_rgid &&
662 	    cr1->cr_zone == cr2->cr_zone &&
663 	    ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) ||
664 	    (grp1 != NULL && grp2 != NULL &&
665 	    grp1->crg_ngroups == grp2->crg_ngroups &&
666 	    bcmp(grp1->crg_groups, grp2->crg_groups,
667 	    grp1->crg_ngroups * sizeof (gid_t)) == 0))) {
668 		return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2)));
669 	}
670 	return (1);
671 }
672 
673 /*
674  * Read access functions to cred_t.
675  */
676 uid_t
677 crgetuid(const cred_t *cr)
678 {
679 	return (cr->cr_uid);
680 }
681 
682 uid_t
683 crgetruid(const cred_t *cr)
684 {
685 	return (cr->cr_ruid);
686 }
687 
688 uid_t
689 crgetsuid(const cred_t *cr)
690 {
691 	return (cr->cr_suid);
692 }
693 
694 gid_t
695 crgetgid(const cred_t *cr)
696 {
697 	return (cr->cr_gid);
698 }
699 
700 gid_t
701 crgetrgid(const cred_t *cr)
702 {
703 	return (cr->cr_rgid);
704 }
705 
706 gid_t
707 crgetsgid(const cred_t *cr)
708 {
709 	return (cr->cr_sgid);
710 }
711 
712 const auditinfo_addr_t *
713 crgetauinfo(const cred_t *cr)
714 {
715 	return ((const auditinfo_addr_t *)CR_AUINFO(cr));
716 }
717 
718 auditinfo_addr_t *
719 crgetauinfo_modifiable(cred_t *cr)
720 {
721 	return (CR_AUINFO(cr));
722 }
723 
724 zoneid_t
725 crgetzoneid(const cred_t *cr)
726 {
727 	return (cr->cr_zone == NULL ?
728 	    (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) :
729 	    cr->cr_zone->zone_id);
730 }
731 
732 projid_t
733 crgetprojid(const cred_t *cr)
734 {
735 	return (cr->cr_projid);
736 }
737 
738 zone_t *
739 crgetzone(const cred_t *cr)
740 {
741 	return (cr->cr_zone);
742 }
743 
744 struct ts_label_s *
745 crgetlabel(const cred_t *cr)
746 {
747 	return (cr->cr_label ?
748 	    cr->cr_label :
749 	    (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL));
750 }
751 
752 boolean_t
753 crisremote(const cred_t *cr)
754 {
755 	return (REMOTE_PEER_CRED(cr));
756 }
757 
758 #define	BADUID(x, zn)	((x) != -1 && !VALID_UID((x), (zn)))
759 #define	BADGID(x, zn)	((x) != -1 && !VALID_GID((x), (zn)))
760 
761 int
762 crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s)
763 {
764 	zone_t	*zone = crgetzone(cr);
765 
766 	ASSERT(cr->cr_ref <= 2);
767 
768 	if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone))
769 		return (-1);
770 
771 	if (r != -1)
772 		cr->cr_ruid = r;
773 	if (e != -1)
774 		cr->cr_uid = e;
775 	if (s != -1)
776 		cr->cr_suid = s;
777 
778 	return (0);
779 }
780 
781 int
782 crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s)
783 {
784 	zone_t	*zone = crgetzone(cr);
785 
786 	ASSERT(cr->cr_ref <= 2);
787 
788 	if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone))
789 		return (-1);
790 
791 	if (r != -1)
792 		cr->cr_rgid = r;
793 	if (e != -1)
794 		cr->cr_gid = e;
795 	if (s != -1)
796 		cr->cr_sgid = s;
797 
798 	return (0);
799 }
800 
801 int
802 crsetugid(cred_t *cr, uid_t uid, gid_t gid)
803 {
804 	zone_t	*zone = crgetzone(cr);
805 
806 	ASSERT(cr->cr_ref <= 2);
807 
808 	if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone))
809 		return (-1);
810 
811 	cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid;
812 	cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid;
813 
814 	return (0);
815 }
816 
817 static int
818 gidcmp(const void *v1, const void *v2)
819 {
820 	gid_t g1 = *(gid_t *)v1;
821 	gid_t g2 = *(gid_t *)v2;
822 
823 	if (g1 < g2)
824 		return (-1);
825 	else if (g1 > g2)
826 		return (1);
827 	else
828 		return (0);
829 }
830 
831 int
832 crsetgroups(cred_t *cr, int n, gid_t *grp)
833 {
834 	ASSERT(cr->cr_ref <= 2);
835 
836 	if (n > ngroups_max || n < 0)
837 		return (-1);
838 
839 	if (cr->cr_grps != NULL)
840 		crgrprele(cr->cr_grps);
841 
842 	if (n > 0) {
843 		cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP);
844 		bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t));
845 		cr->cr_grps->crg_ref = 1;
846 		cr->cr_grps->crg_ngroups = n;
847 		qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp);
848 	} else {
849 		cr->cr_grps = NULL;
850 	}
851 
852 	return (0);
853 }
854 
855 void
856 crsetprojid(cred_t *cr, projid_t projid)
857 {
858 	ASSERT(projid >= 0 && projid <= MAXPROJID);
859 	cr->cr_projid = projid;
860 }
861 
862 /*
863  * This routine returns the pointer to the first element of the crg_groups
864  * array.  It can move around in an implementation defined way.
865  * Note that when we have no grouplist, we return one element but the
866  * caller should never reference it.
867  */
868 const gid_t *
869 crgetgroups(const cred_t *cr)
870 {
871 	return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups);
872 }
873 
874 int
875 crgetngroups(const cred_t *cr)
876 {
877 	return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups);
878 }
879 
880 void
881 cred2prcred(const cred_t *cr, prcred_t *pcrp)
882 {
883 	pcrp->pr_euid = cr->cr_uid;
884 	pcrp->pr_ruid = cr->cr_ruid;
885 	pcrp->pr_suid = cr->cr_suid;
886 	pcrp->pr_egid = cr->cr_gid;
887 	pcrp->pr_rgid = cr->cr_rgid;
888 	pcrp->pr_sgid = cr->cr_sgid;
889 	pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */
890 	pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups;
891 
892 	if (pcrp->pr_ngroups != 0)
893 		bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups,
894 		    sizeof (gid_t) * pcrp->pr_ngroups);
895 }
896 
897 static int
898 cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr)
899 {
900 	auditinfo_addr_t	*ai;
901 	au_tid_addr_t	tid;
902 
903 	if (secpolicy_audit_getattr(rcr, B_TRUE) != 0)
904 		return (-1);
905 
906 	ai = CR_AUINFO(cr);	/* caller makes sure this is non-NULL */
907 	tid = ai->ai_termid;
908 
909 	ainfo->ai_auid = ai->ai_auid;
910 	ainfo->ai_mask = ai->ai_mask;
911 	ainfo->ai_asid = ai->ai_asid;
912 
913 	ainfo->ai_termid.at_type = tid.at_type;
914 	bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t));
915 
916 	ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port);
917 	ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port);
918 
919 	return (0);
920 }
921 
922 void
923 cred2uclabel(const cred_t *cr, bslabel_t *labelp)
924 {
925 	ts_label_t	*tslp;
926 
927 	if ((tslp = crgetlabel(cr)) != NULL)
928 		bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t));
929 }
930 
931 /*
932  * Convert a credential into a "ucred".  Allow the caller to specify
933  * and aligned buffer, e.g., in an mblk, so we don't have to allocate
934  * memory and copy it twice.
935  *
936  * This function may call cred2ucaud(), which calls CRED(). Since this
937  * can be called from an interrupt thread, receiver's cred (rcr) is needed
938  * to determine whether audit info should be included.
939  */
940 struct ucred_s *
941 cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr)
942 {
943 	struct ucred_s *uc;
944 	uint32_t realsz = ucredminsize(cr);
945 	ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL;
946 
947 	/* The structure isn't always completely filled in, so zero it */
948 	if (buf == NULL) {
949 		uc = kmem_zalloc(realsz, KM_SLEEP);
950 	} else {
951 		bzero(buf, realsz);
952 		uc = buf;
953 	}
954 	uc->uc_size = realsz;
955 	uc->uc_pid = pid;
956 	uc->uc_projid = cr->cr_projid;
957 	uc->uc_zoneid = crgetzoneid(cr);
958 
959 	if (REMOTE_PEER_CRED(cr)) {
960 		/*
961 		 * Other than label, the rest of cred info about a
962 		 * remote peer isn't available. Copy the label directly
963 		 * after the header where we generally copy the prcred.
964 		 * That's why we use sizeof (struct ucred_s).  The other
965 		 * offset fields are initialized to 0.
966 		 */
967 		uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s);
968 	} else {
969 		uc->uc_credoff = UCRED_CRED_OFF;
970 		uc->uc_privoff = UCRED_PRIV_OFF;
971 		uc->uc_audoff = UCRED_AUD_OFF;
972 		uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF;
973 
974 		cred2prcred(cr, UCCRED(uc));
975 		cred2prpriv(cr, UCPRIV(uc));
976 
977 		if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0)
978 			uc->uc_audoff = 0;
979 	}
980 	if (tslp != NULL)
981 		bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t));
982 
983 	return (uc);
984 }
985 
986 /*
987  * Don't allocate the non-needed group entries.  Note: this function
988  * must match the code in cred2ucred; they must agree about the
989  * minimal size of the ucred.
990  */
991 uint32_t
992 ucredminsize(const cred_t *cr)
993 {
994 	int ndiff;
995 
996 	if (cr == NULL)
997 		return (ucredsize);
998 
999 	if (REMOTE_PEER_CRED(cr)) {
1000 		if (is_system_labeled())
1001 			return (sizeof (struct ucred_s) + sizeof (bslabel_t));
1002 		else
1003 			return (sizeof (struct ucred_s));
1004 	}
1005 
1006 	if (cr->cr_grps == NULL)
1007 		ndiff = ngroups_max - 1;	/* Needs one for prcred_t */
1008 	else
1009 		ndiff = ngroups_max - cr->cr_grps->crg_ngroups;
1010 
1011 	return (ucredsize - ndiff * sizeof (gid_t));
1012 }
1013 
1014 /*
1015  * Get the "ucred" of a process.
1016  */
1017 struct ucred_s *
1018 pgetucred(proc_t *p)
1019 {
1020 	cred_t *cr;
1021 	struct ucred_s *uc;
1022 
1023 	mutex_enter(&p->p_crlock);
1024 	cr = p->p_cred;
1025 	crhold(cr);
1026 	mutex_exit(&p->p_crlock);
1027 
1028 	uc = cred2ucred(cr, p->p_pid, NULL, CRED());
1029 	crfree(cr);
1030 
1031 	return (uc);
1032 }
1033 
1034 /*
1035  * If the reply status is NFSERR_EACCES, it may be because we are
1036  * root (no root net access).  Check the real uid, if it isn't root
1037  * make that the uid instead and retry the call.
1038  * Private interface for NFS.
1039  */
1040 cred_t *
1041 crnetadjust(cred_t *cr)
1042 {
1043 	if (cr->cr_uid == 0 && cr->cr_ruid != 0) {
1044 		cr = crdup(cr);
1045 		cr->cr_uid = cr->cr_ruid;
1046 		return (cr);
1047 	}
1048 	return (NULL);
1049 }
1050 
1051 /*
1052  * The reference count is of interest when you want to check
1053  * whether it is ok to modify the credential in place.
1054  */
1055 uint_t
1056 crgetref(const cred_t *cr)
1057 {
1058 	return (cr->cr_ref);
1059 }
1060 
1061 static int
1062 get_c2audit_load(void)
1063 {
1064 	static int	gotit = 0;
1065 	static int	c2audit_load;
1066 
1067 	if (gotit)
1068 		return (c2audit_load);
1069 	c2audit_load = 1;		/* set default value once */
1070 	if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0)
1071 		c2audit_load = 0;
1072 	gotit++;
1073 
1074 	return (c2audit_load);
1075 }
1076 
1077 int
1078 get_audit_ucrsize(void)
1079 {
1080 	return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0);
1081 }
1082 
1083 /*
1084  * Set zone pointer in credential to indicated value.  First adds a
1085  * hold for the new zone, then drops the hold on previous zone (if any).
1086  * This is done in this order in case the old and new zones are the
1087  * same.
1088  */
1089 void
1090 crsetzone(cred_t *cr, zone_t *zptr)
1091 {
1092 	zone_t *oldzptr = cr->cr_zone;
1093 
1094 	ASSERT(cr != kcred);
1095 	ASSERT(cr->cr_ref <= 2);
1096 	cr->cr_zone = zptr;
1097 	zone_cred_hold(zptr);
1098 	if (oldzptr)
1099 		zone_cred_rele(oldzptr);
1100 }
1101 
1102 /*
1103  * Create a new cred based on the supplied label
1104  */
1105 cred_t *
1106 newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
1107 {
1108 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
1109 	cred_t *cr = NULL;
1110 
1111 	if (lbl != NULL) {
1112 		if ((cr = crdup_flags(dummycr, flags)) != NULL) {
1113 			cr->cr_label = lbl;
1114 		} else {
1115 			label_rele(lbl);
1116 		}
1117 	}
1118 
1119 	return (cr);
1120 }
1121 
1122 /*
1123  * Derive a new cred from the existing cred, but with a different label.
1124  * To be used when a cred is being shared, but the label needs to be changed
1125  * by a caller without affecting other users
1126  */
1127 cred_t *
1128 copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
1129 {
1130 	cred_t *newcr = NULL;
1131 
1132 	if ((newcr = crdup_flags(cr, flags)) != NULL) {
1133 		if (newcr->cr_label != NULL)
1134 			label_rele(newcr->cr_label);
1135 		label_hold(label);
1136 		newcr->cr_label = label;
1137 	}
1138 
1139 	return (newcr);
1140 }
1141 
1142 /*
1143  * Derive a new cred from the existing cred, but with a different label.
1144  */
1145 cred_t *
1146 copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
1147     uint32_t doi, int flags)
1148 {
1149 	ts_label_t *lbl = labelalloc(blabel, doi, flags);
1150 	cred_t  *newcr = NULL;
1151 
1152 	if (lbl != NULL) {
1153 		newcr = copycred_from_tslabel(cr, lbl, flags);
1154 		label_rele(lbl);
1155 	}
1156 
1157 	return (newcr);
1158 }
1159 
1160 /*
1161  * This function returns a pointer to the kcred-equivalent in the current zone.
1162  */
1163 cred_t *
1164 zone_kcred(void)
1165 {
1166 	zone_t *zone;
1167 
1168 	if ((zone = CRED()->cr_zone) != NULL)
1169 		return (zone->zone_kcred);
1170 	else
1171 		return (kcred);
1172 }
1173 
1174 boolean_t
1175 valid_ephemeral_uid(zone_t *zone, uid_t id)
1176 {
1177 	ephemeral_zsd_t *eph_zsd;
1178 	if (id <= IDMAP_WK__MAX_UID)
1179 		return (B_TRUE);
1180 
1181 	eph_zsd = get_ephemeral_zsd(zone);
1182 	ASSERT(eph_zsd != NULL);
1183 	membar_consumer();
1184 	return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid);
1185 }
1186 
1187 boolean_t
1188 valid_ephemeral_gid(zone_t *zone, gid_t id)
1189 {
1190 	ephemeral_zsd_t *eph_zsd;
1191 	if (id <= IDMAP_WK__MAX_GID)
1192 		return (B_TRUE);
1193 
1194 	eph_zsd = get_ephemeral_zsd(zone);
1195 	ASSERT(eph_zsd != NULL);
1196 	membar_consumer();
1197 	return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid);
1198 }
1199 
1200 int
1201 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count)
1202 {
1203 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1204 
1205 	ASSERT(eph_zsd != NULL);
1206 
1207 	mutex_enter(&eph_zsd->eph_lock);
1208 
1209 	/* Test for unsigned integer wrap around */
1210 	if (eph_zsd->last_uid + count < eph_zsd->last_uid) {
1211 		mutex_exit(&eph_zsd->eph_lock);
1212 		return (-1);
1213 	}
1214 
1215 	/* first call or idmap crashed and state corrupted */
1216 	if (flags != 0)
1217 		eph_zsd->min_uid = eph_zsd->last_uid;
1218 
1219 	hasephids = B_TRUE;
1220 	*start = eph_zsd->last_uid + 1;
1221 	atomic_add_32(&eph_zsd->last_uid, count);
1222 	mutex_exit(&eph_zsd->eph_lock);
1223 	return (0);
1224 }
1225 
1226 int
1227 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count)
1228 {
1229 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1230 
1231 	ASSERT(eph_zsd != NULL);
1232 
1233 	mutex_enter(&eph_zsd->eph_lock);
1234 
1235 	/* Test for unsigned integer wrap around */
1236 	if (eph_zsd->last_gid + count < eph_zsd->last_gid) {
1237 		mutex_exit(&eph_zsd->eph_lock);
1238 		return (-1);
1239 	}
1240 
1241 	/* first call or idmap crashed and state corrupted */
1242 	if (flags != 0)
1243 		eph_zsd->min_gid = eph_zsd->last_gid;
1244 
1245 	hasephids = B_TRUE;
1246 	*start = eph_zsd->last_gid + 1;
1247 	atomic_add_32(&eph_zsd->last_gid, count);
1248 	mutex_exit(&eph_zsd->eph_lock);
1249 	return (0);
1250 }
1251 
1252 /*
1253  * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data()
1254  * are project private functions that are for use of the test system only and
1255  * are not to be used for other purposes.
1256  */
1257 
1258 void
1259 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid,
1260     gid_t *min_gid, gid_t *last_gid)
1261 {
1262 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1263 
1264 	ASSERT(eph_zsd != NULL);
1265 
1266 	mutex_enter(&eph_zsd->eph_lock);
1267 
1268 	*min_uid = eph_zsd->min_uid;
1269 	*last_uid = eph_zsd->last_uid;
1270 	*min_gid = eph_zsd->min_gid;
1271 	*last_gid = eph_zsd->last_gid;
1272 
1273 	mutex_exit(&eph_zsd->eph_lock);
1274 }
1275 
1276 
1277 void
1278 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid,
1279     gid_t min_gid, gid_t last_gid)
1280 {
1281 	ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone);
1282 
1283 	ASSERT(eph_zsd != NULL);
1284 
1285 	mutex_enter(&eph_zsd->eph_lock);
1286 
1287 	if (min_uid != 0)
1288 		eph_zsd->min_uid = min_uid;
1289 	if (last_uid != 0)
1290 		eph_zsd->last_uid = last_uid;
1291 	if (min_gid != 0)
1292 		eph_zsd->min_gid = min_gid;
1293 	if (last_gid != 0)
1294 		eph_zsd->last_gid = last_gid;
1295 
1296 	mutex_exit(&eph_zsd->eph_lock);
1297 }
1298 
1299 /*
1300  * If the credential user SID or group SID is mapped to an ephemeral
1301  * ID, map the credential to nobody.
1302  */
1303 cred_t *
1304 crgetmapped(const cred_t *cr)
1305 {
1306 	ephemeral_zsd_t *eph_zsd;
1307 	/*
1308 	 * Someone incorrectly passed a NULL cred to a vnode operation
1309 	 * either on purpose or by calling CRED() in interrupt context.
1310 	 */
1311 	if (cr == NULL)
1312 		return (NULL);
1313 
1314 	if (cr->cr_ksid != NULL) {
1315 		if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) {
1316 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1317 			return (eph_zsd->eph_nobody);
1318 		}
1319 
1320 		if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) {
1321 			eph_zsd = get_ephemeral_zsd(crgetzone(cr));
1322 			return (eph_zsd->eph_nobody);
1323 		}
1324 	}
1325 
1326 	return ((cred_t *)cr);
1327 }
1328 
1329 /* index should be in range for a ksidindex_t */
1330 void
1331 crsetsid(cred_t *cr, ksid_t *ksp, int index)
1332 {
1333 	ASSERT(cr->cr_ref <= 2);
1334 	ASSERT(index >= 0 && index < KSID_COUNT);
1335 	if (cr->cr_ksid == NULL && ksp == NULL)
1336 		return;
1337 	cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index);
1338 }
1339 
1340 void
1341 crsetsidlist(cred_t *cr, ksidlist_t *ksl)
1342 {
1343 	ASSERT(cr->cr_ref <= 2);
1344 	if (cr->cr_ksid == NULL && ksl == NULL)
1345 		return;
1346 	cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl);
1347 }
1348 
1349 ksid_t *
1350 crgetsid(const cred_t *cr, int i)
1351 {
1352 	ASSERT(i >= 0 && i < KSID_COUNT);
1353 	if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain)
1354 		return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]);
1355 	return (NULL);
1356 }
1357 
1358 ksidlist_t *
1359 crgetsidlist(const cred_t *cr)
1360 {
1361 	if (cr->cr_ksid != NULL)
1362 		return (cr->cr_ksid->kr_sidlist);
1363 	return (NULL);
1364 }
1365 
1366 /*
1367  * Interface to set the effective and permitted privileges for
1368  * a credential; this interface does no security checks and is
1369  * intended for kernel (file)servers creating credentials with
1370  * specific privileges.
1371  */
1372 int
1373 crsetpriv(cred_t *cr, ...)
1374 {
1375 	va_list ap;
1376 	const char *privnm;
1377 
1378 	ASSERT(cr->cr_ref <= 2);
1379 
1380 	priv_set_PA(cr);
1381 
1382 	va_start(ap, cr);
1383 
1384 	while ((privnm = va_arg(ap, const char *)) != NULL) {
1385 		int priv = priv_getbyname(privnm, 0);
1386 		if (priv < 0)
1387 			return (-1);
1388 
1389 		priv_addset(&CR_PPRIV(cr), priv);
1390 		priv_addset(&CR_EPRIV(cr), priv);
1391 	}
1392 	priv_adjust_PA(cr);
1393 	va_end(ap);
1394 	return (0);
1395 }
1396 
1397 /*
1398  * Interface to effectively set the PRIV_ALL for
1399  * a credential; this interface does no security checks and is
1400  * intended for kernel (file)servers to extend the user credentials
1401  * to be ALL, like either kcred or zcred.
1402  */
1403 void
1404 crset_zone_privall(cred_t *cr)
1405 {
1406 	zone_t	*zone = crgetzone(cr);
1407 
1408 	priv_fillset(&CR_LPRIV(cr));
1409 	CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr);
1410 	priv_intersect(zone->zone_privset, &CR_LPRIV(cr));
1411 	priv_intersect(zone->zone_privset, &CR_EPRIV(cr));
1412 	priv_intersect(zone->zone_privset, &CR_IPRIV(cr));
1413 	priv_intersect(zone->zone_privset, &CR_PPRIV(cr));
1414 }
1415 
1416 struct credklpd *
1417 crgetcrklpd(const cred_t *cr)
1418 {
1419 	return (cr->cr_klpd);
1420 }
1421 
1422 void
1423 crsetcrklpd(cred_t *cr, struct credklpd *crklpd)
1424 {
1425 	ASSERT(cr->cr_ref <= 2);
1426 
1427 	if (cr->cr_klpd != NULL)
1428 		crklpd_rele(cr->cr_klpd);
1429 	cr->cr_klpd = crklpd;
1430 }
1431 
1432 credgrp_t *
1433 crgrpcopyin(int n, gid_t *gidset)
1434 {
1435 	credgrp_t *mem;
1436 	size_t sz = CREDGRPSZ(n);
1437 
1438 	ASSERT(n > 0);
1439 
1440 	mem = kmem_alloc(sz, KM_SLEEP);
1441 
1442 	if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) {
1443 		kmem_free(mem, sz);
1444 		return (NULL);
1445 	}
1446 	mem->crg_ref = 1;
1447 	mem->crg_ngroups = n;
1448 	qsort(mem->crg_groups, n, sizeof (gid_t), gidcmp);
1449 	return (mem);
1450 }
1451 
1452 const gid_t *
1453 crgetggroups(const credgrp_t *grps)
1454 {
1455 	return (grps->crg_groups);
1456 }
1457 
1458 void
1459 crsetcredgrp(cred_t *cr, credgrp_t *grps)
1460 {
1461 	ASSERT(cr->cr_ref <= 2);
1462 
1463 	if (cr->cr_grps != NULL)
1464 		crgrprele(cr->cr_grps);
1465 
1466 	cr->cr_grps = grps;
1467 }
1468 
1469 void
1470 crgrprele(credgrp_t *grps)
1471 {
1472 	if (atomic_dec_32_nv(&grps->crg_ref) == 0)
1473 		kmem_free(grps, CREDGRPSZ(grps->crg_ngroups));
1474 }
1475 
1476 static void
1477 crgrphold(credgrp_t *grps)
1478 {
1479 	atomic_inc_32(&grps->crg_ref);
1480 }
1481