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