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. 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