1 /* $NetBSD: kern_prot.c,v 1.37 1996/09/19 04:54:16 jtc Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 41 */ 42 43 /* 44 * System calls related to processes and protection 45 */ 46 47 #include <sys/param.h> 48 #include <sys/acct.h> 49 #include <sys/systm.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 56 #include <sys/mount.h> 57 #include <sys/syscallargs.h> 58 59 /* ARGSUSED */ 60 int 61 sys_getpid(p, v, retval) 62 struct proc *p; 63 void *v; 64 register_t *retval; 65 { 66 67 *retval = p->p_pid; 68 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 69 defined(COMPAT_FREEBSD) 70 retval[1] = p->p_pptr->p_pid; 71 #endif 72 return (0); 73 } 74 75 /* ARGSUSED */ 76 int 77 sys_getppid(p, v, retval) 78 struct proc *p; 79 void *v; 80 register_t *retval; 81 { 82 83 *retval = p->p_pptr->p_pid; 84 return (0); 85 } 86 87 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 88 int 89 sys_getpgrp(p, v, retval) 90 struct proc *p; 91 void *v; 92 register_t *retval; 93 { 94 95 *retval = p->p_pgrp->pg_id; 96 return (0); 97 } 98 99 int 100 sys_getpgid(p, v, retval) 101 struct proc *p; 102 void *v; 103 register_t *retval; 104 { 105 register struct sys_getpgid_args /* { 106 syscallarg(pid_t) pid; 107 } */ *uap = v; 108 109 if (SCARG(uap, pid) == 0) 110 goto found; 111 if ((p = pfind(SCARG(uap, pid))) == 0) 112 return (ESRCH); 113 found: 114 *retval = p->p_pgid; 115 return 0; 116 } 117 118 /* ARGSUSED */ 119 int 120 sys_getuid(p, v, retval) 121 struct proc *p; 122 void *v; 123 register_t *retval; 124 { 125 126 *retval = p->p_cred->p_ruid; 127 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 128 defined(COMPAT_FREEBSD) 129 retval[1] = p->p_ucred->cr_uid; 130 #endif 131 return (0); 132 } 133 134 /* ARGSUSED */ 135 int 136 sys_geteuid(p, v, retval) 137 struct proc *p; 138 void *v; 139 register_t *retval; 140 { 141 142 *retval = p->p_ucred->cr_uid; 143 return (0); 144 } 145 146 /* ARGSUSED */ 147 int 148 sys_getgid(p, v, retval) 149 struct proc *p; 150 void *v; 151 register_t *retval; 152 { 153 154 *retval = p->p_cred->p_rgid; 155 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) 156 retval[1] = p->p_ucred->cr_gid; 157 #endif 158 return (0); 159 } 160 161 /* 162 * Get effective group ID. The "egid" is groups[0], and could be obtained 163 * via getgroups. This syscall exists because it is somewhat painful to do 164 * correctly in a library function. 165 */ 166 /* ARGSUSED */ 167 int 168 sys_getegid(p, v, retval) 169 struct proc *p; 170 void *v; 171 register_t *retval; 172 { 173 174 *retval = p->p_ucred->cr_gid; 175 return (0); 176 } 177 178 int 179 sys_getgroups(p, v, retval) 180 struct proc *p; 181 void *v; 182 register_t *retval; 183 { 184 register struct sys_getgroups_args /* { 185 syscallarg(u_int) gidsetsize; 186 syscallarg(gid_t *) gidset; 187 } */ *uap = v; 188 register struct pcred *pc = p->p_cred; 189 register u_int ngrp; 190 int error; 191 192 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 193 *retval = pc->pc_ucred->cr_ngroups; 194 return (0); 195 } 196 if (ngrp < pc->pc_ucred->cr_ngroups) 197 return (EINVAL); 198 ngrp = pc->pc_ucred->cr_ngroups; 199 error = copyout((caddr_t)pc->pc_ucred->cr_groups, 200 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)); 201 if (error) 202 return (error); 203 *retval = ngrp; 204 return (0); 205 } 206 207 /* ARGSUSED */ 208 int 209 sys_setsid(p, v, retval) 210 register struct proc *p; 211 void *v; 212 register_t *retval; 213 { 214 215 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 216 return (EPERM); 217 } else { 218 (void)enterpgrp(p, p->p_pid, 1); 219 *retval = p->p_pid; 220 return (0); 221 } 222 } 223 224 /* 225 * set process group (setpgid/old setpgrp) 226 * 227 * caller does setpgid(targpid, targpgid) 228 * 229 * pid must be caller or child of caller (ESRCH) 230 * if a child 231 * pid must be in same session (EPERM) 232 * pid can't have done an exec (EACCES) 233 * if pgid != pid 234 * there must exist some pid in same session having pgid (EPERM) 235 * pid must not be session leader (EPERM) 236 */ 237 /* ARGSUSED */ 238 int 239 sys_setpgid(curp, v, retval) 240 struct proc *curp; 241 void *v; 242 register_t *retval; 243 { 244 register struct sys_setpgid_args /* { 245 syscallarg(int) pid; 246 syscallarg(int) pgid; 247 } */ *uap = v; 248 register struct proc *targp; /* target process */ 249 register struct pgrp *pgrp; /* target pgrp */ 250 251 #ifdef COMPAT_09 252 SCARG(uap, pid) = (short) SCARG(uap, pid); /* XXX */ 253 SCARG(uap, pgid) = (short) SCARG(uap, pgid); /* XXX */ 254 #endif 255 256 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) { 257 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp)) 258 return (ESRCH); 259 if (targp->p_session != curp->p_session) 260 return (EPERM); 261 if (targp->p_flag & P_EXEC) 262 return (EACCES); 263 } else 264 targp = curp; 265 if (SESS_LEADER(targp)) 266 return (EPERM); 267 if (SCARG(uap, pgid) == 0) 268 SCARG(uap, pgid) = targp->p_pid; 269 else if (SCARG(uap, pgid) != targp->p_pid) 270 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 || 271 pgrp->pg_session != curp->p_session) 272 return (EPERM); 273 return (enterpgrp(targp, SCARG(uap, pgid), 0)); 274 } 275 276 /* ARGSUSED */ 277 int 278 sys_setuid(p, v, retval) 279 struct proc *p; 280 void *v; 281 register_t *retval; 282 { 283 struct sys_setuid_args /* { 284 syscallarg(uid_t) uid; 285 } */ *uap = v; 286 register struct pcred *pc = p->p_cred; 287 register uid_t uid; 288 int error; 289 290 #ifdef COMPAT_09 /* XXX */ 291 uid = (u_short)SCARG(uap, uid); 292 #else 293 uid = SCARG(uap, uid); 294 #endif 295 if (uid != pc->p_ruid && 296 (error = suser(pc->pc_ucred, &p->p_acflag))) 297 return (error); 298 /* 299 * Everything's okay, do it. 300 * Transfer proc count to new user. 301 * Copy credentials so other references do not see our changes. 302 */ 303 (void)chgproccnt(pc->p_ruid, -1); 304 (void)chgproccnt(uid, 1); 305 pc->pc_ucred = crcopy(pc->pc_ucred); 306 pc->pc_ucred->cr_uid = uid; 307 pc->p_ruid = uid; 308 pc->p_svuid = uid; 309 p->p_flag |= P_SUGID; 310 return (0); 311 } 312 313 /* ARGSUSED */ 314 int 315 sys_seteuid(p, v, retval) 316 struct proc *p; 317 void *v; 318 register_t *retval; 319 { 320 struct sys_seteuid_args /* { 321 syscallarg(uid_t) euid; 322 } */ *uap = v; 323 register struct pcred *pc = p->p_cred; 324 register uid_t euid; 325 int error; 326 327 #ifdef COMPAT_09 /* XXX */ 328 euid = (u_short)SCARG(uap, euid); 329 #else 330 euid = SCARG(uap, euid); 331 #endif 332 if (euid != pc->p_ruid && euid != pc->p_svuid && 333 (error = suser(pc->pc_ucred, &p->p_acflag))) 334 return (error); 335 /* 336 * Everything's okay, do it. Copy credentials so other references do 337 * not see our changes. 338 */ 339 pc->pc_ucred = crcopy(pc->pc_ucred); 340 pc->pc_ucred->cr_uid = euid; 341 p->p_flag |= P_SUGID; 342 return (0); 343 } 344 345 int 346 sys_setreuid(p, v, retval) 347 struct proc *p; 348 void *v; 349 register_t *retval; 350 { 351 struct sys_setreuid_args /* { 352 syscallarg(uid_t) ruid; 353 syscallarg(uid_t) euid; 354 } */ *uap = v; 355 register struct pcred *pc = p->p_cred; 356 register uid_t ruid, euid; 357 int error; 358 359 ruid = SCARG(uap, ruid); 360 euid = SCARG(uap, euid); 361 362 if (ruid != (uid_t)-1 && 363 ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid && 364 (error = suser(pc->pc_ucred, &p->p_acflag))) 365 return (error); 366 367 if (euid != (uid_t)-1 && 368 euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid && 369 euid != pc->p_svuid && 370 (error = suser(pc->pc_ucred, &p->p_acflag))) 371 return (error); 372 373 if (euid != (uid_t)-1) { 374 pc->pc_ucred = crcopy(pc->pc_ucred); 375 pc->pc_ucred->cr_uid = euid; 376 } 377 378 if (ruid != (uid_t)-1) { 379 (void)chgproccnt(pc->p_ruid, -1); 380 (void)chgproccnt(ruid, 1); 381 pc->p_ruid = ruid; 382 pc->p_svuid = pc->pc_ucred->cr_uid; 383 } 384 385 if (euid != (uid_t)-1 && ruid != (uid_t)-1) 386 p->p_flag |= P_SUGID; 387 return (0); 388 } 389 390 /* ARGSUSED */ 391 int 392 sys_setgid(p, v, retval) 393 struct proc *p; 394 void *v; 395 register_t *retval; 396 { 397 struct sys_setgid_args /* { 398 syscallarg(gid_t) gid; 399 } */ *uap = v; 400 register struct pcred *pc = p->p_cred; 401 register gid_t gid; 402 int error; 403 404 #ifdef COMPAT_09 /* XXX */ 405 gid = (u_short)SCARG(uap, gid); 406 #else 407 gid = SCARG(uap, gid); 408 #endif 409 if (gid != pc->p_rgid && 410 (error = suser(pc->pc_ucred, &p->p_acflag))) 411 return (error); 412 pc->pc_ucred = crcopy(pc->pc_ucred); 413 pc->pc_ucred->cr_gid = gid; 414 pc->p_rgid = gid; 415 pc->p_svgid = gid; 416 p->p_flag |= P_SUGID; 417 return (0); 418 } 419 420 /* ARGSUSED */ 421 int 422 sys_setegid(p, v, retval) 423 struct proc *p; 424 void *v; 425 register_t *retval; 426 { 427 struct sys_setegid_args /* { 428 syscallarg(gid_t) egid; 429 } */ *uap = v; 430 register struct pcred *pc = p->p_cred; 431 register gid_t egid; 432 int error; 433 434 #ifdef COMPAT_09 /* XXX */ 435 egid = (u_short)SCARG(uap, egid); 436 #else 437 egid = SCARG(uap, egid); 438 #endif 439 if (egid != pc->p_rgid && egid != pc->p_svgid && 440 (error = suser(pc->pc_ucred, &p->p_acflag))) 441 return (error); 442 pc->pc_ucred = crcopy(pc->pc_ucred); 443 pc->pc_ucred->cr_gid = egid; 444 p->p_flag |= P_SUGID; 445 return (0); 446 } 447 448 int 449 sys_setregid(p, v, retval) 450 struct proc *p; 451 void *v; 452 register_t *retval; 453 { 454 struct sys_setregid_args /* { 455 syscallarg(gid_t) rgid; 456 syscallarg(gid_t) egid; 457 } */ *uap = v; 458 register struct pcred *pc = p->p_cred; 459 register gid_t rgid, egid; 460 int error; 461 462 rgid = SCARG(uap, rgid); 463 egid = SCARG(uap, egid); 464 465 if (rgid != (gid_t)-1 && 466 rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid && 467 (error = suser(pc->pc_ucred, &p->p_acflag))) 468 return (error); 469 470 if (egid != (gid_t)-1 && 471 egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid && 472 egid != pc->p_svgid && 473 (error = suser(pc->pc_ucred, &p->p_acflag))) 474 return (error); 475 476 if (egid != (gid_t)-1) { 477 pc->pc_ucred = crcopy(pc->pc_ucred); 478 pc->pc_ucred->cr_gid = egid; 479 } 480 481 if (rgid != (gid_t)-1) { 482 pc->p_rgid = rgid; 483 pc->p_svgid = pc->pc_ucred->cr_gid; 484 } 485 486 if (egid != (gid_t)-1 && rgid != (gid_t)-1) 487 p->p_flag |= P_SUGID; 488 return (0); 489 } 490 491 /* ARGSUSED */ 492 int 493 sys_setgroups(p, v, retval) 494 struct proc *p; 495 void *v; 496 register_t *retval; 497 { 498 struct sys_setgroups_args /* { 499 syscallarg(u_int) gidsetsize; 500 syscallarg(gid_t *) gidset; 501 } */ *uap = v; 502 register struct pcred *pc = p->p_cred; 503 register u_int ngrp; 504 int error; 505 506 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0) 507 return (error); 508 ngrp = SCARG(uap, gidsetsize); 509 if (ngrp > NGROUPS) 510 return (EINVAL); 511 pc->pc_ucred = crcopy(pc->pc_ucred); 512 error = copyin((caddr_t)SCARG(uap, gidset), 513 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)); 514 if (error) 515 return (error); 516 pc->pc_ucred->cr_ngroups = ngrp; 517 p->p_flag |= P_SUGID; 518 return (0); 519 } 520 521 /* 522 * Check if gid is a member of the group set. 523 */ 524 int 525 groupmember(gid, cred) 526 gid_t gid; 527 register struct ucred *cred; 528 { 529 register gid_t *gp; 530 gid_t *egp; 531 532 egp = &(cred->cr_groups[cred->cr_ngroups]); 533 for (gp = cred->cr_groups; gp < egp; gp++) 534 if (*gp == gid) 535 return (1); 536 return (0); 537 } 538 539 /* 540 * Test whether the specified credentials imply "super-user" 541 * privilege; if so, and we have accounting info, set the flag 542 * indicating use of super-powers. 543 * Returns 0 or error. 544 */ 545 int 546 suser(cred, acflag) 547 struct ucred *cred; 548 u_short *acflag; 549 { 550 if (cred->cr_uid == 0) { 551 if (acflag) 552 *acflag |= ASU; 553 return (0); 554 } 555 return (EPERM); 556 } 557 558 /* 559 * Allocate a zeroed cred structure. 560 */ 561 struct ucred * 562 crget() 563 { 564 register struct ucred *cr; 565 566 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 567 bzero((caddr_t)cr, sizeof(*cr)); 568 cr->cr_ref = 1; 569 return (cr); 570 } 571 572 /* 573 * Free a cred structure. 574 * Throws away space when ref count gets to 0. 575 */ 576 void 577 crfree(cr) 578 struct ucred *cr; 579 { 580 int s; 581 582 s = splimp(); /* ??? */ 583 if (--cr->cr_ref == 0) 584 FREE((caddr_t)cr, M_CRED); 585 (void) splx(s); 586 } 587 588 /* 589 * Copy cred structure to a new one and free the old one. 590 */ 591 struct ucred * 592 crcopy(cr) 593 struct ucred *cr; 594 { 595 struct ucred *newcr; 596 597 if (cr->cr_ref == 1) 598 return (cr); 599 newcr = crget(); 600 *newcr = *cr; 601 crfree(cr); 602 newcr->cr_ref = 1; 603 return (newcr); 604 } 605 606 /* 607 * Dup cred struct to a new held one. 608 */ 609 struct ucred * 610 crdup(cr) 611 struct ucred *cr; 612 { 613 struct ucred *newcr; 614 615 newcr = crget(); 616 *newcr = *cr; 617 newcr->cr_ref = 1; 618 return (newcr); 619 } 620 621 /* 622 * Get login name, if available. 623 */ 624 /* ARGSUSED */ 625 int 626 sys___getlogin(p, v, retval) 627 struct proc *p; 628 void *v; 629 register_t *retval; 630 { 631 struct sys___getlogin_args /* { 632 syscallarg(char *) namebuf; 633 syscallarg(u_int) namelen; 634 } */ *uap = v; 635 636 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 637 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 638 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 639 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 640 } 641 642 /* 643 * Set login name. 644 */ 645 /* ARGSUSED */ 646 int 647 sys_setlogin(p, v, retval) 648 struct proc *p; 649 void *v; 650 register_t *retval; 651 { 652 struct sys_setlogin_args /* { 653 syscallarg(char *) namebuf; 654 } */ *uap = v; 655 int error; 656 657 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 658 return (error); 659 error = copyinstr((caddr_t) SCARG(uap, namebuf), 660 (caddr_t) p->p_pgrp->pg_session->s_login, 661 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0); 662 if (error == ENAMETOOLONG) 663 error = EINVAL; 664 return (error); 665 } 666