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 * $FreeBSD$ 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->pgid < 0) 279 return (EINVAL); 280 if (uap->pid != 0 && uap->pid != curp->p_pid) { 281 if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 282 return (ESRCH); 283 if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 284 return (EPERM); 285 if (targp->p_flag & P_EXEC) 286 return (EACCES); 287 } else 288 targp = curp; 289 if (SESS_LEADER(targp)) 290 return (EPERM); 291 if (uap->pgid == 0) 292 uap->pgid = targp->p_pid; 293 else if (uap->pgid != targp->p_pid) 294 if ((pgrp = pgfind(uap->pgid)) == 0 || 295 pgrp->pg_session != curp->p_session) 296 return (EPERM); 297 return (enterpgrp(targp, uap->pgid, 0)); 298 } 299 300 #ifndef _SYS_SYSPROTO_H_ 301 struct setuid_args { 302 uid_t uid; 303 }; 304 #endif 305 /* ARGSUSED */ 306 int 307 setuid(p, uap, retval) 308 struct proc *p; 309 struct setuid_args *uap; 310 int *retval; 311 { 312 register struct pcred *pc = p->p_cred; 313 register uid_t uid; 314 int error; 315 316 uid = uap->uid; 317 if (uid != pc->p_ruid && 318 #ifdef _POSIX_SAVED_IDS 319 uid != pc->p_svuid && 320 #endif 321 (error = suser(pc->pc_ucred, &p->p_acflag))) 322 return (error); 323 /* 324 * Everything's okay, do it. 325 * Transfer proc count to new user. 326 * Copy credentials so other references do not see our changes. 327 */ 328 if ( 329 #ifdef _POSIX_SAVED_IDS 330 pc->pc_ucred->cr_uid == 0 && 331 #endif 332 uid != pc->p_ruid) { 333 (void)chgproccnt(pc->p_ruid, -1); 334 (void)chgproccnt(uid, 1); 335 } 336 pc->pc_ucred = crcopy(pc->pc_ucred); 337 #ifdef _POSIX_SAVED_IDS 338 if (pc->pc_ucred->cr_uid == 0) { 339 #endif 340 pc->p_ruid = uid; 341 pc->p_svuid = uid; 342 #ifdef _POSIX_SAVED_IDS 343 } 344 #endif 345 pc->pc_ucred->cr_uid = uid; 346 p->p_flag |= P_SUGID; 347 return (0); 348 } 349 350 #ifndef _SYS_SYSPROTO_H_ 351 struct seteuid_args { 352 uid_t euid; 353 }; 354 #endif 355 /* ARGSUSED */ 356 int 357 seteuid(p, uap, retval) 358 struct proc *p; 359 struct seteuid_args *uap; 360 int *retval; 361 { 362 register struct pcred *pc = p->p_cred; 363 register uid_t euid; 364 int error; 365 366 euid = uap->euid; 367 if (euid != pc->p_ruid && euid != pc->p_svuid && 368 (error = suser(pc->pc_ucred, &p->p_acflag))) 369 return (error); 370 /* 371 * Everything's okay, do it. Copy credentials so other references do 372 * not see our changes. 373 */ 374 pc->pc_ucred = crcopy(pc->pc_ucred); 375 pc->pc_ucred->cr_uid = euid; 376 p->p_flag |= P_SUGID; 377 return (0); 378 } 379 380 #ifndef _SYS_SYSPROTO_H_ 381 struct setgid_args { 382 gid_t gid; 383 }; 384 #endif 385 /* ARGSUSED */ 386 int 387 setgid(p, uap, retval) 388 struct proc *p; 389 struct setgid_args *uap; 390 int *retval; 391 { 392 register struct pcred *pc = p->p_cred; 393 register gid_t gid; 394 int error; 395 396 gid = uap->gid; 397 if (gid != pc->p_rgid && 398 #ifdef _POSIX_SAVED_IDS 399 gid != pc->p_svgid && 400 #endif 401 (error = suser(pc->pc_ucred, &p->p_acflag))) 402 return (error); 403 pc->pc_ucred = crcopy(pc->pc_ucred); 404 pc->pc_ucred->cr_groups[0] = gid; 405 #ifdef _POSIX_SAVED_IDS 406 if (pc->pc_ucred->cr_uid == 0) { 407 #endif 408 pc->p_rgid = gid; 409 pc->p_svgid = gid; 410 #ifdef _POSIX_SAVED_IDS 411 } 412 #endif 413 p->p_flag |= P_SUGID; 414 return (0); 415 } 416 417 #ifndef _SYS_SYSPROTO_H_ 418 struct setegid_args { 419 gid_t egid; 420 }; 421 #endif 422 /* ARGSUSED */ 423 int 424 setegid(p, uap, retval) 425 struct proc *p; 426 struct setegid_args *uap; 427 int *retval; 428 { 429 register struct pcred *pc = p->p_cred; 430 register gid_t egid; 431 int error; 432 433 egid = uap->egid; 434 if (egid != pc->p_rgid && egid != pc->p_svgid && 435 (error = suser(pc->pc_ucred, &p->p_acflag))) 436 return (error); 437 pc->pc_ucred = crcopy(pc->pc_ucred); 438 pc->pc_ucred->cr_groups[0] = egid; 439 p->p_flag |= P_SUGID; 440 return (0); 441 } 442 443 #ifndef _SYS_SYSPROTO_H_ 444 struct setgroups_args { 445 u_int gidsetsize; 446 gid_t *gidset; 447 }; 448 #endif 449 /* ARGSUSED */ 450 int 451 setgroups(p, uap, retval) 452 struct proc *p; 453 struct setgroups_args *uap; 454 int *retval; 455 { 456 register struct pcred *pc = p->p_cred; 457 register u_int ngrp; 458 int error; 459 460 if ((error = suser(pc->pc_ucred, &p->p_acflag))) 461 return (error); 462 ngrp = uap->gidsetsize; 463 if (ngrp < 1 || ngrp > NGROUPS) 464 return (EINVAL); 465 pc->pc_ucred = crcopy(pc->pc_ucred); 466 if ((error = copyin((caddr_t)uap->gidset, 467 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 468 return (error); 469 pc->pc_ucred->cr_ngroups = ngrp; 470 p->p_flag |= P_SUGID; 471 return (0); 472 } 473 474 #ifndef _SYS_SYSPROTO_H_ 475 struct setreuid_args { 476 uid_t ruid; 477 uid_t euid; 478 }; 479 #endif 480 /* ARGSUSED */ 481 int 482 setreuid(p, uap, retval) 483 register struct proc *p; 484 struct setreuid_args *uap; 485 int *retval; 486 { 487 register struct pcred *pc = p->p_cred; 488 register uid_t ruid, euid; 489 int error; 490 491 ruid = uap->ruid; 492 euid = uap->euid; 493 if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid || 494 euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) && 495 (error = suser(pc->pc_ucred, &p->p_acflag))) 496 return (error); 497 498 pc->pc_ucred = crcopy(pc->pc_ucred); 499 if (euid != (uid_t)-1) 500 pc->pc_ucred->cr_uid = euid; 501 if (ruid != (uid_t)-1 && ruid != pc->p_ruid) { 502 (void)chgproccnt(pc->p_ruid, -1); 503 (void)chgproccnt(ruid, 1); 504 pc->p_ruid = ruid; 505 } 506 if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) 507 pc->p_svuid = pc->pc_ucred->cr_uid; 508 p->p_flag |= P_SUGID; 509 return (0); 510 } 511 512 #ifndef _SYS_SYSPROTO_H_ 513 struct setregid_args { 514 gid_t rgid; 515 gid_t egid; 516 }; 517 #endif 518 /* ARGSUSED */ 519 int 520 setregid(p, uap, retval) 521 register struct proc *p; 522 struct setregid_args *uap; 523 int *retval; 524 { 525 register struct pcred *pc = p->p_cred; 526 register gid_t rgid, egid; 527 int error; 528 529 rgid = uap->rgid; 530 egid = uap->egid; 531 if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 532 egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) && 533 (error = suser(pc->pc_ucred, &p->p_acflag))) 534 return (error); 535 536 pc->pc_ucred = crcopy(pc->pc_ucred); 537 if (egid != (gid_t)-1) 538 pc->pc_ucred->cr_groups[0] = egid; 539 if (rgid != (gid_t)-1) 540 pc->p_rgid = rgid; 541 if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) 542 pc->p_svgid = pc->pc_ucred->cr_groups[0]; 543 p->p_flag |= P_SUGID; 544 return (0); 545 } 546 547 /* 548 * Check if gid is a member of the group set. 549 */ 550 int 551 groupmember(gid, cred) 552 gid_t gid; 553 register struct ucred *cred; 554 { 555 register gid_t *gp; 556 gid_t *egp; 557 558 egp = &(cred->cr_groups[cred->cr_ngroups]); 559 for (gp = cred->cr_groups; gp < egp; gp++) 560 if (*gp == gid) 561 return (1); 562 return (0); 563 } 564 565 /* 566 * Test whether the specified credentials imply "super-user" 567 * privilege; if so, and we have accounting info, set the flag 568 * indicating use of super-powers. 569 * Returns 0 or error. 570 */ 571 int 572 suser(cred, acflag) 573 struct ucred *cred; 574 u_short *acflag; 575 { 576 if (cred->cr_uid == 0) { 577 if (acflag) 578 *acflag |= ASU; 579 return (0); 580 } 581 return (EPERM); 582 } 583 584 /* 585 * Allocate a zeroed cred structure. 586 */ 587 struct ucred * 588 crget() 589 { 590 register struct ucred *cr; 591 592 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 593 bzero((caddr_t)cr, sizeof(*cr)); 594 cr->cr_ref = 1; 595 return (cr); 596 } 597 598 /* 599 * Free a cred structure. 600 * Throws away space when ref count gets to 0. 601 */ 602 void 603 crfree(cr) 604 struct ucred *cr; 605 { 606 int s; 607 608 s = splimp(); /* ??? */ 609 if (--cr->cr_ref == 0) 610 FREE((caddr_t)cr, M_CRED); 611 (void) splx(s); 612 } 613 614 /* 615 * Copy cred structure to a new one and free the old one. 616 */ 617 struct ucred * 618 crcopy(cr) 619 struct ucred *cr; 620 { 621 struct ucred *newcr; 622 623 if (cr->cr_ref == 1) 624 return (cr); 625 newcr = crget(); 626 *newcr = *cr; 627 crfree(cr); 628 newcr->cr_ref = 1; 629 return (newcr); 630 } 631 632 /* 633 * Dup cred struct to a new held one. 634 */ 635 struct ucred * 636 crdup(cr) 637 struct ucred *cr; 638 { 639 struct ucred *newcr; 640 641 newcr = crget(); 642 *newcr = *cr; 643 newcr->cr_ref = 1; 644 return (newcr); 645 } 646 647 /* 648 * Get login name, if available. 649 */ 650 #ifndef _SYS_SYSPROTO_H_ 651 struct getlogin_args { 652 char *namebuf; 653 u_int namelen; 654 }; 655 #endif 656 /* ARGSUSED */ 657 int 658 getlogin(p, uap, retval) 659 struct proc *p; 660 struct getlogin_args *uap; 661 int *retval; 662 { 663 664 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 665 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 666 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 667 (caddr_t) uap->namebuf, uap->namelen)); 668 } 669 670 /* 671 * Set login name. 672 */ 673 #ifndef _SYS_SYSPROTO_H_ 674 struct setlogin_args { 675 char *namebuf; 676 }; 677 #endif 678 /* ARGSUSED */ 679 int 680 setlogin(p, uap, retval) 681 struct proc *p; 682 struct setlogin_args *uap; 683 int *retval; 684 { 685 int error; 686 char logintmp[sizeof(p->p_pgrp->pg_session->s_login)]; 687 688 if ((error = suser(p->p_ucred, &p->p_acflag))) 689 return (error); 690 error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 691 sizeof(logintmp), (u_int *)0); 692 if (error == ENAMETOOLONG) 693 error = EINVAL; 694 else if (!error) 695 (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 696 sizeof(p->p_pgrp->pg_session->s_login)); 697 return (error); 698 } 699