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