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