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/tuneable.h> 37 #include <sys/cred_impl.h> 38 #include <sys/errno.h> 39 #include <sys/proc.h> 40 #include <sys/signal.h> 41 #include <sys/debug.h> 42 #include <sys/policy.h> 43 #include <sys/zone.h> 44 #include <sys/sid.h> 45 46 int 47 setuid(uid_t uid) 48 { 49 proc_t *p; 50 int error; 51 int do_nocd = 0; 52 int uidchge = 0; 53 cred_t *cr, *newcr; 54 uid_t oldruid = uid; 55 zoneid_t zoneid = getzoneid(); 56 ksid_t ksid, *ksp; 57 58 if (!VALID_UID(uid)) 59 return (set_errno(EINVAL)); 60 61 if (uid > MAXUID) { 62 if (ksid_lookupbyuid(uid, &ksid) != 0) 63 return (set_errno(EINVAL)); 64 ksp = &ksid; 65 } else { 66 ksp = NULL; 67 } 68 /* 69 * Need to pre-allocate the new cred structure before grabbing 70 * the p_crlock mutex. 71 */ 72 newcr = cralloc_ksid(); 73 74 p = ttoproc(curthread); 75 76 retry: 77 mutex_enter(&p->p_crlock); 78 cr = p->p_cred; 79 80 if ((uid == cr->cr_ruid || uid == cr->cr_suid) && 81 secpolicy_allow_setid(cr, uid, B_TRUE) != 0) { 82 error = 0; 83 crcopy_to(cr, newcr); 84 p->p_cred = newcr; 85 newcr->cr_uid = uid; 86 crsetsid(newcr, ksp, KSID_USER); 87 } else if ((error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { 88 if (!uidchge && uid != cr->cr_ruid) { 89 /* 90 * The ruid of the process is going to change. In order 91 * to avoid a race condition involving the 92 * process-count associated with the newly given ruid, 93 * we increment the count before assigning the 94 * credential to the process. 95 * To do that, we'll have to take pidlock, so we first 96 * release p_crlock. 97 */ 98 mutex_exit(&p->p_crlock); 99 uidchge = 1; 100 mutex_enter(&pidlock); 101 upcount_inc(uid, zoneid); 102 mutex_exit(&pidlock); 103 /* 104 * As we released p_crlock we can't rely on the cr 105 * we read. So retry the whole thing. 106 */ 107 goto retry; 108 } 109 /* 110 * A privileged process that gives up its privilege 111 * must be marked to produce no core dump. 112 */ 113 if (cr->cr_uid != uid || 114 cr->cr_ruid != uid || 115 cr->cr_suid != uid) 116 do_nocd = 1; 117 oldruid = cr->cr_ruid; 118 crcopy_to(cr, newcr); 119 p->p_cred = newcr; 120 newcr->cr_ruid = uid; 121 newcr->cr_suid = uid; 122 newcr->cr_uid = uid; 123 crsetsid(newcr, ksp, KSID_USER); 124 ASSERT(uid != oldruid ? uidchge : 1); 125 } else { 126 crfree(newcr); 127 if (ksp != NULL) 128 ksid_rele(ksp); 129 } 130 131 mutex_exit(&p->p_crlock); 132 133 /* 134 * We decrement the number of processes associated with the oldruid 135 * to match the increment above, even if the ruid of the process 136 * did not change or an error occurred (oldruid == uid). 137 */ 138 if (uidchge) { 139 mutex_enter(&pidlock); 140 upcount_dec(oldruid, zoneid); 141 mutex_exit(&pidlock); 142 } 143 144 if (error == 0) { 145 if (do_nocd) { 146 mutex_enter(&p->p_lock); 147 p->p_flag |= SNOCD; 148 mutex_exit(&p->p_lock); 149 } 150 crset(p, newcr); /* broadcast to process threads */ 151 return (0); 152 } 153 return (set_errno(error)); 154 } 155 156 int64_t 157 getuid(void) 158 { 159 rval_t r; 160 cred_t *cr; 161 162 cr = curthread->t_cred; 163 r.r_val1 = cr->cr_ruid; 164 r.r_val2 = cr->cr_uid; 165 return (r.r_vals); 166 } 167 168 int 169 seteuid(uid_t uid) 170 { 171 proc_t *p; 172 int error = EPERM; 173 int do_nocd = 0; 174 cred_t *cr, *newcr; 175 ksid_t ksid, *ksp; 176 177 if (!VALID_UID(uid)) 178 return (set_errno(EINVAL)); 179 180 if (uid > MAXUID) { 181 if (ksid_lookupbyuid(uid, &ksid) != 0) 182 return (set_errno(EINVAL)); 183 ksp = &ksid; 184 } else { 185 ksp = NULL; 186 } 187 188 /* 189 * Need to pre-allocate the new cred structure before grabbing 190 * the p_crlock mutex. 191 */ 192 newcr = cralloc_ksid(); 193 p = ttoproc(curthread); 194 mutex_enter(&p->p_crlock); 195 cr = p->p_cred; 196 197 if (uid == cr->cr_ruid || uid == cr->cr_uid || uid == cr->cr_suid || 198 (error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { 199 /* 200 * A privileged process that makes itself look like a 201 * set-uid process must be marked to produce no core dump, 202 * if the effective uid did changed. 203 */ 204 if (cr->cr_uid != uid && error == 0) 205 do_nocd = 1; 206 error = 0; 207 crcopy_to(cr, newcr); 208 p->p_cred = newcr; 209 newcr->cr_uid = uid; 210 crsetsid(newcr, ksp, KSID_USER); 211 } else { 212 crfree(newcr); 213 if (ksp != NULL) 214 ksid_rele(ksp); 215 } 216 217 mutex_exit(&p->p_crlock); 218 219 if (error == 0) { 220 if (do_nocd) { 221 mutex_enter(&p->p_lock); 222 p->p_flag |= SNOCD; 223 mutex_exit(&p->p_lock); 224 } 225 crset(p, newcr); /* broadcast to process threads */ 226 return (0); 227 } 228 return (set_errno(error)); 229 } 230 231 /* 232 * Buy-back from SunOS 4.x 233 * 234 * Like setuid() and seteuid() combined -except- that non-root users 235 * can change cr_ruid to cr_uid, and the semantics of cr_suid are 236 * subtly different. 237 */ 238 int 239 setreuid(uid_t ruid, uid_t euid) 240 { 241 proc_t *p; 242 int error = 0; 243 int do_nocd = 0; 244 int uidchge = 0; 245 uid_t oldruid = ruid; 246 cred_t *cr, *newcr; 247 zoneid_t zoneid = getzoneid(); 248 ksid_t ksid, *ksp; 249 250 if ((ruid != -1 && !VALID_UID(ruid)) || 251 (euid != -1 && !VALID_UID(euid))) 252 return (set_errno(EINVAL)); 253 254 if (euid != -1 && euid > MAXUID) { 255 if (ksid_lookupbyuid(euid, &ksid) != 0) 256 return (set_errno(EINVAL)); 257 ksp = &ksid; 258 } else { 259 ksp = NULL; 260 } 261 262 /* 263 * Need to pre-allocate the new cred structure before grabbing 264 * the p_crlock mutex. 265 */ 266 newcr = cralloc_ksid(); 267 268 p = ttoproc(curthread); 269 270 retry: 271 mutex_enter(&p->p_crlock); 272 cr = p->p_cred; 273 274 if (ruid != -1 && ruid != cr->cr_ruid && ruid != cr->cr_uid && 275 secpolicy_allow_setid(cr, ruid, B_FALSE) != 0) { 276 error = EPERM; 277 } else if (euid != -1 && 278 euid != cr->cr_ruid && euid != cr->cr_uid && 279 euid != cr->cr_suid && secpolicy_allow_setid(cr, euid, B_FALSE)) { 280 error = EPERM; 281 } else { 282 if (!uidchge && ruid != -1 && cr->cr_ruid != ruid) { 283 /* 284 * The ruid of the process is going to change. In order 285 * to avoid a race condition involving the 286 * process-count associated with the newly given ruid, 287 * we increment the count before assigning the 288 * credential to the process. 289 * To do that, we'll have to take pidlock, so we first 290 * release p_crlock. 291 */ 292 mutex_exit(&p->p_crlock); 293 uidchge = 1; 294 mutex_enter(&pidlock); 295 upcount_inc(ruid, zoneid); 296 mutex_exit(&pidlock); 297 /* 298 * As we released p_crlock we can't rely on the cr 299 * we read. So retry the whole thing. 300 */ 301 goto retry; 302 } 303 crhold(cr); 304 crcopy_to(cr, newcr); 305 p->p_cred = newcr; 306 307 if (euid != -1) { 308 newcr->cr_uid = euid; 309 crsetsid(newcr, ksp, KSID_USER); 310 } 311 if (ruid != -1) { 312 oldruid = newcr->cr_ruid; 313 newcr->cr_ruid = ruid; 314 ASSERT(ruid != oldruid ? uidchge : 1); 315 } 316 /* 317 * "If the real uid is being changed, or the effective uid is 318 * being changed to a value not equal to the real uid, the 319 * saved uid is set to the new effective uid." 320 */ 321 if (ruid != -1 || 322 (euid != -1 && newcr->cr_uid != newcr->cr_ruid)) 323 newcr->cr_suid = newcr->cr_uid; 324 /* 325 * A process that gives up its privilege 326 * must be marked to produce no core dump. 327 */ 328 if ((cr->cr_uid != newcr->cr_uid || 329 cr->cr_ruid != newcr->cr_ruid || 330 cr->cr_suid != newcr->cr_suid)) 331 do_nocd = 1; 332 333 crfree(cr); 334 } 335 mutex_exit(&p->p_crlock); 336 337 /* 338 * We decrement the number of processes associated with the oldruid 339 * to match the increment above, even if the ruid of the process 340 * did not change or an error occurred (oldruid == uid). 341 */ 342 if (uidchge) { 343 ASSERT(oldruid != -1 && ruid != -1); 344 mutex_enter(&pidlock); 345 upcount_dec(oldruid, zoneid); 346 mutex_exit(&pidlock); 347 } 348 349 if (error == 0) { 350 if (do_nocd) { 351 mutex_enter(&p->p_lock); 352 p->p_flag |= SNOCD; 353 mutex_exit(&p->p_lock); 354 } 355 crset(p, newcr); /* broadcast to process threads */ 356 return (0); 357 } 358 crfree(newcr); 359 if (ksp != NULL) 360 ksid_rele(ksp); 361 return (set_errno(error)); 362 } 363