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