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