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