1 /* 2 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 39 * $Id: kern_prot.c,v 1.35 1997/10/12 20:23:54 phk Exp $ 40 */ 41 42 /* 43 * System calls related to processes and protection 44 */ 45 46 #include <sys/param.h> 47 #include <sys/acct.h> 48 #include <sys/systm.h> 49 #include <sys/sysproto.h> 50 #include <sys/proc.h> 51 #include <sys/malloc.h> 52 #include <sys/unistd.h> 53 54 static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 55 56 #ifndef _SYS_SYSPROTO_H_ 57 struct getpid_args { 58 int dummy; 59 }; 60 #endif 61 62 /* ARGSUSED */ 63 int 64 getpid(p, uap, retval) 65 struct proc *p; 66 struct getpid_args *uap; 67 int *retval; 68 { 69 70 *retval = p->p_pid; 71 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 72 retval[1] = p->p_pptr->p_pid; 73 #endif 74 return (0); 75 } 76 77 #ifndef _SYS_SYSPROTO_H_ 78 struct getppid_args { 79 int dummy; 80 }; 81 #endif 82 /* ARGSUSED */ 83 int 84 getppid(p, uap, retval) 85 struct proc *p; 86 struct getppid_args *uap; 87 int *retval; 88 { 89 90 *retval = p->p_pptr->p_pid; 91 return (0); 92 } 93 94 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 95 #ifndef _SYS_SYSPROTO_H_ 96 struct getpgrp_args { 97 int dummy; 98 }; 99 #endif 100 101 int 102 getpgrp(p, uap, retval) 103 struct proc *p; 104 struct getpgrp_args *uap; 105 int *retval; 106 { 107 108 *retval = p->p_pgrp->pg_id; 109 return (0); 110 } 111 112 /* Get an arbitary pid's process group id */ 113 #ifndef _SYS_SYSPROTO_H_ 114 struct getpgid_args { 115 pid_t pid; 116 }; 117 #endif 118 119 int 120 getpgid(p, uap, retval) 121 struct proc *p; 122 struct getpgid_args *uap; 123 int *retval; 124 { 125 if (uap->pid == 0) 126 goto found; 127 128 if ((p == pfind(uap->pid)) == 0) 129 return ESRCH; 130 found: 131 *retval = p->p_pgrp->pg_id; 132 return 0; 133 } 134 135 /* 136 * Get an arbitary pid's session id. 137 */ 138 #ifndef _SYS_SYSPROTO_H_ 139 struct getsid_args { 140 pid_t pid; 141 }; 142 #endif 143 144 int 145 getsid(p, uap, retval) 146 struct proc *p; 147 struct getsid_args *uap; 148 int *retval; 149 { 150 if (uap->pid == 0) 151 goto found; 152 153 if ((p == pfind(uap->pid)) == 0) 154 return ESRCH; 155 found: 156 *retval = p->p_pgrp->pg_session->s_leader->p_pid; 157 return 0; 158 } 159 160 161 #ifndef _SYS_SYSPROTO_H_ 162 struct getuid_args { 163 int dummy; 164 }; 165 #endif 166 167 /* ARGSUSED */ 168 int 169 getuid(p, uap, retval) 170 struct proc *p; 171 struct getuid_args *uap; 172 int *retval; 173 { 174 175 *retval = p->p_cred->p_ruid; 176 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 177 retval[1] = p->p_ucred->cr_uid; 178 #endif 179 return (0); 180 } 181 182 #ifndef _SYS_SYSPROTO_H_ 183 struct geteuid_args { 184 int dummy; 185 }; 186 #endif 187 188 /* ARGSUSED */ 189 int 190 geteuid(p, uap, retval) 191 struct proc *p; 192 struct geteuid_args *uap; 193 int *retval; 194 { 195 196 *retval = p->p_ucred->cr_uid; 197 return (0); 198 } 199 200 #ifndef _SYS_SYSPROTO_H_ 201 struct getgid_args { 202 int dummy; 203 }; 204 #endif 205 206 /* ARGSUSED */ 207 int 208 getgid(p, uap, retval) 209 struct proc *p; 210 struct getgid_args *uap; 211 int *retval; 212 { 213 214 *retval = p->p_cred->p_rgid; 215 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 216 retval[1] = p->p_ucred->cr_groups[0]; 217 #endif 218 return (0); 219 } 220 221 /* 222 * Get effective group ID. The "egid" is groups[0], and could be obtained 223 * via getgroups. This syscall exists because it is somewhat painful to do 224 * correctly in a library function. 225 */ 226 #ifndef _SYS_SYSPROTO_H_ 227 struct getegid_args { 228 int dummy; 229 }; 230 #endif 231 232 /* ARGSUSED */ 233 int 234 getegid(p, uap, retval) 235 struct proc *p; 236 struct getegid_args *uap; 237 int *retval; 238 { 239 240 *retval = p->p_ucred->cr_groups[0]; 241 return (0); 242 } 243 244 #ifndef _SYS_SYSPROTO_H_ 245 struct getgroups_args { 246 u_int gidsetsize; 247 gid_t *gidset; 248 }; 249 #endif 250 int 251 getgroups(p, uap, retval) 252 struct proc *p; 253 register struct getgroups_args *uap; 254 int *retval; 255 { 256 register struct pcred *pc = p->p_cred; 257 register u_int ngrp; 258 int error; 259 260 if ((ngrp = uap->gidsetsize) == 0) { 261 *retval = pc->pc_ucred->cr_ngroups; 262 return (0); 263 } 264 if (ngrp < pc->pc_ucred->cr_ngroups) 265 return (EINVAL); 266 ngrp = pc->pc_ucred->cr_ngroups; 267 if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 268 (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 269 return (error); 270 *retval = ngrp; 271 return (0); 272 } 273 274 #ifndef _SYS_SYSPROTO_H_ 275 struct setsid_args { 276 int dummy; 277 }; 278 #endif 279 280 /* ARGSUSED */ 281 int 282 setsid(p, uap, retval) 283 register struct proc *p; 284 struct setsid_args *uap; 285 int *retval; 286 { 287 288 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 289 return (EPERM); 290 } else { 291 (void)enterpgrp(p, p->p_pid, 1); 292 *retval = p->p_pid; 293 return (0); 294 } 295 } 296 297 /* 298 * set process group (setpgid/old setpgrp) 299 * 300 * caller does setpgid(targpid, targpgid) 301 * 302 * pid must be caller or child of caller (ESRCH) 303 * if a child 304 * pid must be in same session (EPERM) 305 * pid can't have done an exec (EACCES) 306 * if pgid != pid 307 * there must exist some pid in same session having pgid (EPERM) 308 * pid must not be session leader (EPERM) 309 */ 310 #ifndef _SYS_SYSPROTO_H_ 311 struct setpgid_args { 312 int pid; /* target process id */ 313 int pgid; /* target pgrp id */ 314 }; 315 #endif 316 /* ARGSUSED */ 317 int 318 setpgid(curp, uap, retval) 319 struct proc *curp; 320 register struct setpgid_args *uap; 321 int *retval; 322 { 323 register struct proc *targp; /* target process */ 324 register struct pgrp *pgrp; /* target pgrp */ 325 326 if (uap->pgid < 0) 327 return (EINVAL); 328 if (uap->pid != 0 && uap->pid != curp->p_pid) { 329 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 330 return (ESRCH); 331 if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 332 return (EPERM); 333 if (targp->p_flag & P_EXEC) 334 return (EACCES); 335 } else 336 targp = curp; 337 if (SESS_LEADER(targp)) 338 return (EPERM); 339 if (uap->pgid == 0) 340 uap->pgid = targp->p_pid; 341 else if (uap->pgid != targp->p_pid) 342 if ((pgrp = pgfind(uap->pgid)) == 0 || 343 pgrp->pg_session != curp->p_session) 344 return (EPERM); 345 return (enterpgrp(targp, uap->pgid, 0)); 346 } 347 348 /* 349 * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 350 * compatable. It says that setting the uid/gid to euid/egid is a special 351 * case of "appropriate privilege". Once the rules are expanded out, this 352 * basically means that setuid(nnn) sets all three id's, in all permitted 353 * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 354 * does not set the saved id - this is dangerous for traditional BSD 355 * programs. For this reason, we *really* do not want to set 356 * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 357 */ 358 #define POSIX_APPENDIX_B_4_2_2 359 360 #ifndef _SYS_SYSPROTO_H_ 361 struct setuid_args { 362 uid_t uid; 363 }; 364 #endif 365 /* ARGSUSED */ 366 int 367 setuid(p, uap, retval) 368 struct proc *p; 369 struct setuid_args *uap; 370 int *retval; 371 { 372 register struct pcred *pc = p->p_cred; 373 register uid_t uid; 374 int error; 375 376 /* 377 * See if we have "permission" by POSIX 1003.1 rules. 378 * 379 * Note that setuid(geteuid()) is a special case of 380 * "appropriate privileges" in appendix B.4.2.2. We need 381 * to use this clause to be compatable with traditional BSD 382 * semantics. Basically, it means that "setuid(xx)" sets all 383 * three id's (assuming you have privs). 384 * 385 * Notes on the logic. We do things in three steps. 386 * 1: We determine if the euid is going to change, and do EPERM 387 * right away. We unconditionally change the euid later if this 388 * test is satisfied, simplifying that part of the logic. 389 * 2: We determine if the real and/or saved uid's are going to 390 * change. Determined by compile options. 391 * 3: Change euid last. (after tests in #2 for "appropriate privs") 392 */ 393 uid = uap->uid; 394 if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 395 #ifdef _POSIX_SAVED_IDS 396 uid != pc->p_svuid && /* allow setuid(saved gid) */ 397 #endif 398 #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 399 uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 400 #endif 401 (error = suser(pc->pc_ucred, &p->p_acflag))) 402 return (error); 403 404 #ifdef _POSIX_SAVED_IDS 405 /* 406 * Do we have "appropriate privileges" (are we root or uid == euid) 407 * If so, we are changing the real uid and/or saved uid. 408 */ 409 if ( 410 #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 411 uid == pc->pc_ucred->cr_uid || 412 #endif 413 suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 414 #endif 415 { 416 /* 417 * Transfer proc count to new user. 418 */ 419 if (uid != pc->p_ruid) { 420 (void)chgproccnt(pc->p_ruid, -1); 421 (void)chgproccnt(uid, 1); 422 } 423 /* 424 * Set real uid 425 */ 426 if (uid != pc->p_ruid) { 427 p->p_flag |= P_SUGID; 428 pc->p_ruid = uid; 429 } 430 /* 431 * Set saved uid 432 * 433 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 434 * the security of seteuid() depends on it. B.4.2.2 says it 435 * is important that we should do this. 436 */ 437 if (pc->p_svuid != uid) { 438 p->p_flag |= P_SUGID; 439 pc->p_svuid = uid; 440 } 441 } 442 443 /* 444 * In all permitted cases, we are changing the euid. 445 * Copy credentials so other references do not see our changes. 446 */ 447 if (pc->pc_ucred->cr_uid != uid) { 448 pc->pc_ucred = crcopy(pc->pc_ucred); 449 pc->pc_ucred->cr_uid = uid; 450 p->p_flag |= P_SUGID; 451 } 452 return (0); 453 } 454 455 #ifndef _SYS_SYSPROTO_H_ 456 struct seteuid_args { 457 uid_t euid; 458 }; 459 #endif 460 /* ARGSUSED */ 461 int 462 seteuid(p, uap, retval) 463 struct proc *p; 464 struct seteuid_args *uap; 465 int *retval; 466 { 467 register struct pcred *pc = p->p_cred; 468 register uid_t euid; 469 int error; 470 471 euid = uap->euid; 472 if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 473 euid != pc->p_svuid && /* allow seteuid(saved uid) */ 474 (error = suser(pc->pc_ucred, &p->p_acflag))) 475 return (error); 476 /* 477 * Everything's okay, do it. Copy credentials so other references do 478 * not see our changes. 479 */ 480 if (pc->pc_ucred->cr_uid != euid) { 481 pc->pc_ucred = crcopy(pc->pc_ucred); 482 pc->pc_ucred->cr_uid = euid; 483 p->p_flag |= P_SUGID; 484 } 485 return (0); 486 } 487 488 #ifndef _SYS_SYSPROTO_H_ 489 struct setgid_args { 490 gid_t gid; 491 }; 492 #endif 493 /* ARGSUSED */ 494 int 495 setgid(p, uap, retval) 496 struct proc *p; 497 struct setgid_args *uap; 498 int *retval; 499 { 500 register struct pcred *pc = p->p_cred; 501 register gid_t gid; 502 int error; 503 504 /* 505 * See if we have "permission" by POSIX 1003.1 rules. 506 * 507 * Note that setgid(getegid()) is a special case of 508 * "appropriate privileges" in appendix B.4.2.2. We need 509 * to use this clause to be compatable with traditional BSD 510 * semantics. Basically, it means that "setgid(xx)" sets all 511 * three id's (assuming you have privs). 512 * 513 * For notes on the logic here, see setuid() above. 514 */ 515 gid = uap->gid; 516 if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 517 #ifdef _POSIX_SAVED_IDS 518 gid != pc->p_svgid && /* allow setgid(saved gid) */ 519 #endif 520 #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 521 gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 522 #endif 523 (error = suser(pc->pc_ucred, &p->p_acflag))) 524 return (error); 525 526 #ifdef _POSIX_SAVED_IDS 527 /* 528 * Do we have "appropriate privileges" (are we root or gid == egid) 529 * If so, we are changing the real uid and saved gid. 530 */ 531 if ( 532 #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 533 gid == pc->pc_ucred->cr_groups[0] || 534 #endif 535 suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 536 #endif 537 { 538 /* 539 * Set real gid 540 */ 541 if (pc->p_rgid != gid) { 542 p->p_flag |= P_SUGID; 543 pc->p_rgid = gid; 544 } 545 /* 546 * Set saved gid 547 * 548 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 549 * the security of setegid() depends on it. B.4.2.2 says it 550 * is important that we should do this. 551 */ 552 if (pc->p_svgid != gid) { 553 p->p_flag |= P_SUGID; 554 pc->p_svgid = gid; 555 } 556 } 557 /* 558 * In all cases permitted cases, we are changing the egid. 559 * Copy credentials so other references do not see our changes. 560 */ 561 if (pc->pc_ucred->cr_groups[0] != gid) { 562 pc->pc_ucred = crcopy(pc->pc_ucred); 563 pc->pc_ucred->cr_groups[0] = gid; 564 p->p_flag |= P_SUGID; 565 } 566 return (0); 567 } 568 569 #ifndef _SYS_SYSPROTO_H_ 570 struct setegid_args { 571 gid_t egid; 572 }; 573 #endif 574 /* ARGSUSED */ 575 int 576 setegid(p, uap, retval) 577 struct proc *p; 578 struct setegid_args *uap; 579 int *retval; 580 { 581 register struct pcred *pc = p->p_cred; 582 register gid_t egid; 583 int error; 584 585 egid = uap->egid; 586 if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 587 egid != pc->p_svgid && /* allow setegid(saved gid) */ 588 (error = suser(pc->pc_ucred, &p->p_acflag))) 589 return (error); 590 if (pc->pc_ucred->cr_groups[0] != egid) { 591 pc->pc_ucred = crcopy(pc->pc_ucred); 592 pc->pc_ucred->cr_groups[0] = egid; 593 p->p_flag |= P_SUGID; 594 } 595 return (0); 596 } 597 598 #ifndef _SYS_SYSPROTO_H_ 599 struct setgroups_args { 600 u_int gidsetsize; 601 gid_t *gidset; 602 }; 603 #endif 604 /* ARGSUSED */ 605 int 606 setgroups(p, uap, retval) 607 struct proc *p; 608 struct setgroups_args *uap; 609 int *retval; 610 { 611 register struct pcred *pc = p->p_cred; 612 register u_int ngrp; 613 int error; 614 615 if ((error = suser(pc->pc_ucred, &p->p_acflag))) 616 return (error); 617 ngrp = uap->gidsetsize; 618 if (ngrp > NGROUPS) 619 return (EINVAL); 620 /* 621 * XXX A little bit lazy here. We could test if anything has 622 * changed before crcopy() and setting P_SUGID. 623 */ 624 pc->pc_ucred = crcopy(pc->pc_ucred); 625 if (ngrp < 1) { 626 /* 627 * setgroups(0, NULL) is a legitimate way of clearing the 628 * groups vector on non-BSD systems (which generally do not 629 * have the egid in the groups[0]). We risk security holes 630 * when running non-BSD software if we do not do the same. 631 */ 632 pc->pc_ucred->cr_ngroups = 1; 633 } else { 634 if ((error = copyin((caddr_t)uap->gidset, 635 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 636 return (error); 637 pc->pc_ucred->cr_ngroups = ngrp; 638 } 639 p->p_flag |= P_SUGID; 640 return (0); 641 } 642 643 #ifndef _SYS_SYSPROTO_H_ 644 struct setreuid_args { 645 uid_t ruid; 646 uid_t euid; 647 }; 648 #endif 649 /* ARGSUSED */ 650 int 651 setreuid(p, uap, retval) 652 register struct proc *p; 653 struct setreuid_args *uap; 654 int *retval; 655 { 656 register struct pcred *pc = p->p_cred; 657 register uid_t ruid, euid; 658 int error; 659 660 ruid = uap->ruid; 661 euid = uap->euid; 662 if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid || 663 euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 664 euid != pc->p_ruid && euid != pc->p_svuid) && 665 (error = suser(pc->pc_ucred, &p->p_acflag))) 666 return (error); 667 668 if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 669 pc->pc_ucred = crcopy(pc->pc_ucred); 670 pc->pc_ucred->cr_uid = euid; 671 p->p_flag |= P_SUGID; 672 } 673 if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 674 (void)chgproccnt(pc->p_ruid, -1); 675 (void)chgproccnt(ruid, 1); 676 pc->p_ruid = ruid; 677 p->p_flag |= P_SUGID; 678 } 679 if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 680 pc->p_svuid != pc->pc_ucred->cr_uid) { 681 pc->p_svuid = pc->pc_ucred->cr_uid; 682 p->p_flag |= P_SUGID; 683 } 684 return (0); 685 } 686 687 #ifndef _SYS_SYSPROTO_H_ 688 struct setregid_args { 689 gid_t rgid; 690 gid_t egid; 691 }; 692 #endif 693 /* ARGSUSED */ 694 int 695 setregid(p, uap, retval) 696 register struct proc *p; 697 struct setregid_args *uap; 698 int *retval; 699 { 700 register struct pcred *pc = p->p_cred; 701 register gid_t rgid, egid; 702 int error; 703 704 rgid = uap->rgid; 705 egid = uap->egid; 706 if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 707 egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 708 egid != pc->p_rgid && egid != pc->p_svgid) && 709 (error = suser(pc->pc_ucred, &p->p_acflag))) 710 return (error); 711 712 if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 713 pc->pc_ucred = crcopy(pc->pc_ucred); 714 pc->pc_ucred->cr_groups[0] = egid; 715 p->p_flag |= P_SUGID; 716 } 717 if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 718 pc->p_rgid = rgid; 719 p->p_flag |= P_SUGID; 720 } 721 if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 722 pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 723 pc->p_svgid = pc->pc_ucred->cr_groups[0]; 724 p->p_flag |= P_SUGID; 725 } 726 return (0); 727 } 728 729 #ifndef _SYS_SYSPROTO_H_ 730 struct issetugid_args { 731 int dummy; 732 }; 733 #endif 734 /* ARGSUSED */ 735 int 736 issetugid(p, uap, retval) 737 register struct proc *p; 738 struct issetugid_args *uap; 739 int *retval; 740 { 741 /* 742 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 743 * we use P_SUGID because we consider changing the owners as 744 * "tainting" as well. 745 * This is significant for procs that start as root and "become" 746 * a user without an exec - programs cannot know *everything* 747 * that libc *might* have put in their data segment. 748 */ 749 if (p->p_flag & P_SUGID) 750 return (1); 751 return (0); 752 } 753 754 /* 755 * Check if gid is a member of the group set. 756 */ 757 int 758 groupmember(gid, cred) 759 gid_t gid; 760 register struct ucred *cred; 761 { 762 register gid_t *gp; 763 gid_t *egp; 764 765 egp = &(cred->cr_groups[cred->cr_ngroups]); 766 for (gp = cred->cr_groups; gp < egp; gp++) 767 if (*gp == gid) 768 return (1); 769 return (0); 770 } 771 772 /* 773 * Test whether the specified credentials imply "super-user" 774 * privilege; if so, and we have accounting info, set the flag 775 * indicating use of super-powers. 776 * Returns 0 or error. 777 */ 778 int 779 suser(cred, acflag) 780 struct ucred *cred; 781 u_short *acflag; 782 { 783 if (cred->cr_uid == 0) { 784 if (acflag) 785 *acflag |= ASU; 786 return (0); 787 } 788 return (EPERM); 789 } 790 791 /* 792 * Allocate a zeroed cred structure. 793 */ 794 struct ucred * 795 crget() 796 { 797 register struct ucred *cr; 798 799 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 800 bzero((caddr_t)cr, sizeof(*cr)); 801 cr->cr_ref = 1; 802 return (cr); 803 } 804 805 /* 806 * Free a cred structure. 807 * Throws away space when ref count gets to 0. 808 */ 809 void 810 crfree(cr) 811 struct ucred *cr; 812 { 813 if (--cr->cr_ref == 0) 814 FREE((caddr_t)cr, M_CRED); 815 } 816 817 /* 818 * Copy cred structure to a new one and free the old one. 819 */ 820 struct ucred * 821 crcopy(cr) 822 struct ucred *cr; 823 { 824 struct ucred *newcr; 825 826 if (cr->cr_ref == 1) 827 return (cr); 828 newcr = crget(); 829 *newcr = *cr; 830 crfree(cr); 831 newcr->cr_ref = 1; 832 return (newcr); 833 } 834 835 /* 836 * Dup cred struct to a new held one. 837 */ 838 struct ucred * 839 crdup(cr) 840 struct ucred *cr; 841 { 842 struct ucred *newcr; 843 844 newcr = crget(); 845 *newcr = *cr; 846 newcr->cr_ref = 1; 847 return (newcr); 848 } 849 850 /* 851 * Get login name, if available. 852 */ 853 #ifndef _SYS_SYSPROTO_H_ 854 struct getlogin_args { 855 char *namebuf; 856 u_int namelen; 857 }; 858 #endif 859 /* ARGSUSED */ 860 int 861 getlogin(p, uap, retval) 862 struct proc *p; 863 struct getlogin_args *uap; 864 int *retval; 865 { 866 867 if (uap->namelen > MAXLOGNAME) 868 uap->namelen = MAXLOGNAME; 869 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 870 (caddr_t) uap->namebuf, uap->namelen)); 871 } 872 873 /* 874 * Set login name. 875 */ 876 #ifndef _SYS_SYSPROTO_H_ 877 struct setlogin_args { 878 char *namebuf; 879 }; 880 #endif 881 /* ARGSUSED */ 882 int 883 setlogin(p, uap, retval) 884 struct proc *p; 885 struct setlogin_args *uap; 886 int *retval; 887 { 888 int error; 889 char logintmp[MAXLOGNAME]; 890 891 if ((error = suser(p->p_ucred, &p->p_acflag))) 892 return (error); 893 error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 894 sizeof(logintmp), (u_int *)0); 895 if (error == ENAMETOOLONG) 896 error = EINVAL; 897 else if (!error) 898 (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 899 sizeof(logintmp)); 900 return (error); 901 } 902