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