1 /* $OpenBSD: kern_prot.c,v 1.24 2003/06/02 23:28:05 millert 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 620 return (error); 621 622 /* 623 * Everything's okay, do it. 624 */ 625 if (uid == pc->pc_ucred->cr_uid || 626 suser(pc->pc_ucred, &p->p_acflag) == 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(pc->pc_ucred, &p->p_acflag))) 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(pc->pc_ucred, &p->p_acflag))) 704 return (error); 705 706 if (gid == pc->pc_ucred->cr_gid || 707 suser(pc->pc_ucred, &p->p_acflag) == 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(pc->pc_ucred, &p->p_acflag))) 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(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(pc->pc_ucred, &p->p_acflag)) != 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 the specified credentials imply "super-user" 803 * privilege; if so, and we have accounting info, set the flag 804 * indicating use of super-powers. 805 * Returns 0 or error. 806 */ 807 int 808 suser(cred, acflag) 809 struct ucred *cred; 810 u_short *acflag; 811 { 812 if (cred->cr_uid == 0) { 813 if (acflag) 814 *acflag |= ASU; 815 return (0); 816 } 817 return (EPERM); 818 } 819 820 /* 821 * Allocate a zeroed cred structure. 822 */ 823 struct ucred * 824 crget() 825 { 826 struct ucred *cr; 827 828 cr = pool_get(&ucred_pool, PR_WAITOK); 829 bzero((caddr_t)cr, sizeof(*cr)); 830 cr->cr_ref = 1; 831 return (cr); 832 } 833 834 /* 835 * Free a cred structure. 836 * Throws away space when ref count gets to 0. 837 */ 838 void 839 crfree(cr) 840 struct ucred *cr; 841 { 842 843 if (--cr->cr_ref == 0) 844 pool_put(&ucred_pool, cr); 845 } 846 847 /* 848 * Copy cred structure to a new one and free the old one. 849 */ 850 struct ucred * 851 crcopy(cr) 852 struct ucred *cr; 853 { 854 struct ucred *newcr; 855 856 if (cr->cr_ref == 1) 857 return (cr); 858 newcr = crget(); 859 *newcr = *cr; 860 crfree(cr); 861 newcr->cr_ref = 1; 862 return (newcr); 863 } 864 865 /* 866 * Dup cred struct to a new held one. 867 */ 868 struct ucred * 869 crdup(cr) 870 struct ucred *cr; 871 { 872 struct ucred *newcr; 873 874 newcr = crget(); 875 *newcr = *cr; 876 newcr->cr_ref = 1; 877 return (newcr); 878 } 879 880 /* 881 * Get login name, if available. 882 */ 883 /* ARGSUSED */ 884 int 885 sys_getlogin(p, v, retval) 886 struct proc *p; 887 void *v; 888 register_t *retval; 889 { 890 struct sys_getlogin_args /* { 891 syscallarg(char *) namebuf; 892 syscallarg(u_int) namelen; 893 } */ *uap = v; 894 895 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 896 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 897 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 898 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 899 } 900 901 /* 902 * Set login name. 903 */ 904 /* ARGSUSED */ 905 int 906 sys_setlogin(p, v, retval) 907 struct proc *p; 908 void *v; 909 register_t *retval; 910 { 911 struct sys_setlogin_args /* { 912 syscallarg(char *) namebuf; 913 } */ *uap = v; 914 int error; 915 916 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 917 return (error); 918 error = copyinstr((caddr_t) SCARG(uap, namebuf), 919 (caddr_t) p->p_pgrp->pg_session->s_login, 920 sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0); 921 if (error == ENAMETOOLONG) 922 error = EINVAL; 923 return (error); 924 } 925 926 /* 927 * Check if a process is allowed to raise its privileges. 928 */ 929 int 930 proc_cansugid(struct proc *p) 931 { 932 /* ptrace(2)d processes shouldn't. */ 933 if ((p->p_flag & P_TRACED) != 0) 934 return (0); 935 936 /* proceses with shared filedescriptors shouldn't. */ 937 if (p->p_fd->fd_refcnt > 1) 938 return (0); 939 940 /* Allow. */ 941 return (1); 942 } 943