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