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