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