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