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