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