1 /* $OpenBSD: kern_prot.c,v 1.36 2008/10/31 17:17:04 deraadt 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; 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 237 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 238 return (EPERM); 239 } else { 240 (void)enterpgrp(p, p->p_pid, 1); 241 *retval = p->p_pid; 242 return (0); 243 } 244 } 245 246 /* 247 * set process group (setpgid/old setpgrp) 248 * 249 * caller does setpgid(targpid, targpgid) 250 * 251 * pid must be caller or child of caller (ESRCH) 252 * if a child 253 * pid must be in same session (EPERM) 254 * pid can't have done an exec (EACCES) 255 * if pgid != pid 256 * there must exist some pid in same session having pgid (EPERM) 257 * pid must not be session leader (EPERM) 258 */ 259 /* ARGSUSED */ 260 int 261 sys_setpgid(struct proc *curp, void *v, register_t *retval) 262 { 263 struct sys_setpgid_args /* { 264 syscallarg(pid_t) pid; 265 syscallarg(int) pgid; 266 } */ *uap = v; 267 struct proc *targp; /* target process */ 268 struct pgrp *pgrp; /* target pgrp */ 269 pid_t pid; 270 int pgid; 271 272 pid = SCARG(uap, pid); 273 pgid = SCARG(uap, pgid); 274 275 if (pgid < 0) 276 return (EINVAL); 277 278 if (pid != 0 && pid != curp->p_pid) { 279 if ((targp = pfind(pid)) == 0 || !inferior(targp)) 280 return (ESRCH); 281 if (targp->p_session != curp->p_session) 282 return (EPERM); 283 if (targp->p_flag & P_EXEC) 284 return (EACCES); 285 } else 286 targp = curp; 287 if (SESS_LEADER(targp)) 288 return (EPERM); 289 if (pgid == 0) 290 pgid = targp->p_pid; 291 else if (pgid != targp->p_pid) 292 if ((pgrp = pgfind(pgid)) == 0 || 293 pgrp->pg_session != curp->p_session) 294 return (EPERM); 295 return (enterpgrp(targp, pgid, 0)); 296 } 297 298 /* ARGSUSED */ 299 int 300 sys_getresuid(struct proc *p, void *v, register_t *retval) 301 { 302 struct sys_getresuid_args /* { 303 syscallarg(uid_t *) ruid; 304 syscallarg(uid_t *) euid; 305 syscallarg(uid_t *) suid; 306 } */ *uap = v; 307 struct pcred *pc = p->p_cred; 308 uid_t *ruid, *euid, *suid; 309 int error1 = 0, error2 = 0, error3 = 0; 310 311 ruid = SCARG(uap, ruid); 312 euid = SCARG(uap, euid); 313 suid = SCARG(uap, suid); 314 315 if (ruid != NULL) 316 error1 = copyout(&pc->p_ruid, ruid, sizeof(*ruid)); 317 if (euid != NULL) 318 error2 = copyout(&pc->pc_ucred->cr_uid, euid, sizeof(*euid)); 319 if (suid != NULL) 320 error3 = copyout(&pc->p_svuid, suid, sizeof(*suid)); 321 322 return (error1 ? error1 : error2 ? error2 : error3); 323 } 324 325 /* ARGSUSED */ 326 int 327 sys_setresuid(struct proc *p, void *v, register_t *retval) 328 { 329 struct sys_setresuid_args /* { 330 syscallarg(uid_t) ruid; 331 syscallarg(uid_t) euid; 332 syscallarg(uid_t) suid; 333 } */ *uap = v; 334 struct pcred *pc = p->p_cred; 335 uid_t ruid, euid, suid; 336 int error; 337 338 ruid = SCARG(uap, ruid); 339 euid = SCARG(uap, euid); 340 suid = SCARG(uap, suid); 341 342 if ((ruid == -1 || ruid == pc->p_ruid) && 343 (euid == -1 || euid == pc->pc_ucred->cr_uid) && 344 (suid == -1 || suid == pc->p_svuid)) 345 return (0); /* no change */ 346 347 /* 348 * Any of the real, effective, and saved uids may be changed 349 * to the current value of one of the three (root is not limited). 350 */ 351 if (ruid != (uid_t)-1 && 352 ruid != pc->p_ruid && 353 ruid != pc->pc_ucred->cr_uid && 354 ruid != pc->p_svuid && 355 (error = suser(p, 0))) 356 return (error); 357 358 if (euid != (uid_t)-1 && 359 euid != pc->p_ruid && 360 euid != pc->pc_ucred->cr_uid && 361 euid != pc->p_svuid && 362 (error = suser(p, 0))) 363 return (error); 364 365 if (suid != (uid_t)-1 && 366 suid != pc->p_ruid && 367 suid != pc->pc_ucred->cr_uid && 368 suid != pc->p_svuid && 369 (error = suser(p, 0))) 370 return (error); 371 372 /* 373 * Note that unlike the other set*uid() calls, each 374 * uid type is set independently of the others. 375 */ 376 if (ruid != (uid_t)-1 && ruid != pc->p_ruid) { 377 /* 378 * Transfer proc count to new user. 379 */ 380 (void)chgproccnt(pc->p_ruid, -p->p_p->ps_refcnt); 381 (void)chgproccnt(ruid, p->p_p->ps_refcnt); 382 pc->p_ruid = ruid; 383 } 384 if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) { 385 /* 386 * Copy credentials so other references do not see our changes. 387 */ 388 pc->pc_ucred = crcopy(pc->pc_ucred); 389 pc->pc_ucred->cr_uid = euid; 390 } 391 if (suid != (uid_t)-1 && suid != pc->p_svuid) 392 pc->p_svuid = suid; 393 394 atomic_setbits_int(&p->p_flag, P_SUGID); 395 return (0); 396 } 397 398 /* ARGSUSED */ 399 int 400 sys_getresgid(struct proc *p, void *v, register_t *retval) 401 { 402 struct sys_getresgid_args /* { 403 syscallarg(gid_t *) rgid; 404 syscallarg(gid_t *) egid; 405 syscallarg(gid_t *) sgid; 406 } */ *uap = v; 407 struct pcred *pc = p->p_cred; 408 gid_t *rgid, *egid, *sgid; 409 int error1 = 0, error2 = 0, error3 = 0; 410 411 rgid = SCARG(uap, rgid); 412 egid = SCARG(uap, egid); 413 sgid = SCARG(uap, sgid); 414 415 if (rgid != NULL) 416 error1 = copyout(&pc->p_rgid, rgid, sizeof(*rgid)); 417 if (egid != NULL) 418 error2 = copyout(&pc->pc_ucred->cr_gid, egid, sizeof(*egid)); 419 if (sgid != NULL) 420 error3 = copyout(&pc->p_svgid, sgid, sizeof(*sgid)); 421 422 return (error1 ? error1 : error2 ? error2 : error3); 423 } 424 425 /* ARGSUSED */ 426 int 427 sys_setresgid(struct proc *p, void *v, register_t *retval) 428 { 429 struct sys_setresgid_args /* { 430 syscallarg(gid_t) rgid; 431 syscallarg(gid_t) egid; 432 syscallarg(gid_t) sgid; 433 } */ *uap = v; 434 struct pcred *pc = p->p_cred; 435 gid_t rgid, egid, sgid; 436 int error; 437 438 rgid = SCARG(uap, rgid); 439 egid = SCARG(uap, egid); 440 sgid = SCARG(uap, sgid); 441 442 if ((rgid == -1 || rgid == pc->p_rgid) && 443 (egid == -1 || egid == pc->pc_ucred->cr_gid) && 444 (sgid == -1 || sgid == pc->p_svgid)) 445 return (0); /* no change */ 446 447 /* 448 * Any of the real, effective, and saved gids may be changed 449 * to the current value of one of the three (root is not limited). 450 */ 451 if (rgid != (gid_t)-1 && 452 rgid != pc->p_rgid && 453 rgid != pc->pc_ucred->cr_gid && 454 rgid != pc->p_svgid && 455 (error = suser(p, 0))) 456 return (error); 457 458 if (egid != (gid_t)-1 && 459 egid != pc->p_rgid && 460 egid != pc->pc_ucred->cr_gid && 461 egid != pc->p_svgid && 462 (error = suser(p, 0))) 463 return (error); 464 465 if (sgid != (gid_t)-1 && 466 sgid != pc->p_rgid && 467 sgid != pc->pc_ucred->cr_gid && 468 sgid != pc->p_svgid && 469 (error = suser(p, 0))) 470 return (error); 471 472 /* 473 * Note that unlike the other set*gid() calls, each 474 * gid type is set independently of the others. 475 */ 476 if (rgid != (gid_t)-1) 477 pc->p_rgid = rgid; 478 if (egid != (gid_t)-1) { 479 /* 480 * Copy credentials so other references do not see our changes. 481 */ 482 pc->pc_ucred = crcopy(pc->pc_ucred); 483 pc->pc_ucred->cr_gid = egid; 484 } 485 if (sgid != (gid_t)-1) 486 pc->p_svgid = sgid; 487 488 atomic_setbits_int(&p->p_flag, P_SUGID); 489 return (0); 490 } 491 492 /* ARGSUSED */ 493 int 494 sys_setregid(struct proc *p, void *v, register_t *retval) 495 { 496 struct sys_setregid_args /* { 497 syscallarg(gid_t) rgid; 498 syscallarg(gid_t) egid; 499 } */ *uap = v; 500 struct pcred *pc = p->p_cred; 501 struct sys_setresgid_args sresgidargs; 502 gid_t rgid, egid; 503 504 rgid = SCARG(&sresgidargs, rgid) = SCARG(uap, rgid); 505 egid = SCARG(&sresgidargs, egid) = SCARG(uap, egid); 506 507 /* 508 * The saved gid presents a bit of a dilemma, as it did not 509 * exist when setregid(2) was conceived. We only set the saved 510 * gid when the real gid is specified and either its value would 511 * change, or where the saved and effective gids are different. 512 */ 513 if (rgid != (gid_t)-1 && (rgid != pc->p_rgid || 514 pc->p_svgid != (egid != (gid_t)-1 ? egid : pc->pc_ucred->cr_gid))) 515 SCARG(&sresgidargs, sgid) = rgid; 516 else 517 SCARG(&sresgidargs, sgid) = (gid_t)-1; 518 519 return (sys_setresgid(p, &sresgidargs, retval)); 520 } 521 522 /* ARGSUSED */ 523 int 524 sys_setreuid(struct proc *p, void *v, register_t *retval) 525 { 526 struct sys_setreuid_args /* { 527 syscallarg(uid_t) ruid; 528 syscallarg(uid_t) euid; 529 } */ *uap = v; 530 struct pcred *pc = p->p_cred; 531 struct sys_setresuid_args sresuidargs; 532 uid_t ruid, euid; 533 534 ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid); 535 euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid); 536 537 /* 538 * The saved uid presents a bit of a dilemma, as it did not 539 * exist when setreuid(2) was conceived. We only set the saved 540 * uid when the real uid is specified and either its value would 541 * change, or where the saved and effective uids are different. 542 */ 543 if (ruid != (uid_t)-1 && (ruid != pc->p_ruid || 544 pc->p_svuid != (euid != (uid_t)-1 ? euid : pc->pc_ucred->cr_uid))) 545 SCARG(&sresuidargs, suid) = ruid; 546 else 547 SCARG(&sresuidargs, suid) = (uid_t)-1; 548 549 return (sys_setresuid(p, &sresuidargs, retval)); 550 } 551 552 /* ARGSUSED */ 553 int 554 sys_setuid(struct proc *p, void *v, register_t *retval) 555 { 556 struct sys_setuid_args /* { 557 syscallarg(uid_t) uid; 558 } */ *uap = v; 559 struct pcred *pc = p->p_cred; 560 uid_t uid; 561 int error; 562 563 uid = SCARG(uap, uid); 564 565 if (pc->pc_ucred->cr_uid == uid && 566 pc->p_ruid == uid && 567 pc->p_svuid == uid) 568 return (0); 569 570 if (uid != pc->p_ruid && 571 uid != pc->p_svuid && 572 uid != pc->pc_ucred->cr_uid && 573 (error = suser(p, 0))) 574 return (error); 575 576 /* 577 * Everything's okay, do it. 578 */ 579 if (uid == pc->pc_ucred->cr_uid || 580 suser(p, 0) == 0) { 581 /* 582 * Transfer proc count to new user. 583 */ 584 if (uid != pc->p_ruid) { 585 (void)chgproccnt(pc->p_ruid, -p->p_p->ps_refcnt); 586 (void)chgproccnt(uid, p->p_p->ps_refcnt); 587 } 588 pc->p_ruid = uid; 589 pc->p_svuid = uid; 590 } 591 592 /* 593 * Copy credentials so other references do not see our changes. 594 */ 595 pc->pc_ucred = crcopy(pc->pc_ucred); 596 pc->pc_ucred->cr_uid = uid; 597 atomic_setbits_int(&p->p_flag, P_SUGID); 598 return (0); 599 } 600 601 /* ARGSUSED */ 602 int 603 sys_seteuid(struct proc *p, void *v, register_t *retval) 604 { 605 struct sys_seteuid_args /* { 606 syscallarg(uid_t) euid; 607 } */ *uap = v; 608 struct pcred *pc = p->p_cred; 609 uid_t euid; 610 int error; 611 612 euid = SCARG(uap, euid); 613 614 if (pc->pc_ucred->cr_uid == euid) 615 return (0); 616 617 if (euid != pc->p_ruid && euid != pc->p_svuid && 618 (error = suser(p, 0))) 619 return (error); 620 621 /* 622 * Copy credentials so other references do not see our changes. 623 */ 624 pc->pc_ucred = crcopy(pc->pc_ucred); 625 pc->pc_ucred->cr_uid = euid; 626 atomic_setbits_int(&p->p_flag, P_SUGID); 627 return (0); 628 } 629 630 /* ARGSUSED */ 631 int 632 sys_setgid(struct proc *p, void *v, register_t *retval) 633 { 634 struct sys_setgid_args /* { 635 syscallarg(gid_t) gid; 636 } */ *uap = v; 637 struct pcred *pc = p->p_cred; 638 gid_t gid; 639 int error; 640 641 gid = SCARG(uap, gid); 642 643 if (pc->pc_ucred->cr_gid == gid && 644 pc->p_rgid == gid && 645 pc->p_svgid == gid) 646 return (0); 647 648 if (gid != pc->p_rgid && 649 gid != pc->p_svgid && 650 gid != pc->pc_ucred->cr_gid && 651 (error = suser(p, 0))) 652 return (error); 653 654 if (gid == pc->pc_ucred->cr_gid || 655 suser(p, 0) == 0) { 656 pc->p_rgid = gid; 657 pc->p_svgid = gid; 658 } 659 660 /* 661 * Copy credentials so other references do not see our changes. 662 */ 663 pc->pc_ucred = crcopy(pc->pc_ucred); 664 pc->pc_ucred->cr_gid = gid; 665 atomic_setbits_int(&p->p_flag, P_SUGID); 666 return (0); 667 } 668 669 /* ARGSUSED */ 670 int 671 sys_setegid(struct proc *p, void *v, register_t *retval) 672 { 673 struct sys_setegid_args /* { 674 syscallarg(gid_t) egid; 675 } */ *uap = v; 676 struct pcred *pc = p->p_cred; 677 gid_t egid; 678 int error; 679 680 egid = SCARG(uap, egid); 681 682 if (pc->pc_ucred->cr_gid == egid) 683 return (0); 684 685 if (egid != pc->p_rgid && egid != pc->p_svgid && 686 (error = suser(p, 0))) 687 return (error); 688 689 /* 690 * Copy credentials so other references do not see our changes. 691 */ 692 pc->pc_ucred = crcopy(pc->pc_ucred); 693 pc->pc_ucred->cr_gid = egid; 694 atomic_setbits_int(&p->p_flag, P_SUGID); 695 return (0); 696 } 697 698 /* ARGSUSED */ 699 int 700 sys_setgroups(struct proc *p, void *v, register_t *retval) 701 { 702 struct sys_setgroups_args /* { 703 syscallarg(int) gidsetsize; 704 syscallarg(const gid_t *) gidset; 705 } */ *uap = v; 706 struct pcred *pc = p->p_cred; 707 u_int ngrp; 708 int error; 709 710 if ((error = suser(p, 0)) != 0) 711 return (error); 712 ngrp = SCARG(uap, gidsetsize); 713 if (ngrp > NGROUPS) 714 return (EINVAL); 715 pc->pc_ucred = crcopy(pc->pc_ucred); 716 error = copyin((caddr_t)SCARG(uap, gidset), 717 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)); 718 if (error) 719 return (error); 720 pc->pc_ucred->cr_ngroups = ngrp; 721 atomic_setbits_int(&p->p_flag, P_SUGID); 722 return (0); 723 } 724 725 /* 726 * Check if gid is a member of the group set. 727 */ 728 int 729 groupmember(gid_t gid, struct ucred *cred) 730 { 731 gid_t *gp; 732 gid_t *egp; 733 734 egp = &(cred->cr_groups[cred->cr_ngroups]); 735 for (gp = cred->cr_groups; gp < egp; gp++) 736 if (*gp == gid) 737 return (1); 738 return (0); 739 } 740 741 /* 742 * Test whether this process has special user powers. 743 * Returns 0 or error. 744 */ 745 int 746 suser(struct proc *p, u_int flags) 747 { 748 struct ucred *cred = p->p_ucred; 749 750 if (cred->cr_uid == 0) { 751 if (!(flags & SUSER_NOACCT)) 752 p->p_acflag |= ASU; 753 return (0); 754 } 755 return (EPERM); 756 } 757 758 /* 759 * replacement for old suser, for callers who don't have a process 760 */ 761 int 762 suser_ucred(struct ucred *cred) 763 { 764 if (cred->cr_uid == 0) 765 return (0); 766 return (EPERM); 767 } 768 769 /* 770 * Allocate a zeroed cred structure. 771 */ 772 struct ucred * 773 crget(void) 774 { 775 struct ucred *cr; 776 777 cr = pool_get(&ucred_pool, PR_WAITOK|PR_ZERO); 778 cr->cr_ref = 1; 779 return (cr); 780 } 781 782 /* 783 * Free a cred structure. 784 * Throws away space when ref count gets to 0. 785 */ 786 void 787 crfree(struct ucred *cr) 788 { 789 790 if (--cr->cr_ref == 0) 791 pool_put(&ucred_pool, cr); 792 } 793 794 /* 795 * Copy cred structure to a new one and free the old one. 796 */ 797 struct ucred * 798 crcopy(struct ucred *cr) 799 { 800 struct ucred *newcr; 801 802 if (cr->cr_ref == 1) 803 return (cr); 804 newcr = crget(); 805 *newcr = *cr; 806 crfree(cr); 807 newcr->cr_ref = 1; 808 return (newcr); 809 } 810 811 /* 812 * Dup cred struct to a new held one. 813 */ 814 struct ucred * 815 crdup(struct ucred *cr) 816 { 817 struct ucred *newcr; 818 819 newcr = crget(); 820 *newcr = *cr; 821 newcr->cr_ref = 1; 822 return (newcr); 823 } 824 825 /* 826 * Get login name, if available. 827 */ 828 /* ARGSUSED */ 829 int 830 sys_getlogin(struct proc *p, void *v, register_t *retval) 831 { 832 struct sys_getlogin_args /* { 833 syscallarg(char *) namebuf; 834 syscallarg(u_int) namelen; 835 } */ *uap = v; 836 837 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 838 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 839 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 840 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 841 } 842 843 /* 844 * Set login name. 845 */ 846 /* ARGSUSED */ 847 int 848 sys_setlogin(struct proc *p, void *v, register_t *retval) 849 { 850 struct sys_setlogin_args /* { 851 syscallarg(const char *) namebuf; 852 } */ *uap = v; 853 int error; 854 855 if ((error = suser(p, 0)) != 0) 856 return (error); 857 error = copyinstr((caddr_t) SCARG(uap, namebuf), 858 (caddr_t) p->p_pgrp->pg_session->s_login, 859 sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0); 860 if (error == ENAMETOOLONG) 861 error = EINVAL; 862 return (error); 863 } 864 865 /* 866 * Check if a process is allowed to raise its privileges. 867 */ 868 int 869 proc_cansugid(struct proc *p) 870 { 871 /* ptrace(2)d processes shouldn't. */ 872 if ((p->p_flag & P_TRACED) != 0) 873 return (0); 874 875 /* proceses with shared filedescriptors shouldn't. */ 876 if (p->p_fd->fd_refcnt > 1) 877 return (0); 878 879 /* Allow. */ 880 return (1); 881 } 882