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