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