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	"@(#)gid.c	1.17	08/01/04 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.
     68 	 */
     69 	newcr = cralloc_ksid();
     70 	p = ttoproc(curthread);
     71 	mutex_enter(&p->p_crlock);
     72 	cr = p->p_cred;
     73 
     74 	if ((gid == cr->cr_rgid || gid == cr->cr_sgid) &&
     75 	    secpolicy_allow_setid(cr, -1, B_TRUE) != 0) {
     76 		error = 0;
     77 		crcopy_to(cr, newcr);
     78 		p->p_cred = newcr;
     79 		newcr->cr_gid = gid;
     80 		crsetsid(newcr, ksp, KSID_GROUP);
     81 	} else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
     82 		/*
     83 		 * A privileged process that makes itself look like a
     84 		 * set-gid process must be marked to produce no core dump.
     85 		 */
     86 		if (cr->cr_gid != gid ||
     87 		    cr->cr_rgid != gid ||
     88 		    cr->cr_sgid != gid)
     89 			do_nocd = 1;
     90 		crcopy_to(cr, newcr);
     91 		p->p_cred = newcr;
     92 		newcr->cr_gid = gid;
     93 		newcr->cr_rgid = gid;
     94 		newcr->cr_sgid = gid;
     95 		crsetsid(newcr, ksp, KSID_GROUP);
     96 	} else {
     97 		crfree(newcr);
     98 		if (ksp != NULL)
     99 			ksid_rele(ksp);
    100 
    101 	}
    102 
    103 	mutex_exit(&p->p_crlock);
    104 
    105 	if (error == 0) {
    106 		if (do_nocd) {
    107 			mutex_enter(&p->p_lock);
    108 			p->p_flag |= SNOCD;
    109 			mutex_exit(&p->p_lock);
    110 		}
    111 		crset(p, newcr);	/* broadcast to process threads */
    112 		return (0);
    113 	}
    114 	return (set_errno(error));
    115 }
    116 
    117 int64_t
    118 getgid(void)
    119 {
    120 	rval_t	r;
    121 	cred_t	*cr;
    122 
    123 	cr = curthread->t_cred;
    124 	r.r_val1 = cr->cr_rgid;
    125 	r.r_val2 = cr->cr_gid;
    126 	return (r.r_vals);
    127 }
    128 
    129 int
    130 setegid(gid_t gid)
    131 {
    132 	proc_t *p;
    133 	cred_t	*cr, *newcr;
    134 	int error = EPERM;
    135 	int do_nocd = 0;
    136 	ksid_t ksid, *ksp;
    137 	zone_t	*zone = crgetzone(CRED());
    138 
    139 	if (!VALID_GID(gid, zone))
    140 		return (set_errno(EINVAL));
    141 
    142 	if (gid > MAXUID) {
    143 		if (ksid_lookupbygid(zone, gid, &ksid) != 0)
    144 			return (set_errno(EINVAL));
    145 		ksp = &ksid;
    146 	} else {
    147 		ksp = NULL;
    148 	}
    149 	/*
    150 	 * Need to pre-allocate the new cred structure before grabbing
    151 	 * the p_crlock mutex.
    152 	 */
    153 	newcr = cralloc_ksid();
    154 	p = ttoproc(curthread);
    155 	mutex_enter(&p->p_crlock);
    156 	cr = p->p_cred;
    157 	if (gid == cr->cr_rgid || gid == cr->cr_gid || gid == cr->cr_sgid ||
    158 	    (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
    159 		/*
    160 		 * A privileged process that makes itself look like a
    161 		 * set-gid process must be marked to produce no core dump.
    162 		 */
    163 		if (cr->cr_gid != gid && error == 0)
    164 			do_nocd = 1;
    165 		error = 0;
    166 		crcopy_to(cr, newcr);
    167 		p->p_cred = newcr;
    168 		newcr->cr_gid = gid;
    169 		crsetsid(newcr, ksp, KSID_GROUP);
    170 	} else {
    171 		crfree(newcr);
    172 		if (ksp != NULL)
    173 			ksid_rele(ksp);
    174 	}
    175 
    176 	mutex_exit(&p->p_crlock);
    177 
    178 	if (error == 0) {
    179 		if (do_nocd) {
    180 			mutex_enter(&p->p_lock);
    181 			p->p_flag |= SNOCD;
    182 			mutex_exit(&p->p_lock);
    183 		}
    184 		crset(p, newcr);	/* broadcast to process threads */
    185 		return (0);
    186 	}
    187 	return (set_errno(error));
    188 }
    189 
    190 /*
    191  * Buy-back from SunOS 4.x
    192  *
    193  * Like setgid() and setegid() combined -except- that non-root users
    194  * can change cr_rgid to cr_gid, and the semantics of cr_sgid are
    195  * subtly different.
    196  */
    197 int
    198 setregid(gid_t rgid, gid_t egid)
    199 {
    200 	proc_t *p;
    201 	int error = EPERM;
    202 	int do_nocd = 0;
    203 	cred_t *cr, *newcr;
    204 	ksid_t ksid, *ksp;
    205 	zone_t	*zone = crgetzone(CRED());
    206 
    207 	if ((rgid != -1 && !VALID_GID(rgid, zone)) ||
    208 	    (egid != -1 && !VALID_GID(egid, zone)))
    209 		return (set_errno(EINVAL));
    210 
    211 	if (egid != -1 && egid > MAXUID) {
    212 		if (ksid_lookupbygid(zone, egid, &ksid) != 0)
    213 			return (set_errno(EINVAL));
    214 		ksp = &ksid;
    215 	} else {
    216 		ksp = NULL;
    217 	}
    218 	/*
    219 	 * Need to pre-allocate the new cred structure before grabbing
    220 	 * the p_crlock mutex.
    221 	 */
    222 	newcr = cralloc_ksid();
    223 
    224 	p = ttoproc(curthread);
    225 	mutex_enter(&p->p_crlock);
    226 	cr = p->p_cred;
    227 
    228 	if ((rgid == -1 ||
    229 	    rgid == cr->cr_rgid || rgid == cr->cr_gid || rgid == cr->cr_sgid) &&
    230 	    (egid == -1 || egid == cr->cr_rgid || egid == cr->cr_gid ||
    231 	    egid == cr->cr_sgid) ||
    232 	    (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
    233 		crhold(cr);
    234 		crcopy_to(cr, newcr);
    235 		p->p_cred = newcr;
    236 
    237 		if (egid != -1) {
    238 			newcr->cr_gid = egid;
    239 			crsetsid(newcr, ksp, KSID_GROUP);
    240 		}
    241 		if (rgid != -1)
    242 			newcr->cr_rgid = rgid;
    243 		/*
    244 		 * "If the real gid is being changed, or the effective gid is
    245 		 * being changed to a value not equal to the real gid, the
    246 		 * saved gid is set to the new effective gid."
    247 		 */
    248 		if (rgid != -1 ||
    249 		    (egid != -1 && newcr->cr_gid != newcr->cr_rgid))
    250 			newcr->cr_sgid = newcr->cr_gid;
    251 		/*
    252 		 * A privileged process that makes itself look like a
    253 		 * set-gid process must be marked to produce no core dump.
    254 		 */
    255 		if ((cr->cr_gid != newcr->cr_gid ||
    256 		    cr->cr_rgid != newcr->cr_rgid ||
    257 		    cr->cr_sgid != newcr->cr_sgid) && error == 0)
    258 			do_nocd = 1;
    259 		error = 0;
    260 		crfree(cr);
    261 	}
    262 	mutex_exit(&p->p_crlock);
    263 
    264 	if (error == 0) {
    265 		if (do_nocd) {
    266 			mutex_enter(&p->p_lock);
    267 			p->p_flag |= SNOCD;
    268 			mutex_exit(&p->p_lock);
    269 		}
    270 		crset(p, newcr);	/* broadcast to process threads */
    271 		return (0);
    272 	}
    273 	crfree(newcr);
    274 	if (ksp != NULL)
    275 		ksid_rele(ksp);
    276 	return (set_errno(error));
    277 }
    278