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