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