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