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