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.18 1996/09/01 22:15:54 ache 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/ucred.h> 51 #include <sys/proc.h> 52 #include <sys/timeb.h> 53 #include <sys/times.h> 54 #include <sys/malloc.h> 55 #include <sys/unistd.h> 56 57 #ifndef _SYS_SYSPROTO_H_ 58 struct getpid_args { 59 int dummy; 60 }; 61 #endif 62 63 /* ARGSUSED */ 64 int 65 getpid(p, uap, retval) 66 struct proc *p; 67 struct getpid_args *uap; 68 int *retval; 69 { 70 71 *retval = p->p_pid; 72 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 73 retval[1] = p->p_pptr->p_pid; 74 #endif 75 return (0); 76 } 77 78 #ifndef _SYS_SYSPROTO_H_ 79 struct getppid_args { 80 int dummy; 81 }; 82 #endif 83 /* ARGSUSED */ 84 int 85 getppid(p, uap, retval) 86 struct proc *p; 87 struct getppid_args *uap; 88 int *retval; 89 { 90 91 *retval = p->p_pptr->p_pid; 92 return (0); 93 } 94 95 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 96 #ifndef _SYS_SYSPROTO_H_ 97 struct getpgrp_args { 98 int dummy; 99 }; 100 #endif 101 102 int 103 getpgrp(p, uap, retval) 104 struct proc *p; 105 struct getpgrp_args *uap; 106 int *retval; 107 { 108 109 *retval = p->p_pgrp->pg_id; 110 return (0); 111 } 112 113 #ifndef _SYS_SYSPROTO_H_ 114 struct getuid_args { 115 int dummy; 116 }; 117 #endif 118 119 /* ARGSUSED */ 120 int 121 getuid(p, uap, retval) 122 struct proc *p; 123 struct getuid_args *uap; 124 int *retval; 125 { 126 127 *retval = p->p_cred->p_ruid; 128 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 129 retval[1] = p->p_ucred->cr_uid; 130 #endif 131 return (0); 132 } 133 134 #ifndef _SYS_SYSPROTO_H_ 135 struct geteuid_args { 136 int dummy; 137 }; 138 #endif 139 140 /* ARGSUSED */ 141 int 142 geteuid(p, uap, retval) 143 struct proc *p; 144 struct geteuid_args *uap; 145 int *retval; 146 { 147 148 *retval = p->p_ucred->cr_uid; 149 return (0); 150 } 151 152 #ifndef _SYS_SYSPROTO_H_ 153 struct getgid_args { 154 int dummy; 155 }; 156 #endif 157 158 /* ARGSUSED */ 159 int 160 getgid(p, uap, retval) 161 struct proc *p; 162 struct getgid_args *uap; 163 int *retval; 164 { 165 166 *retval = p->p_cred->p_rgid; 167 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 168 retval[1] = p->p_ucred->cr_groups[0]; 169 #endif 170 return (0); 171 } 172 173 /* 174 * Get effective group ID. The "egid" is groups[0], and could be obtained 175 * via getgroups. This syscall exists because it is somewhat painful to do 176 * correctly in a library function. 177 */ 178 #ifndef _SYS_SYSPROTO_H_ 179 struct getegid_args { 180 int dummy; 181 }; 182 #endif 183 184 /* ARGSUSED */ 185 int 186 getegid(p, uap, retval) 187 struct proc *p; 188 struct getegid_args *uap; 189 int *retval; 190 { 191 192 *retval = p->p_ucred->cr_groups[0]; 193 return (0); 194 } 195 196 #ifndef _SYS_SYSPROTO_H_ 197 struct getgroups_args { 198 u_int gidsetsize; 199 gid_t *gidset; 200 }; 201 #endif 202 int 203 getgroups(p, uap, retval) 204 struct proc *p; 205 register struct getgroups_args *uap; 206 int *retval; 207 { 208 register struct pcred *pc = p->p_cred; 209 register u_int ngrp; 210 int error; 211 212 if ((ngrp = uap->gidsetsize) == 0) { 213 *retval = pc->pc_ucred->cr_ngroups; 214 return (0); 215 } 216 if (ngrp < pc->pc_ucred->cr_ngroups) 217 return (EINVAL); 218 ngrp = pc->pc_ucred->cr_ngroups; 219 if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 220 (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 221 return (error); 222 *retval = ngrp; 223 return (0); 224 } 225 226 #ifndef _SYS_SYSPROTO_H_ 227 struct setsid_args { 228 int dummy; 229 }; 230 #endif 231 232 /* ARGSUSED */ 233 int 234 setsid(p, uap, retval) 235 register struct proc *p; 236 struct setsid_args *uap; 237 int *retval; 238 { 239 240 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 241 return (EPERM); 242 } else { 243 (void)enterpgrp(p, p->p_pid, 1); 244 *retval = p->p_pid; 245 return (0); 246 } 247 } 248 249 /* 250 * set process group (setpgid/old setpgrp) 251 * 252 * caller does setpgid(targpid, targpgid) 253 * 254 * pid must be caller or child of caller (ESRCH) 255 * if a child 256 * pid must be in same session (EPERM) 257 * pid can't have done an exec (EACCES) 258 * if pgid != pid 259 * there must exist some pid in same session having pgid (EPERM) 260 * pid must not be session leader (EPERM) 261 */ 262 #ifndef _SYS_SYSPROTO_H_ 263 struct setpgid_args { 264 int pid; /* target process id */ 265 int pgid; /* target pgrp id */ 266 }; 267 #endif 268 /* ARGSUSED */ 269 int 270 setpgid(curp, uap, retval) 271 struct proc *curp; 272 register struct setpgid_args *uap; 273 int *retval; 274 { 275 register struct proc *targp; /* target process */ 276 register struct pgrp *pgrp; /* target pgrp */ 277 278 if (uap->pid != 0 && uap->pid != curp->p_pid) { 279 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 280 return (ESRCH); 281 if (targp->p_pgrp == NULL || 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 (uap->pgid == 0) 290 uap->pgid = targp->p_pid; 291 else if (uap->pgid != targp->p_pid) 292 if ((pgrp = pgfind(uap->pgid)) == 0 || 293 pgrp->pg_session != curp->p_session) 294 return (EPERM); 295 return (enterpgrp(targp, uap->pgid, 0)); 296 } 297 298 #ifndef _SYS_SYSPROTO_H_ 299 struct setuid_args { 300 uid_t uid; 301 }; 302 #endif 303 /* ARGSUSED */ 304 int 305 setuid(p, uap, retval) 306 struct proc *p; 307 struct setuid_args *uap; 308 int *retval; 309 { 310 register struct pcred *pc = p->p_cred; 311 register uid_t uid; 312 int error; 313 314 uid = uap->uid; 315 if (uid != pc->p_ruid && 316 #ifdef _POSIX_SAVED_IDS 317 uid != pc->p_svuid && 318 #endif 319 (error = suser(pc->pc_ucred, &p->p_acflag))) 320 return (error); 321 /* 322 * Everything's okay, do it. 323 * Transfer proc count to new user. 324 * Copy credentials so other references do not see our changes. 325 */ 326 if ( 327 #ifdef _POSIX_SAVED_IDS 328 pc->pc_ucred->cr_uid == 0 && 329 #endif 330 uid != pc->p_ruid) { 331 (void)chgproccnt(pc->p_ruid, -1); 332 (void)chgproccnt(uid, 1); 333 } 334 pc->pc_ucred = crcopy(pc->pc_ucred); 335 #ifdef _POSIX_SAVED_IDS 336 if (pc->pc_ucred->cr_uid == 0) { 337 #endif 338 pc->p_ruid = uid; 339 pc->p_svuid = uid; 340 #ifdef _POSIX_SAVED_IDS 341 } 342 #endif 343 pc->pc_ucred->cr_uid = uid; 344 p->p_flag |= P_SUGID; 345 return (0); 346 } 347 348 #ifndef _SYS_SYSPROTO_H_ 349 struct seteuid_args { 350 uid_t euid; 351 }; 352 #endif 353 /* ARGSUSED */ 354 int 355 seteuid(p, uap, retval) 356 struct proc *p; 357 struct seteuid_args *uap; 358 int *retval; 359 { 360 register struct pcred *pc = p->p_cred; 361 register uid_t euid; 362 int error; 363 364 euid = uap->euid; 365 if (euid != pc->p_ruid && euid != pc->p_svuid && 366 (error = suser(pc->pc_ucred, &p->p_acflag))) 367 return (error); 368 /* 369 * Everything's okay, do it. Copy credentials so other references do 370 * not see our changes. 371 */ 372 pc->pc_ucred = crcopy(pc->pc_ucred); 373 pc->pc_ucred->cr_uid = euid; 374 p->p_flag |= P_SUGID; 375 return (0); 376 } 377 378 #ifndef _SYS_SYSPROTO_H_ 379 struct setgid_args { 380 gid_t gid; 381 }; 382 #endif 383 /* ARGSUSED */ 384 int 385 setgid(p, uap, retval) 386 struct proc *p; 387 struct setgid_args *uap; 388 int *retval; 389 { 390 register struct pcred *pc = p->p_cred; 391 register gid_t gid; 392 int error; 393 394 gid = uap->gid; 395 if (gid != pc->p_rgid && 396 #ifdef _POSIX_SAVED_IDS 397 gid != pc->p_svgid && 398 #endif 399 (error = suser(pc->pc_ucred, &p->p_acflag))) 400 return (error); 401 pc->pc_ucred = crcopy(pc->pc_ucred); 402 pc->pc_ucred->cr_groups[0] = gid; 403 #ifdef _POSIX_SAVED_IDS 404 if (pc->pc_ucred->cr_uid == 0) { 405 #endif 406 pc->p_rgid = gid; 407 pc->p_svgid = gid; 408 #ifdef _POSIX_SAVED_IDS 409 } 410 #endif 411 p->p_flag |= P_SUGID; 412 return (0); 413 } 414 415 #ifndef _SYS_SYSPROTO_H_ 416 struct setegid_args { 417 gid_t egid; 418 }; 419 #endif 420 /* ARGSUSED */ 421 int 422 setegid(p, uap, retval) 423 struct proc *p; 424 struct setegid_args *uap; 425 int *retval; 426 { 427 register struct pcred *pc = p->p_cred; 428 register gid_t egid; 429 int error; 430 431 egid = uap->egid; 432 if (egid != pc->p_rgid && egid != pc->p_svgid && 433 (error = suser(pc->pc_ucred, &p->p_acflag))) 434 return (error); 435 pc->pc_ucred = crcopy(pc->pc_ucred); 436 pc->pc_ucred->cr_groups[0] = egid; 437 p->p_flag |= P_SUGID; 438 return (0); 439 } 440 441 #ifndef _SYS_SYSPROTO_H_ 442 struct setgroups_args { 443 u_int gidsetsize; 444 gid_t *gidset; 445 }; 446 #endif 447 /* ARGSUSED */ 448 int 449 setgroups(p, uap, retval) 450 struct proc *p; 451 struct setgroups_args *uap; 452 int *retval; 453 { 454 register struct pcred *pc = p->p_cred; 455 register u_int ngrp; 456 int error; 457 458 if ((error = suser(pc->pc_ucred, &p->p_acflag))) 459 return (error); 460 ngrp = uap->gidsetsize; 461 if (ngrp < 1 || ngrp > NGROUPS) 462 return (EINVAL); 463 pc->pc_ucred = crcopy(pc->pc_ucred); 464 if ((error = copyin((caddr_t)uap->gidset, 465 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 466 return (error); 467 pc->pc_ucred->cr_ngroups = ngrp; 468 p->p_flag |= P_SUGID; 469 return (0); 470 } 471 472 #ifndef _SYS_SYSPROTO_H_ 473 struct setreuid_args { 474 uid_t ruid; 475 uid_t euid; 476 }; 477 #endif 478 /* ARGSUSED */ 479 int 480 setreuid(p, uap, retval) 481 register struct proc *p; 482 struct setreuid_args *uap; 483 int *retval; 484 { 485 register struct pcred *pc = p->p_cred; 486 register uid_t ruid, euid; 487 int error; 488 489 ruid = uap->ruid; 490 euid = uap->euid; 491 if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid || 492 euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) && 493 (error = suser(pc->pc_ucred, &p->p_acflag))) 494 return (error); 495 496 pc->pc_ucred = crcopy(pc->pc_ucred); 497 if (euid != (uid_t)-1) 498 pc->pc_ucred->cr_uid = euid; 499 if (ruid != (uid_t)-1 && ruid != pc->p_ruid) { 500 (void)chgproccnt(pc->p_ruid, -1); 501 (void)chgproccnt(ruid, 1); 502 pc->p_ruid = ruid; 503 } 504 if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) 505 pc->p_svuid = pc->pc_ucred->cr_uid; 506 p->p_flag |= P_SUGID; 507 return (0); 508 } 509 510 #ifndef _SYS_SYSPROTO_H_ 511 struct setregid_args { 512 gid_t rgid; 513 gid_t egid; 514 }; 515 #endif 516 /* ARGSUSED */ 517 int 518 setregid(p, uap, retval) 519 register struct proc *p; 520 struct setregid_args *uap; 521 int *retval; 522 { 523 register struct pcred *pc = p->p_cred; 524 register gid_t rgid, egid; 525 int error; 526 527 rgid = uap->rgid; 528 egid = uap->egid; 529 if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 530 egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) && 531 (error = suser(pc->pc_ucred, &p->p_acflag))) 532 return (error); 533 534 pc->pc_ucred = crcopy(pc->pc_ucred); 535 if (egid != (gid_t)-1) 536 pc->pc_ucred->cr_groups[0] = egid; 537 if (rgid != (gid_t)-1) 538 pc->p_rgid = rgid; 539 if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) 540 pc->p_svgid = pc->pc_ucred->cr_groups[0]; 541 p->p_flag |= P_SUGID; 542 return (0); 543 } 544 545 /* 546 * Check if gid is a member of the group set. 547 */ 548 int 549 groupmember(gid, cred) 550 gid_t gid; 551 register struct ucred *cred; 552 { 553 register gid_t *gp; 554 gid_t *egp; 555 556 egp = &(cred->cr_groups[cred->cr_ngroups]); 557 for (gp = cred->cr_groups; gp < egp; gp++) 558 if (*gp == gid) 559 return (1); 560 return (0); 561 } 562 563 /* 564 * Test whether the specified credentials imply "super-user" 565 * privilege; if so, and we have accounting info, set the flag 566 * indicating use of super-powers. 567 * Returns 0 or error. 568 */ 569 int 570 suser(cred, acflag) 571 struct ucred *cred; 572 u_short *acflag; 573 { 574 if (cred->cr_uid == 0) { 575 if (acflag) 576 *acflag |= ASU; 577 return (0); 578 } 579 return (EPERM); 580 } 581 582 /* 583 * Allocate a zeroed cred structure. 584 */ 585 struct ucred * 586 crget() 587 { 588 register struct ucred *cr; 589 590 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 591 bzero((caddr_t)cr, sizeof(*cr)); 592 cr->cr_ref = 1; 593 return (cr); 594 } 595 596 /* 597 * Free a cred structure. 598 * Throws away space when ref count gets to 0. 599 */ 600 void 601 crfree(cr) 602 struct ucred *cr; 603 { 604 int s; 605 606 s = splimp(); /* ??? */ 607 if (--cr->cr_ref == 0) 608 FREE((caddr_t)cr, M_CRED); 609 (void) splx(s); 610 } 611 612 /* 613 * Copy cred structure to a new one and free the old one. 614 */ 615 struct ucred * 616 crcopy(cr) 617 struct ucred *cr; 618 { 619 struct ucred *newcr; 620 621 if (cr->cr_ref == 1) 622 return (cr); 623 newcr = crget(); 624 *newcr = *cr; 625 crfree(cr); 626 newcr->cr_ref = 1; 627 return (newcr); 628 } 629 630 /* 631 * Dup cred struct to a new held one. 632 */ 633 struct ucred * 634 crdup(cr) 635 struct ucred *cr; 636 { 637 struct ucred *newcr; 638 639 newcr = crget(); 640 *newcr = *cr; 641 newcr->cr_ref = 1; 642 return (newcr); 643 } 644 645 /* 646 * Get login name, if available. 647 */ 648 #ifndef _SYS_SYSPROTO_H_ 649 struct getlogin_args { 650 char *namebuf; 651 u_int namelen; 652 }; 653 #endif 654 /* ARGSUSED */ 655 int 656 getlogin(p, uap, retval) 657 struct proc *p; 658 struct getlogin_args *uap; 659 int *retval; 660 { 661 662 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 663 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 664 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 665 (caddr_t) uap->namebuf, uap->namelen)); 666 } 667 668 /* 669 * Set login name. 670 */ 671 #ifndef _SYS_SYSPROTO_H_ 672 struct setlogin_args { 673 char *namebuf; 674 }; 675 #endif 676 /* ARGSUSED */ 677 int 678 setlogin(p, uap, retval) 679 struct proc *p; 680 struct setlogin_args *uap; 681 int *retval; 682 { 683 int error; 684 685 if ((error = suser(p->p_ucred, &p->p_acflag))) 686 return (error); 687 error = copyinstr((caddr_t) uap->namebuf, 688 (caddr_t) p->p_pgrp->pg_session->s_login, 689 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 690 if (error == ENAMETOOLONG) 691 error = EINVAL; 692 return (error); 693 } 694