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