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