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