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