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