Home | History | Annotate | Download | only in syscall
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  *	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
     28  */
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 #include <sys/param.h>
     33 #include <sys/types.h>
     34 #include <sys/sysmacros.h>
     35 #include <sys/systm.h>
     36 #include <sys/cred_impl.h>
     37 #include <sys/errno.h>
     38 #include <sys/proc.h>
     39 #include <sys/debug.h>
     40 #include <sys/policy.h>
     41 
     42 
     43 int
     44 setgid(gid_t gid)
     45 {
     46 	proc_t *p;
     47 	int error;
     48 	int do_nocd = 0;
     49 	cred_t	*cr, *newcr;
     50 	ksid_t ksid, *ksp;
     51 	zone_t	*zone = crgetzone(CRED());
     52 
     53 
     54 	if (!VALID_GID(gid, zone))
     55 		return (set_errno(EINVAL));
     56 
     57 	if (gid > MAXUID) {
     58 		if (ksid_lookupbygid(zone, gid, &ksid) != 0)
     59 			return (set_errno(EINVAL));
     60 		ksp = &ksid;
     61 	} else {
     62 		ksp = NULL;
     63 	}
     64 
     65 	/*
     66 	 * Need to pre-allocate the new cred structure before grabbing
     67 	 * the p_crlock mutex.  We cannot hold the mutex across the
     68 	 * secpolicy functions.
     69 	 */
     70 	newcr = cralloc_ksid();
     71 	p = ttoproc(curthread);
     72 	mutex_enter(&p->p_crlock);
     73 retry:
     74 	cr = p->p_cred;
     75 	crhold(cr);
     76 	mutex_exit(&p->p_crlock);
     77 
     78 
     79 	if ((gid == cr->cr_rgid || gid == cr->cr_sgid) &&
     80 	    secpolicy_allow_setid(cr, -1, B_TRUE) != 0) {
     81 		mutex_enter(&p->p_crlock);
     82 		crfree(cr);
     83 		if (cr != p->p_cred)
     84 			goto retry;
     85 		error = 0;
     86 		crcopy_to(cr, newcr);
     87 		p->p_cred = newcr;
     88 		newcr->cr_gid = gid;
     89 		crsetsid(newcr, ksp, KSID_GROUP);
     90 		mutex_exit(&p->p_crlock);
     91 	} else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
     92 		mutex_enter(&p->p_crlock);
     93 		crfree(cr);
     94 		if (cr != p->p_cred)
     95 			goto retry;
     96 		/*
     97 		 * A privileged process that makes itself look like a
     98 		 * set-gid process must be marked to produce no core dump.
     99 		 */
    100 		if (cr->cr_gid != gid ||
    101 		    cr->cr_rgid != gid ||
    102 		    cr->cr_sgid != gid)
    103 			do_nocd = 1;
    104 		crcopy_to(cr, newcr);
    105 		p->p_cred = newcr;
    106 		newcr->cr_gid = gid;
    107 		newcr->cr_rgid = gid;
    108 		newcr->cr_sgid = gid;
    109 		crsetsid(newcr, ksp, KSID_GROUP);
    110 		mutex_exit(&p->p_crlock);
    111 	} else {
    112 		crfree(newcr);
    113 		crfree(cr);
    114 		if (ksp != NULL)
    115 			ksid_rele(ksp);
    116 
    117 	}
    118 
    119 	if (error == 0) {
    120 		if (do_nocd) {
    121 			mutex_enter(&p->p_lock);
    122 			p->p_flag |= SNOCD;
    123 			mutex_exit(&p->p_lock);
    124 		}
    125 		crset(p, newcr);	/* broadcast to process threads */
    126 		return (0);
    127 	}
    128 	return (set_errno(error));
    129 }
    130 
    131 int64_t
    132 getgid(void)
    133 {
    134 	rval_t	r;
    135 	cred_t	*cr;
    136 
    137 	cr = curthread->t_cred;
    138 	r.r_val1 = cr->cr_rgid;
    139 	r.r_val2 = cr->cr_gid;
    140 	return (r.r_vals);
    141 }
    142 
    143 int
    144 setegid(gid_t gid)
    145 {
    146 	proc_t *p;
    147 	cred_t	*cr, *newcr;
    148 	int error = EPERM;
    149 	int do_nocd = 0;
    150 	ksid_t ksid, *ksp;
    151 	zone_t	*zone = crgetzone(CRED());
    152 
    153 	if (!VALID_GID(gid, zone))
    154 		return (set_errno(EINVAL));
    155 
    156 	if (gid > MAXUID) {
    157 		if (ksid_lookupbygid(zone, gid, &ksid) != 0)
    158 			return (set_errno(EINVAL));
    159 		ksp = &ksid;
    160 	} else {
    161 		ksp = NULL;
    162 	}
    163 	/*
    164 	 * Need to pre-allocate the new cred structure before grabbing
    165 	 * the p_crlock mutex.
    166 	 */
    167 	newcr = cralloc_ksid();
    168 	p = ttoproc(curthread);
    169 	mutex_enter(&p->p_crlock);
    170 retry:
    171 	crhold(cr = p->p_cred);
    172 	mutex_exit(&p->p_crlock);
    173 
    174 	if (gid == cr->cr_rgid || gid == cr->cr_gid || gid == cr->cr_sgid ||
    175 	    (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
    176 		mutex_enter(&p->p_crlock);
    177 		crfree(cr);
    178 		if (cr != p->p_cred)
    179 			goto retry;
    180 		/*
    181 		 * A privileged process that makes itself look like a
    182 		 * set-gid process must be marked to produce no core dump.
    183 		 */
    184 		if (cr->cr_gid != gid && error == 0)
    185 			do_nocd = 1;
    186 		error = 0;
    187 		crcopy_to(cr, newcr);
    188 		p->p_cred = newcr;
    189 		newcr->cr_gid = gid;
    190 		crsetsid(newcr, ksp, KSID_GROUP);
    191 		mutex_exit(&p->p_crlock);
    192 	} else {
    193 		crfree(newcr);
    194 		crfree(cr);
    195 		if (ksp != NULL)
    196 			ksid_rele(ksp);
    197 	}
    198 
    199 	if (error == 0) {
    200 		if (do_nocd) {
    201 			mutex_enter(&p->p_lock);
    202 			p->p_flag |= SNOCD;
    203 			mutex_exit(&p->p_lock);
    204 		}
    205 		crset(p, newcr);	/* broadcast to process threads */
    206 		return (0);
    207 	}
    208 	return (set_errno(error));
    209 }
    210 
    211 /*
    212  * Buy-back from SunOS 4.x
    213  *
    214  * Like setgid() and setegid() combined -except- that non-root users
    215  * can change cr_rgid to cr_gid, and the semantics of cr_sgid are
    216  * subtly different.
    217  */
    218 int
    219 setregid(gid_t rgid, gid_t egid)
    220 {
    221 	proc_t *p;
    222 	int error = EPERM;
    223 	int do_nocd = 0;
    224 	cred_t *cr, *newcr;
    225 	ksid_t ksid, *ksp;
    226 	zone_t	*zone = crgetzone(CRED());
    227 
    228 	if ((rgid != -1 && !VALID_GID(rgid, zone)) ||
    229 	    (egid != -1 && !VALID_GID(egid, zone)))
    230 		return (set_errno(EINVAL));
    231 
    232 	if (egid != -1 && egid > MAXUID) {
    233 		if (ksid_lookupbygid(zone, egid, &ksid) != 0)
    234 			return (set_errno(EINVAL));
    235 		ksp = &ksid;
    236 	} else {
    237 		ksp = NULL;
    238 	}
    239 	/*
    240 	 * Need to pre-allocate the new cred structure before grabbing
    241 	 * the p_crlock mutex.
    242 	 */
    243 	newcr = cralloc_ksid();
    244 
    245 	p = ttoproc(curthread);
    246 	mutex_enter(&p->p_crlock);
    247 	cr = p->p_cred;
    248 
    249 	if ((rgid == -1 ||
    250 	    rgid == cr->cr_rgid || rgid == cr->cr_gid || rgid == cr->cr_sgid) &&
    251 	    (egid == -1 || egid == cr->cr_rgid || egid == cr->cr_gid ||
    252 	    egid == cr->cr_sgid) ||
    253 	    (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
    254 		crhold(cr);
    255 		crcopy_to(cr, newcr);
    256 		p->p_cred = newcr;
    257 
    258 		if (egid != -1) {
    259 			newcr->cr_gid = egid;
    260 			crsetsid(newcr, ksp, KSID_GROUP);
    261 		}
    262 		if (rgid != -1)
    263 			newcr->cr_rgid = rgid;
    264 		/*
    265 		 * "If the real gid is being changed, or the effective gid is
    266 		 * being changed to a value not equal to the real gid, the
    267 		 * saved gid is set to the new effective gid."
    268 		 */
    269 		if (rgid != -1 ||
    270 		    (egid != -1 && newcr->cr_gid != newcr->cr_rgid))
    271 			newcr->cr_sgid = newcr->cr_gid;
    272 		/*
    273 		 * A privileged process that makes itself look like a
    274 		 * set-gid process must be marked to produce no core dump.
    275 		 */
    276 		if ((cr->cr_gid != newcr->cr_gid ||
    277 		    cr->cr_rgid != newcr->cr_rgid ||
    278 		    cr->cr_sgid != newcr->cr_sgid) && error == 0)
    279 			do_nocd = 1;
    280 		error = 0;
    281 		crfree(cr);
    282 	}
    283 	mutex_exit(&p->p_crlock);
    284 
    285 	if (error == 0) {
    286 		if (do_nocd) {
    287 			mutex_enter(&p->p_lock);
    288 			p->p_flag |= SNOCD;
    289 			mutex_exit(&p->p_lock);
    290 		}
    291 		crset(p, newcr);	/* broadcast to process threads */
    292 		return (0);
    293 	}
    294 	crfree(newcr);
    295 	if (ksp != NULL)
    296 		ksid_rele(ksp);
    297 	return (set_errno(error));
    298 }
    299