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