1 /* $OpenBSD: kern_prot.c,v 1.43 2010/06/29 00:28:14 tedu Exp $ */ 2 /* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 38 */ 39 40 /* 41 * System calls related to processes and protection 42 */ 43 44 #include <sys/param.h> 45 #include <sys/acct.h> 46 #include <sys/systm.h> 47 #include <sys/ucred.h> 48 #include <sys/proc.h> 49 #include <sys/times.h> 50 #include <sys/malloc.h> 51 #include <sys/filedesc.h> 52 #include <sys/pool.h> 53 54 #include <sys/mount.h> 55 #include <sys/syscallargs.h> 56 57 /* ARGSUSED */ 58 int 59 sys_getpid(struct proc *p, void *v, register_t *retval) 60 { 61 62 *retval = p->p_p->ps_mainproc->p_pid; 63 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 64 defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 65 retval[1] = p->p_p->ps_mainproc->p_pptr->p_pid; 66 #endif 67 return (0); 68 } 69 70 /* ARGSUSED */ 71 int 72 sys_getthrid(struct proc *p, void *v, register_t *retval) 73 { 74 75 if (!rthreads_enabled) 76 return (ENOTSUP); 77 *retval = p->p_pid + (p->p_flag & P_THREAD ? 0 : THREAD_PID_OFFSET); 78 return (0); 79 } 80 81 /* ARGSUSED */ 82 int 83 sys_getppid(struct proc *p, void *v, register_t *retval) 84 { 85 86 *retval = p->p_p->ps_mainproc->p_pptr->p_pid; 87 return (0); 88 } 89 90 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 91 int 92 sys_getpgrp(struct proc *p, void *v, register_t *retval) 93 { 94 95 *retval = p->p_pgrp->pg_id; 96 return (0); 97 } 98 99 /* 100 * SysVR.4 compatible getpgid() 101 */ 102 pid_t 103 sys_getpgid(struct proc *curp, void *v, register_t *retval) 104 { 105 struct sys_getpgid_args /* { 106 syscallarg(pid_t) pid; 107 } */ *uap = v; 108 struct proc *targp = curp; 109 110 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid) 111 goto found; 112 if ((targp = pfind(SCARG(uap, pid))) == NULL) 113 return (ESRCH); 114 if (targp->p_session != curp->p_session) 115 return (EPERM); 116 found: 117 *retval = targp->p_pgid; 118 return (0); 119 } 120 121 pid_t 122 sys_getsid(struct proc *curp, void *v, register_t *retval) 123 { 124 struct sys_getsid_args /* { 125 syscallarg(pid_t) pid; 126 } */ *uap = v; 127 struct proc *targp = curp; 128 129 if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid) 130 goto found; 131 if ((targp = pfind(SCARG(uap, pid))) == NULL) 132 return (ESRCH); 133 if (targp->p_session != curp->p_session) 134 return (EPERM); 135 found: 136 /* Skip exiting processes */ 137 if (targp->p_pgrp->pg_session->s_leader == NULL) 138 return (ESRCH); 139 *retval = targp->p_pgrp->pg_session->s_leader->p_pid; 140 return (0); 141 } 142 143 /* ARGSUSED */ 144 int 145 sys_getuid(struct proc *p, void *v, register_t *retval) 146 { 147 148 *retval = p->p_cred->p_ruid; 149 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 150 defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 151 retval[1] = p->p_ucred->cr_uid; 152 #endif 153 return (0); 154 } 155 156 /* ARGSUSED */ 157 int 158 sys_geteuid(struct proc *p, void *v, register_t *retval) 159 { 160 161 *retval = p->p_ucred->cr_uid; 162 return (0); 163 } 164 165 /* ARGSUSED */ 166 int 167 sys_issetugid(struct proc *p, void *v, register_t *retval) 168 { 169 if (p->p_flag & P_SUGIDEXEC) 170 *retval = 1; 171 else 172 *retval = 0; 173 return (0); 174 } 175 176 /* ARGSUSED */ 177 int 178 sys_getgid(struct proc *p, void *v, register_t *retval) 179 { 180 181 *retval = p->p_cred->p_rgid; 182 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS) 183 retval[1] = p->p_ucred->cr_gid; 184 #endif 185 return (0); 186 } 187 188 /* 189 * Get effective group ID. The "egid" is groups[0], and could be obtained 190 * via getgroups. This syscall exists because it is somewhat painful to do 191 * correctly in a library function. 192 */ 193 /* ARGSUSED */ 194 int 195 sys_getegid(struct proc *p, void *v, register_t *retval) 196 { 197 198 *retval = p->p_ucred->cr_gid; 199 return (0); 200 } 201 202 int 203 sys_getgroups(struct proc *p, void *v, register_t *retval) 204 { 205 struct sys_getgroups_args /* { 206 syscallarg(int) gidsetsize; 207 syscallarg(gid_t *) gidset; 208 } */ *uap = v; 209 struct pcred *pc = p->p_cred; 210 u_int ngrp; 211 int error; 212 213 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 214 *retval = pc->pc_ucred->cr_ngroups; 215 return (0); 216 } 217 if (ngrp < pc->pc_ucred->cr_ngroups) 218 return (EINVAL); 219 ngrp = pc->pc_ucred->cr_ngroups; 220 error = copyout((caddr_t)pc->pc_ucred->cr_groups, 221 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)); 222 if (error) 223 return (error); 224 *retval = ngrp; 225 return (0); 226 } 227 228 /* ARGSUSED */ 229 int 230 sys_setsid(struct proc *p, void *v, register_t *retval) 231 { 232 struct session *newsess; 233 struct pgrp *newpgrp; 234 235 newsess = pool_get(&session_pool, PR_WAITOK); 236 newpgrp = pool_get(&pgrp_pool, PR_WAITOK); 237 238 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 239 pool_put(&pgrp_pool, newpgrp); 240 pool_put(&session_pool, newsess); 241 return (EPERM); 242 } else { 243 (void) enterpgrp(p, p->p_pid, newpgrp, newsess); 244 *retval = p->p_pid; 245 return (0); 246 } 247 } 248 249 /* 250 * set process group (setpgid/old setpgrp) 251 * 252 * caller does setpgid(targpid, targpgid) 253 * 254 * pid must be caller or child of caller (ESRCH) 255 * if a child 256 * pid must be in same session (EPERM) 257 * pid can't have done an exec (EACCES) 258 * if pgid != pid 259 * there must exist some pid in same session having pgid (EPERM) 260 * pid must not be session leader (EPERM) 261 */ 262 /* ARGSUSED */ 263 int 264 sys_setpgid(struct proc *curp, void *v, register_t *retval) 265 { 266 struct sys_setpgid_args /* { 267 syscallarg(pid_t) pid; 268 syscallarg(int) pgid; 269 } */ *uap = v; 270 struct proc *targp; /* target process */ 271 struct pgrp *pgrp, *newpgrp; /* target pgrp */ 272 pid_t pid; 273 int pgid, error; 274 275 pid = SCARG(uap, pid); 276 pgid = SCARG(uap, pgid); 277 278 if (pgid < 0) 279 return (EINVAL); 280 281 newpgrp = pool_get(&pgrp_pool, PR_WAITOK); 282 283 if (pid != 0 && pid != curp->p_pid) { 284 if ((targp = pfind(pid)) == 0 || !inferior(targp, curp)) { 285 error = ESRCH; 286 goto out; 287 } 288 if (targp->p_session != curp->p_session) { 289 error = EPERM; 290 goto out; 291 } 292 if (targp->p_flag & P_EXEC) { 293 error = EACCES; 294 goto out; 295 } 296 } else 297 targp = curp; 298 if (SESS_LEADER(targp)) { 299 error = EPERM; 300 goto out; 301 } 302 if (pgid == 0) 303 pgid = targp->p_pid; 304 else if (pgid != targp->p_pid) 305 if ((pgrp = pgfind(pgid)) == 0 || 306 pgrp->pg_session != curp->p_session) { 307 error = EPERM; 308 goto out; 309 } 310 return (enterpgrp(targp, pgid, newpgrp, NULL)); 311 out: 312 pool_put(&pgrp_pool, newpgrp); 313 return (error); 314 } 315 316 /* ARGSUSED */ 317 int 318 sys_getresuid(struct proc *p, void *v, register_t *retval) 319 { 320 struct sys_getresuid_args /* { 321 syscallarg(uid_t *) ruid; 322 syscallarg(uid_t *) euid; 323 syscallarg(uid_t *) suid; 324 } */ *uap = v; 325 struct pcred *pc = p->p_cred; 326 uid_t *ruid, *euid, *suid; 327 int error1 = 0, error2 = 0, error3 = 0; 328 329 ruid = SCARG(uap, ruid); 330 euid = SCARG(uap, euid); 331 suid = SCARG(uap, suid); 332 333 if (ruid != NULL) 334 error1 = copyout(&pc->p_ruid, ruid, sizeof(*ruid)); 335 if (euid != NULL) 336 error2 = copyout(&pc->pc_ucred->cr_uid, euid, sizeof(*euid)); 337 if (suid != NULL) 338 error3 = copyout(&pc->p_svuid, suid, sizeof(*suid)); 339 340 return (error1 ? error1 : error2 ? error2 : error3); 341 } 342 343 /* ARGSUSED */ 344 int 345 sys_setresuid(struct proc *p, void *v, register_t *retval) 346 { 347 struct sys_setresuid_args /* { 348 syscallarg(uid_t) ruid; 349 syscallarg(uid_t) euid; 350 syscallarg(uid_t) suid; 351 } */ *uap = v; 352 struct pcred *pc = p->p_cred; 353 uid_t ruid, euid, suid; 354 int error; 355 356 ruid = SCARG(uap, ruid); 357 euid = SCARG(uap, euid); 358 suid = SCARG(uap, suid); 359 360 if ((ruid == -1 || ruid == pc->p_ruid) && 361 (euid == -1 || euid == pc->pc_ucred->cr_uid) && 362 (suid == -1 || suid == pc->p_svuid)) 363 return (0); /* no change */ 364 365 /* 366 * Any of the real, effective, and saved uids may be changed 367 * to the current value of one of the three (root is not limited). 368 */ 369 if (ruid != (uid_t)-1 && 370 ruid != pc->p_ruid && 371 ruid != pc->pc_ucred->cr_uid && 372 ruid != pc->p_svuid && 373 (error = suser(p, 0))) 374 return (error); 375 376 if (euid != (uid_t)-1 && 377 euid != pc->p_ruid && 378 euid != pc->pc_ucred->cr_uid && 379 euid != pc->p_svuid && 380 (error = suser(p, 0))) 381 return (error); 382 383 if (suid != (uid_t)-1 && 384 suid != pc->p_ruid && 385 suid != pc->pc_ucred->cr_uid && 386 suid != pc->p_svuid && 387 (error = suser(p, 0))) 388 return (error); 389 390 /* 391 * Note that unlike the other set*uid() calls, each 392 * uid type is set independently of the others. 393 */ 394 if (ruid != (uid_t)-1 && ruid != pc->p_ruid) { 395 /* 396 * Transfer proc count to new user. 397 */ 398 (void)chgproccnt(pc->p_ruid, -p->p_p->ps_refcnt); 399 (void)chgproccnt(ruid, p->p_p->ps_refcnt); 400 pc->p_ruid = ruid; 401 } 402 if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) { 403 /* 404 * Copy credentials so other references do not see our changes. 405 */ 406 pc->pc_ucred = crcopy(pc->pc_ucred); 407 pc->pc_ucred->cr_uid = euid; 408 } 409 if (suid != (uid_t)-1 && suid != pc->p_svuid) 410 pc->p_svuid = suid; 411 412 atomic_setbits_int(&p->p_flag, P_SUGID); 413 return (0); 414 } 415 416 /* ARGSUSED */ 417 int 418 sys_getresgid(struct proc *p, void *v, register_t *retval) 419 { 420 struct sys_getresgid_args /* { 421 syscallarg(gid_t *) rgid; 422 syscallarg(gid_t *) egid; 423 syscallarg(gid_t *) sgid; 424 } */ *uap = v; 425 struct pcred *pc = p->p_cred; 426 gid_t *rgid, *egid, *sgid; 427 int error1 = 0, error2 = 0, error3 = 0; 428 429 rgid = SCARG(uap, rgid); 430 egid = SCARG(uap, egid); 431 sgid = SCARG(uap, sgid); 432 433 if (rgid != NULL) 434 error1 = copyout(&pc->p_rgid, rgid, sizeof(*rgid)); 435 if (egid != NULL) 436 error2 = copyout(&pc->pc_ucred->cr_gid, egid, sizeof(*egid)); 437 if (sgid != NULL) 438 error3 = copyout(&pc->p_svgid, sgid, sizeof(*sgid)); 439 440 return (error1 ? error1 : error2 ? error2 : error3); 441 } 442 443 /* ARGSUSED */ 444 int 445 sys_setresgid(struct proc *p, void *v, register_t *retval) 446 { 447 struct sys_setresgid_args /* { 448 syscallarg(gid_t) rgid; 449 syscallarg(gid_t) egid; 450 syscallarg(gid_t) sgid; 451 } */ *uap = v; 452 struct pcred *pc = p->p_cred; 453 gid_t rgid, egid, sgid; 454 int error; 455 456 rgid = SCARG(uap, rgid); 457 egid = SCARG(uap, egid); 458 sgid = SCARG(uap, sgid); 459 460 if ((rgid == -1 || rgid == pc->p_rgid) && 461 (egid == -1 || egid == pc->pc_ucred->cr_gid) && 462 (sgid == -1 || sgid == pc->p_svgid)) 463 return (0); /* no change */ 464 465 /* 466 * Any of the real, effective, and saved gids may be changed 467 * to the current value of one of the three (root is not limited). 468 */ 469 if (rgid != (gid_t)-1 && 470 rgid != pc->p_rgid && 471 rgid != pc->pc_ucred->cr_gid && 472 rgid != pc->p_svgid && 473 (error = suser(p, 0))) 474 return (error); 475 476 if (egid != (gid_t)-1 && 477 egid != pc->p_rgid && 478 egid != pc->pc_ucred->cr_gid && 479 egid != pc->p_svgid && 480 (error = suser(p, 0))) 481 return (error); 482 483 if (sgid != (gid_t)-1 && 484 sgid != pc->p_rgid && 485 sgid != pc->pc_ucred->cr_gid && 486 sgid != pc->p_svgid && 487 (error = suser(p, 0))) 488 return (error); 489 490 /* 491 * Note that unlike the other set*gid() calls, each 492 * gid type is set independently of the others. 493 */ 494 if (rgid != (gid_t)-1) 495 pc->p_rgid = rgid; 496 if (egid != (gid_t)-1) { 497 /* 498 * Copy credentials so other references do not see our changes. 499 */ 500 pc->pc_ucred = crcopy(pc->pc_ucred); 501 pc->pc_ucred->cr_gid = egid; 502 } 503 if (sgid != (gid_t)-1) 504 pc->p_svgid = sgid; 505 506 atomic_setbits_int(&p->p_flag, P_SUGID); 507 return (0); 508 } 509 510 /* ARGSUSED */ 511 int 512 sys_setregid(struct proc *p, void *v, register_t *retval) 513 { 514 struct sys_setregid_args /* { 515 syscallarg(gid_t) rgid; 516 syscallarg(gid_t) egid; 517 } */ *uap = v; 518 struct pcred *pc = p->p_cred; 519 struct sys_setresgid_args sresgidargs; 520 gid_t rgid, egid; 521 522 rgid = SCARG(&sresgidargs, rgid) = SCARG(uap, rgid); 523 egid = SCARG(&sresgidargs, egid) = SCARG(uap, egid); 524 525 /* 526 * The saved gid presents a bit of a dilemma, as it did not 527 * exist when setregid(2) was conceived. We only set the saved 528 * gid when the real gid is specified and either its value would 529 * change, or where the saved and effective gids are different. 530 */ 531 if (rgid != (gid_t)-1 && (rgid != pc->p_rgid || 532 pc->p_svgid != (egid != (gid_t)-1 ? egid : pc->pc_ucred->cr_gid))) 533 SCARG(&sresgidargs, sgid) = rgid; 534 else 535 SCARG(&sresgidargs, sgid) = (gid_t)-1; 536 537 return (sys_setresgid(p, &sresgidargs, retval)); 538 } 539 540 /* ARGSUSED */ 541 int 542 sys_setreuid(struct proc *p, void *v, register_t *retval) 543 { 544 struct sys_setreuid_args /* { 545 syscallarg(uid_t) ruid; 546 syscallarg(uid_t) euid; 547 } */ *uap = v; 548 struct pcred *pc = p->p_cred; 549 struct sys_setresuid_args sresuidargs; 550 uid_t ruid, euid; 551 552 ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid); 553 euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid); 554 555 /* 556 * The saved uid presents a bit of a dilemma, as it did not 557 * exist when setreuid(2) was conceived. We only set the saved 558 * uid when the real uid is specified and either its value would 559 * change, or where the saved and effective uids are different. 560 */ 561 if (ruid != (uid_t)-1 && (ruid != pc->p_ruid || 562 pc->p_svuid != (euid != (uid_t)-1 ? euid : pc->pc_ucred->cr_uid))) 563 SCARG(&sresuidargs, suid) = ruid; 564 else 565 SCARG(&sresuidargs, suid) = (uid_t)-1; 566 567 return (sys_setresuid(p, &sresuidargs, retval)); 568 } 569 570 /* ARGSUSED */ 571 int 572 sys_setuid(struct proc *p, void *v, register_t *retval) 573 { 574 struct sys_setuid_args /* { 575 syscallarg(uid_t) uid; 576 } */ *uap = v; 577 struct pcred *pc = p->p_cred; 578 uid_t uid; 579 int error; 580 581 uid = SCARG(uap, uid); 582 583 if (pc->pc_ucred->cr_uid == uid && 584 pc->p_ruid == uid && 585 pc->p_svuid == uid) 586 return (0); 587 588 if (uid != pc->p_ruid && 589 uid != pc->p_svuid && 590 uid != pc->pc_ucred->cr_uid && 591 (error = suser(p, 0))) 592 return (error); 593 594 /* 595 * Everything's okay, do it. 596 */ 597 if (uid == pc->pc_ucred->cr_uid || 598 suser(p, 0) == 0) { 599 /* 600 * Transfer proc count to new user. 601 */ 602 if (uid != pc->p_ruid) { 603 (void)chgproccnt(pc->p_ruid, -p->p_p->ps_refcnt); 604 (void)chgproccnt(uid, p->p_p->ps_refcnt); 605 } 606 pc->p_ruid = uid; 607 pc->p_svuid = uid; 608 } 609 610 /* 611 * Copy credentials so other references do not see our changes. 612 */ 613 pc->pc_ucred = crcopy(pc->pc_ucred); 614 pc->pc_ucred->cr_uid = uid; 615 atomic_setbits_int(&p->p_flag, P_SUGID); 616 return (0); 617 } 618 619 /* ARGSUSED */ 620 int 621 sys_seteuid(struct proc *p, void *v, register_t *retval) 622 { 623 struct sys_seteuid_args /* { 624 syscallarg(uid_t) euid; 625 } */ *uap = v; 626 struct pcred *pc = p->p_cred; 627 uid_t euid; 628 int error; 629 630 euid = SCARG(uap, euid); 631 632 if (pc->pc_ucred->cr_uid == euid) 633 return (0); 634 635 if (euid != pc->p_ruid && euid != pc->p_svuid && 636 (error = suser(p, 0))) 637 return (error); 638 639 /* 640 * Copy credentials so other references do not see our changes. 641 */ 642 pc->pc_ucred = crcopy(pc->pc_ucred); 643 pc->pc_ucred->cr_uid = euid; 644 atomic_setbits_int(&p->p_flag, P_SUGID); 645 return (0); 646 } 647 648 /* ARGSUSED */ 649 int 650 sys_setgid(struct proc *p, void *v, register_t *retval) 651 { 652 struct sys_setgid_args /* { 653 syscallarg(gid_t) gid; 654 } */ *uap = v; 655 struct pcred *pc = p->p_cred; 656 gid_t gid; 657 int error; 658 659 gid = SCARG(uap, gid); 660 661 if (pc->pc_ucred->cr_gid == gid && 662 pc->p_rgid == gid && 663 pc->p_svgid == gid) 664 return (0); 665 666 if (gid != pc->p_rgid && 667 gid != pc->p_svgid && 668 gid != pc->pc_ucred->cr_gid && 669 (error = suser(p, 0))) 670 return (error); 671 672 if (gid == pc->pc_ucred->cr_gid || 673 suser(p, 0) == 0) { 674 pc->p_rgid = gid; 675 pc->p_svgid = gid; 676 } 677 678 /* 679 * Copy credentials so other references do not see our changes. 680 */ 681 pc->pc_ucred = crcopy(pc->pc_ucred); 682 pc->pc_ucred->cr_gid = gid; 683 atomic_setbits_int(&p->p_flag, P_SUGID); 684 return (0); 685 } 686 687 /* ARGSUSED */ 688 int 689 sys_setegid(struct proc *p, void *v, register_t *retval) 690 { 691 struct sys_setegid_args /* { 692 syscallarg(gid_t) egid; 693 } */ *uap = v; 694 struct pcred *pc = p->p_cred; 695 gid_t egid; 696 int error; 697 698 egid = SCARG(uap, egid); 699 700 if (pc->pc_ucred->cr_gid == egid) 701 return (0); 702 703 if (egid != pc->p_rgid && egid != pc->p_svgid && 704 (error = suser(p, 0))) 705 return (error); 706 707 /* 708 * Copy credentials so other references do not see our changes. 709 */ 710 pc->pc_ucred = crcopy(pc->pc_ucred); 711 pc->pc_ucred->cr_gid = egid; 712 atomic_setbits_int(&p->p_flag, P_SUGID); 713 return (0); 714 } 715 716 /* ARGSUSED */ 717 int 718 sys_setgroups(struct proc *p, void *v, register_t *retval) 719 { 720 struct sys_setgroups_args /* { 721 syscallarg(int) gidsetsize; 722 syscallarg(const gid_t *) gidset; 723 } */ *uap = v; 724 struct pcred *pc = p->p_cred; 725 u_int ngrp; 726 int error; 727 728 if ((error = suser(p, 0)) != 0) 729 return (error); 730 ngrp = SCARG(uap, gidsetsize); 731 if (ngrp > NGROUPS) 732 return (EINVAL); 733 pc->pc_ucred = crcopy(pc->pc_ucred); 734 error = copyin((caddr_t)SCARG(uap, gidset), 735 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)); 736 if (error) 737 return (error); 738 pc->pc_ucred->cr_ngroups = ngrp; 739 atomic_setbits_int(&p->p_flag, P_SUGID); 740 return (0); 741 } 742 743 /* 744 * Check if gid is a member of the group set. 745 */ 746 int 747 groupmember(gid_t gid, struct ucred *cred) 748 { 749 gid_t *gp; 750 gid_t *egp; 751 752 egp = &(cred->cr_groups[cred->cr_ngroups]); 753 for (gp = cred->cr_groups; gp < egp; gp++) 754 if (*gp == gid) 755 return (1); 756 return (0); 757 } 758 759 /* 760 * Test whether this process has special user powers. 761 * Returns 0 or error. 762 */ 763 int 764 suser(struct proc *p, u_int flags) 765 { 766 struct ucred *cred = p->p_ucred; 767 768 if (cred->cr_uid == 0) { 769 if (!(flags & SUSER_NOACCT)) 770 p->p_acflag |= ASU; 771 return (0); 772 } 773 return (EPERM); 774 } 775 776 /* 777 * replacement for old suser, for callers who don't have a process 778 */ 779 int 780 suser_ucred(struct ucred *cred) 781 { 782 if (cred->cr_uid == 0) 783 return (0); 784 return (EPERM); 785 } 786 787 /* 788 * Allocate a zeroed cred structure. 789 */ 790 struct ucred * 791 crget(void) 792 { 793 struct ucred *cr; 794 795 cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO); 796 cr->cr_ref = 1; 797 return (cr); 798 } 799 800 /* 801 * Free a cred structure. 802 * Throws away space when ref count gets to 0. 803 */ 804 void 805 crfree(struct ucred *cr) 806 { 807 808 if (--cr->cr_ref == 0) 809 pool_put(&ucred_pool, cr); 810 } 811 812 /* 813 * Copy cred structure to a new one and free the old one. 814 */ 815 struct ucred * 816 crcopy(struct ucred *cr) 817 { 818 struct ucred *newcr; 819 820 if (cr->cr_ref == 1) 821 return (cr); 822 newcr = crget(); 823 *newcr = *cr; 824 crfree(cr); 825 newcr->cr_ref = 1; 826 return (newcr); 827 } 828 829 /* 830 * Dup cred struct to a new held one. 831 */ 832 struct ucred * 833 crdup(struct ucred *cr) 834 { 835 struct ucred *newcr; 836 837 newcr = crget(); 838 *newcr = *cr; 839 newcr->cr_ref = 1; 840 return (newcr); 841 } 842 843 /* 844 * Get login name, if available. 845 */ 846 /* ARGSUSED */ 847 int 848 sys_getlogin(struct proc *p, void *v, register_t *retval) 849 { 850 struct sys_getlogin_args /* { 851 syscallarg(char *) namebuf; 852 syscallarg(u_int) namelen; 853 } */ *uap = v; 854 855 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 856 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 857 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 858 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 859 } 860 861 /* 862 * Set login name. 863 */ 864 /* ARGSUSED */ 865 int 866 sys_setlogin(struct proc *p, void *v, register_t *retval) 867 { 868 struct sys_setlogin_args /* { 869 syscallarg(const char *) namebuf; 870 } */ *uap = v; 871 int error; 872 873 if ((error = suser(p, 0)) != 0) 874 return (error); 875 error = copyinstr((caddr_t) SCARG(uap, namebuf), 876 (caddr_t) p->p_pgrp->pg_session->s_login, 877 sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0); 878 if (error == ENAMETOOLONG) 879 error = EINVAL; 880 return (error); 881 } 882 883 /* 884 * Check if a process is allowed to raise its privileges. 885 */ 886 int 887 proc_cansugid(struct proc *p) 888 { 889 /* ptrace(2)d processes shouldn't. */ 890 if ((p->p_flag & P_TRACED) != 0) 891 return (0); 892 893 /* processes with shared filedescriptors shouldn't. */ 894 if (p->p_fd->fd_refcnt > 1) 895 return (0); 896 897 /* Allow. */ 898 return (1); 899 } 900