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