10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
54321Scasper * Common Development and Distribution License (the "License").
64321Scasper * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12273SCasper.Dik@Sun.COM * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
270Sstevel@tonic-gate */
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/tuneable.h>
340Sstevel@tonic-gate #include <sys/cred_impl.h>
350Sstevel@tonic-gate #include <sys/errno.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/signal.h>
380Sstevel@tonic-gate #include <sys/debug.h>
390Sstevel@tonic-gate #include <sys/policy.h>
400Sstevel@tonic-gate #include <sys/zone.h>
414321Scasper #include <sys/sid.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate int
setuid(uid_t uid)440Sstevel@tonic-gate setuid(uid_t uid)
450Sstevel@tonic-gate {
464321Scasper proc_t *p;
470Sstevel@tonic-gate int error;
480Sstevel@tonic-gate int do_nocd = 0;
490Sstevel@tonic-gate int uidchge = 0;
500Sstevel@tonic-gate cred_t *cr, *newcr;
510Sstevel@tonic-gate uid_t oldruid = uid;
520Sstevel@tonic-gate zoneid_t zoneid = getzoneid();
534321Scasper ksid_t ksid, *ksp;
545771Sjp151216 zone_t *zone = crgetzone(CRED());
550Sstevel@tonic-gate
565771Sjp151216 if (!VALID_UID(uid, zone))
570Sstevel@tonic-gate return (set_errno(EINVAL));
580Sstevel@tonic-gate
594321Scasper if (uid > MAXUID) {
605771Sjp151216 if (ksid_lookupbyuid(zone, uid, &ksid) != 0)
614321Scasper return (set_errno(EINVAL));
624321Scasper ksp = &ksid;
634321Scasper } else {
644321Scasper ksp = NULL;
654321Scasper }
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate * Need to pre-allocate the new cred structure before grabbing
686134Scasper * the p_crlock mutex. We can't hold on to the p_crlock for most
696134Scasper * if this though, now that we allow kernel upcalls from the
706134Scasper * policy routines.
710Sstevel@tonic-gate */
724321Scasper newcr = cralloc_ksid();
730Sstevel@tonic-gate
740Sstevel@tonic-gate p = ttoproc(curthread);
750Sstevel@tonic-gate
760Sstevel@tonic-gate retry:
770Sstevel@tonic-gate mutex_enter(&p->p_crlock);
786134Scasper retry_locked:
790Sstevel@tonic-gate cr = p->p_cred;
806134Scasper crhold(cr);
816134Scasper mutex_exit(&p->p_crlock);
820Sstevel@tonic-gate
830Sstevel@tonic-gate if ((uid == cr->cr_ruid || uid == cr->cr_suid) &&
840Sstevel@tonic-gate secpolicy_allow_setid(cr, uid, B_TRUE) != 0) {
856134Scasper mutex_enter(&p->p_crlock);
866134Scasper crfree(cr);
876134Scasper if (cr != p->p_cred)
886134Scasper goto retry_locked;
890Sstevel@tonic-gate error = 0;
900Sstevel@tonic-gate crcopy_to(cr, newcr);
910Sstevel@tonic-gate p->p_cred = newcr;
920Sstevel@tonic-gate newcr->cr_uid = uid;
934321Scasper crsetsid(newcr, ksp, KSID_USER);
946134Scasper mutex_exit(&p->p_crlock);
950Sstevel@tonic-gate } else if ((error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) {
966134Scasper mutex_enter(&p->p_crlock);
976134Scasper crfree(cr);
986134Scasper if (cr != p->p_cred)
996134Scasper goto retry_locked;
1000Sstevel@tonic-gate if (!uidchge && uid != cr->cr_ruid) {
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * The ruid of the process is going to change. In order
1030Sstevel@tonic-gate * to avoid a race condition involving the
1040Sstevel@tonic-gate * process-count associated with the newly given ruid,
1050Sstevel@tonic-gate * we increment the count before assigning the
1060Sstevel@tonic-gate * credential to the process.
1070Sstevel@tonic-gate * To do that, we'll have to take pidlock, so we first
1080Sstevel@tonic-gate * release p_crlock.
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate mutex_exit(&p->p_crlock);
1110Sstevel@tonic-gate uidchge = 1;
1120Sstevel@tonic-gate mutex_enter(&pidlock);
1130Sstevel@tonic-gate upcount_inc(uid, zoneid);
1140Sstevel@tonic-gate mutex_exit(&pidlock);
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate * As we released p_crlock we can't rely on the cr
1170Sstevel@tonic-gate * we read. So retry the whole thing.
1180Sstevel@tonic-gate */
1190Sstevel@tonic-gate goto retry;
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate * A privileged process that gives up its privilege
1230Sstevel@tonic-gate * must be marked to produce no core dump.
1240Sstevel@tonic-gate */
1250Sstevel@tonic-gate if (cr->cr_uid != uid ||
1260Sstevel@tonic-gate cr->cr_ruid != uid ||
1270Sstevel@tonic-gate cr->cr_suid != uid)
1280Sstevel@tonic-gate do_nocd = 1;
1290Sstevel@tonic-gate oldruid = cr->cr_ruid;
1300Sstevel@tonic-gate crcopy_to(cr, newcr);
1310Sstevel@tonic-gate p->p_cred = newcr;
1320Sstevel@tonic-gate newcr->cr_ruid = uid;
1330Sstevel@tonic-gate newcr->cr_suid = uid;
1340Sstevel@tonic-gate newcr->cr_uid = uid;
135*12273SCasper.Dik@Sun.COM
136*12273SCasper.Dik@Sun.COM /* Remove the PRIV_PFEXEC, we changed the real uid. */
137*12273SCasper.Dik@Sun.COM if (uidchge)
138*12273SCasper.Dik@Sun.COM CR_FLAGS(newcr) &= ~PRIV_PFEXEC;
139*12273SCasper.Dik@Sun.COM
1404321Scasper crsetsid(newcr, ksp, KSID_USER);
1419799SCasper.Dik@Sun.COM
1429799SCasper.Dik@Sun.COM priv_reset_PA(newcr, B_TRUE);
1439799SCasper.Dik@Sun.COM
1440Sstevel@tonic-gate ASSERT(uid != oldruid ? uidchge : 1);
1456134Scasper mutex_exit(&p->p_crlock);
1464321Scasper } else {
1470Sstevel@tonic-gate crfree(newcr);
1486134Scasper crfree(cr);
1494321Scasper if (ksp != NULL)
1504321Scasper ksid_rele(ksp);
1514321Scasper }
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate * We decrement the number of processes associated with the oldruid
1550Sstevel@tonic-gate * to match the increment above, even if the ruid of the process
1560Sstevel@tonic-gate * did not change or an error occurred (oldruid == uid).
1570Sstevel@tonic-gate */
1580Sstevel@tonic-gate if (uidchge) {
1590Sstevel@tonic-gate mutex_enter(&pidlock);
1600Sstevel@tonic-gate upcount_dec(oldruid, zoneid);
1610Sstevel@tonic-gate mutex_exit(&pidlock);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (error == 0) {
1650Sstevel@tonic-gate if (do_nocd) {
1660Sstevel@tonic-gate mutex_enter(&p->p_lock);
1670Sstevel@tonic-gate p->p_flag |= SNOCD;
1680Sstevel@tonic-gate mutex_exit(&p->p_lock);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate crset(p, newcr); /* broadcast to process threads */
1710Sstevel@tonic-gate return (0);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate return (set_errno(error));
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate int64_t
getuid(void)1770Sstevel@tonic-gate getuid(void)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate rval_t r;
1800Sstevel@tonic-gate cred_t *cr;
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate cr = curthread->t_cred;
1830Sstevel@tonic-gate r.r_val1 = cr->cr_ruid;
1840Sstevel@tonic-gate r.r_val2 = cr->cr_uid;
1850Sstevel@tonic-gate return (r.r_vals);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate int
seteuid(uid_t uid)1890Sstevel@tonic-gate seteuid(uid_t uid)
1900Sstevel@tonic-gate {
1914321Scasper proc_t *p;
1920Sstevel@tonic-gate int error = EPERM;
1930Sstevel@tonic-gate int do_nocd = 0;
1940Sstevel@tonic-gate cred_t *cr, *newcr;
1954321Scasper ksid_t ksid, *ksp;
1965771Sjp151216 zone_t *zone = crgetzone(CRED());
1970Sstevel@tonic-gate
1985771Sjp151216 if (!VALID_UID(uid, zone))
1990Sstevel@tonic-gate return (set_errno(EINVAL));
2000Sstevel@tonic-gate
2014321Scasper if (uid > MAXUID) {
2025771Sjp151216 if (ksid_lookupbyuid(zone, uid, &ksid) != 0)
2034321Scasper return (set_errno(EINVAL));
2044321Scasper ksp = &ksid;
2054321Scasper } else {
2064321Scasper ksp = NULL;
2074321Scasper }
2084321Scasper
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate * Need to pre-allocate the new cred structure before grabbing
2110Sstevel@tonic-gate * the p_crlock mutex.
2120Sstevel@tonic-gate */
2134321Scasper newcr = cralloc_ksid();
2140Sstevel@tonic-gate p = ttoproc(curthread);
2150Sstevel@tonic-gate mutex_enter(&p->p_crlock);
2166134Scasper retry:
2176134Scasper crhold(cr = p->p_cred);
2186134Scasper mutex_exit(&p->p_crlock);
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate if (uid == cr->cr_ruid || uid == cr->cr_uid || uid == cr->cr_suid ||
2210Sstevel@tonic-gate (error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) {
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate * A privileged process that makes itself look like a
2240Sstevel@tonic-gate * set-uid process must be marked to produce no core dump,
2250Sstevel@tonic-gate * if the effective uid did changed.
2260Sstevel@tonic-gate */
2276134Scasper mutex_enter(&p->p_crlock);
2286134Scasper crfree(cr);
2296134Scasper if (cr != p->p_cred)
2306134Scasper goto retry;
2310Sstevel@tonic-gate if (cr->cr_uid != uid && error == 0)
2320Sstevel@tonic-gate do_nocd = 1;
2330Sstevel@tonic-gate error = 0;
2340Sstevel@tonic-gate crcopy_to(cr, newcr);
2350Sstevel@tonic-gate p->p_cred = newcr;
2360Sstevel@tonic-gate newcr->cr_uid = uid;
2374321Scasper crsetsid(newcr, ksp, KSID_USER);
2389799SCasper.Dik@Sun.COM priv_reset_PA(newcr, B_FALSE);
2396134Scasper mutex_exit(&p->p_crlock);
2400Sstevel@tonic-gate if (do_nocd) {
2410Sstevel@tonic-gate mutex_enter(&p->p_lock);
2420Sstevel@tonic-gate p->p_flag |= SNOCD;
2430Sstevel@tonic-gate mutex_exit(&p->p_lock);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate crset(p, newcr); /* broadcast to process threads */
2460Sstevel@tonic-gate return (0);
2470Sstevel@tonic-gate }
2486134Scasper
2496134Scasper crfree(newcr);
2506134Scasper crfree(cr);
2516134Scasper if (ksp != NULL)
2526134Scasper ksid_rele(ksp);
2530Sstevel@tonic-gate return (set_errno(error));
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate * Buy-back from SunOS 4.x
2580Sstevel@tonic-gate *
2590Sstevel@tonic-gate * Like setuid() and seteuid() combined -except- that non-root users
2600Sstevel@tonic-gate * can change cr_ruid to cr_uid, and the semantics of cr_suid are
2610Sstevel@tonic-gate * subtly different.
2620Sstevel@tonic-gate */
2630Sstevel@tonic-gate int
setreuid(uid_t ruid,uid_t euid)2640Sstevel@tonic-gate setreuid(uid_t ruid, uid_t euid)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate proc_t *p;
2670Sstevel@tonic-gate int error = 0;
2680Sstevel@tonic-gate int do_nocd = 0;
2690Sstevel@tonic-gate int uidchge = 0;
2700Sstevel@tonic-gate uid_t oldruid = ruid;
2710Sstevel@tonic-gate cred_t *cr, *newcr;
2720Sstevel@tonic-gate zoneid_t zoneid = getzoneid();
2734321Scasper ksid_t ksid, *ksp;
2745771Sjp151216 zone_t *zone = crgetzone(CRED());
2750Sstevel@tonic-gate
2765771Sjp151216 if ((ruid != -1 && !VALID_UID(ruid, zone)) ||
2775771Sjp151216 (euid != -1 && !VALID_UID(euid, zone)))
2780Sstevel@tonic-gate return (set_errno(EINVAL));
2790Sstevel@tonic-gate
2804321Scasper if (euid != -1 && euid > MAXUID) {
2815771Sjp151216 if (ksid_lookupbyuid(zone, euid, &ksid) != 0)
2824321Scasper return (set_errno(EINVAL));
2834321Scasper ksp = &ksid;
2844321Scasper } else {
2854321Scasper ksp = NULL;
2864321Scasper }
2874321Scasper
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * Need to pre-allocate the new cred structure before grabbing
2900Sstevel@tonic-gate * the p_crlock mutex.
2910Sstevel@tonic-gate */
2924321Scasper newcr = cralloc_ksid();
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate p = ttoproc(curthread);
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate retry:
2970Sstevel@tonic-gate mutex_enter(&p->p_crlock);
2986134Scasper retry_locked:
2996134Scasper crhold(cr = p->p_cred);
3006134Scasper mutex_exit(&p->p_crlock);
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate if (ruid != -1 && ruid != cr->cr_ruid && ruid != cr->cr_uid &&
3030Sstevel@tonic-gate secpolicy_allow_setid(cr, ruid, B_FALSE) != 0) {
3046134Scasper mutex_enter(&p->p_crlock);
3056134Scasper crfree(cr);
3066134Scasper if (cr != p->p_cred)
3076134Scasper goto retry_locked;
3080Sstevel@tonic-gate error = EPERM;
3090Sstevel@tonic-gate } else if (euid != -1 &&
3100Sstevel@tonic-gate euid != cr->cr_ruid && euid != cr->cr_uid &&
3110Sstevel@tonic-gate euid != cr->cr_suid && secpolicy_allow_setid(cr, euid, B_FALSE)) {
3126134Scasper mutex_enter(&p->p_crlock);
3136134Scasper crfree(cr);
3146134Scasper if (cr != p->p_cred)
3156134Scasper goto retry_locked;
3160Sstevel@tonic-gate error = EPERM;
3170Sstevel@tonic-gate } else {
3186134Scasper mutex_enter(&p->p_crlock);
3196134Scasper crfree(cr);
3206134Scasper if (cr != p->p_cred)
3216134Scasper goto retry_locked;
3220Sstevel@tonic-gate if (!uidchge && ruid != -1 && cr->cr_ruid != ruid) {
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate * The ruid of the process is going to change. In order
3250Sstevel@tonic-gate * to avoid a race condition involving the
3260Sstevel@tonic-gate * process-count associated with the newly given ruid,
3270Sstevel@tonic-gate * we increment the count before assigning the
3280Sstevel@tonic-gate * credential to the process.
3290Sstevel@tonic-gate * To do that, we'll have to take pidlock, so we first
3300Sstevel@tonic-gate * release p_crlock.
3310Sstevel@tonic-gate */
3320Sstevel@tonic-gate mutex_exit(&p->p_crlock);
3330Sstevel@tonic-gate uidchge = 1;
3340Sstevel@tonic-gate mutex_enter(&pidlock);
3350Sstevel@tonic-gate upcount_inc(ruid, zoneid);
3360Sstevel@tonic-gate mutex_exit(&pidlock);
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate * As we released p_crlock we can't rely on the cr
3390Sstevel@tonic-gate * we read. So retry the whole thing.
3400Sstevel@tonic-gate */
3410Sstevel@tonic-gate goto retry;
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate crhold(cr);
3440Sstevel@tonic-gate crcopy_to(cr, newcr);
3450Sstevel@tonic-gate p->p_cred = newcr;
3460Sstevel@tonic-gate
3474321Scasper if (euid != -1) {
3480Sstevel@tonic-gate newcr->cr_uid = euid;
3494321Scasper crsetsid(newcr, ksp, KSID_USER);
3504321Scasper }
3510Sstevel@tonic-gate if (ruid != -1) {
352*12273SCasper.Dik@Sun.COM /* Remove the PRIV_PFEXEC, we changed the real uid. */
353*12273SCasper.Dik@Sun.COM if (uidchge)
354*12273SCasper.Dik@Sun.COM CR_FLAGS(newcr) &= ~PRIV_PFEXEC;
355*12273SCasper.Dik@Sun.COM
3560Sstevel@tonic-gate oldruid = newcr->cr_ruid;
3570Sstevel@tonic-gate newcr->cr_ruid = ruid;
3580Sstevel@tonic-gate ASSERT(ruid != oldruid ? uidchge : 1);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * "If the real uid is being changed, or the effective uid is
3620Sstevel@tonic-gate * being changed to a value not equal to the real uid, the
3630Sstevel@tonic-gate * saved uid is set to the new effective uid."
3640Sstevel@tonic-gate */
3650Sstevel@tonic-gate if (ruid != -1 ||
3660Sstevel@tonic-gate (euid != -1 && newcr->cr_uid != newcr->cr_ruid))
3670Sstevel@tonic-gate newcr->cr_suid = newcr->cr_uid;
3680Sstevel@tonic-gate /*
3690Sstevel@tonic-gate * A process that gives up its privilege
3700Sstevel@tonic-gate * must be marked to produce no core dump.
3710Sstevel@tonic-gate */
3720Sstevel@tonic-gate if ((cr->cr_uid != newcr->cr_uid ||
3730Sstevel@tonic-gate cr->cr_ruid != newcr->cr_ruid ||
3740Sstevel@tonic-gate cr->cr_suid != newcr->cr_suid))
3750Sstevel@tonic-gate do_nocd = 1;
3760Sstevel@tonic-gate
3779799SCasper.Dik@Sun.COM priv_reset_PA(newcr, ruid != -1 && euid != -1 && ruid == euid);
3780Sstevel@tonic-gate crfree(cr);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate mutex_exit(&p->p_crlock);
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate * We decrement the number of processes associated with the oldruid
3840Sstevel@tonic-gate * to match the increment above, even if the ruid of the process
3850Sstevel@tonic-gate * did not change or an error occurred (oldruid == uid).
3860Sstevel@tonic-gate */
3870Sstevel@tonic-gate if (uidchge) {
3880Sstevel@tonic-gate ASSERT(oldruid != -1 && ruid != -1);
3890Sstevel@tonic-gate mutex_enter(&pidlock);
3900Sstevel@tonic-gate upcount_dec(oldruid, zoneid);
3910Sstevel@tonic-gate mutex_exit(&pidlock);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate if (error == 0) {
3950Sstevel@tonic-gate if (do_nocd) {
3960Sstevel@tonic-gate mutex_enter(&p->p_lock);
3970Sstevel@tonic-gate p->p_flag |= SNOCD;
3980Sstevel@tonic-gate mutex_exit(&p->p_lock);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate crset(p, newcr); /* broadcast to process threads */
4010Sstevel@tonic-gate return (0);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate crfree(newcr);
4044321Scasper if (ksp != NULL)
4054321Scasper ksid_rele(ksp);
4060Sstevel@tonic-gate return (set_errno(error));
4070Sstevel@tonic-gate }
408