Home | History | Annotate | Line # | Download | only in kern
kern_prot.c revision 1.34
      1 /*	$NetBSD: kern_prot.c,v 1.34 1996/05/22 02:22:47 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 /* ARGSUSED */
    327 int
    328 sys_setgid(p, v, retval)
    329 	struct proc *p;
    330 	void *v;
    331 	register_t *retval;
    332 {
    333 	struct sys_setgid_args /* {
    334 		syscallarg(gid_t) gid;
    335 	} */ *uap = v;
    336 	register struct pcred *pc = p->p_cred;
    337 	register gid_t gid;
    338 	int error;
    339 
    340 #ifdef COMPAT_09				/* XXX */
    341 	gid = (u_short)SCARG(uap, gid);
    342 #else
    343 	gid = SCARG(uap, gid);
    344 #endif
    345 	if (gid != pc->p_rgid &&
    346 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    347 		return (error);
    348 	pc->pc_ucred = crcopy(pc->pc_ucred);
    349 	pc->pc_ucred->cr_gid = gid;
    350 	pc->p_rgid = gid;
    351 	pc->p_svgid = gid;
    352 	p->p_flag |= P_SUGID;
    353 	return (0);
    354 }
    355 
    356 /* ARGSUSED */
    357 int
    358 sys_setegid(p, v, retval)
    359 	struct proc *p;
    360 	void *v;
    361 	register_t *retval;
    362 {
    363 	struct sys_setegid_args /* {
    364 		syscallarg(gid_t) egid;
    365 	} */ *uap = v;
    366 	register struct pcred *pc = p->p_cred;
    367 	register gid_t egid;
    368 	int error;
    369 
    370 #ifdef COMPAT_09				/* XXX */
    371 	egid = (u_short)SCARG(uap, egid);
    372 #else
    373 	egid = SCARG(uap, egid);
    374 #endif
    375 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
    376 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    377 		return (error);
    378 	pc->pc_ucred = crcopy(pc->pc_ucred);
    379 	pc->pc_ucred->cr_gid = egid;
    380 	p->p_flag |= P_SUGID;
    381 	return (0);
    382 }
    383 
    384 /* ARGSUSED */
    385 int
    386 sys_setgroups(p, v, retval)
    387 	struct proc *p;
    388 	void *v;
    389 	register_t *retval;
    390 {
    391 	struct sys_setgroups_args /* {
    392 		syscallarg(u_int) gidsetsize;
    393 		syscallarg(gid_t *) gidset;
    394 	} */ *uap = v;
    395 	register struct pcred *pc = p->p_cred;
    396 	register u_int ngrp;
    397 	int error;
    398 
    399 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
    400 		return (error);
    401 	ngrp = SCARG(uap, gidsetsize);
    402 	if (ngrp > NGROUPS)
    403 		return (EINVAL);
    404 	pc->pc_ucred = crcopy(pc->pc_ucred);
    405 	error = copyin((caddr_t)SCARG(uap, gidset),
    406 		       (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
    407 	if (error)
    408 		return (error);
    409 	pc->pc_ucred->cr_ngroups = ngrp;
    410 	p->p_flag |= P_SUGID;
    411 	return (0);
    412 }
    413 
    414 /*
    415  * Check if gid is a member of the group set.
    416  */
    417 int
    418 groupmember(gid, cred)
    419 	gid_t gid;
    420 	register struct ucred *cred;
    421 {
    422 	register gid_t *gp;
    423 	gid_t *egp;
    424 
    425 	egp = &(cred->cr_groups[cred->cr_ngroups]);
    426 	for (gp = cred->cr_groups; gp < egp; gp++)
    427 		if (*gp == gid)
    428 			return (1);
    429 	return (0);
    430 }
    431 
    432 /*
    433  * Test whether the specified credentials imply "super-user"
    434  * privilege; if so, and we have accounting info, set the flag
    435  * indicating use of super-powers.
    436  * Returns 0 or error.
    437  */
    438 int
    439 suser(cred, acflag)
    440 	struct ucred *cred;
    441 	u_short *acflag;
    442 {
    443 	if (cred->cr_uid == 0) {
    444 		if (acflag)
    445 			*acflag |= ASU;
    446 		return (0);
    447 	}
    448 	return (EPERM);
    449 }
    450 
    451 /*
    452  * Allocate a zeroed cred structure.
    453  */
    454 struct ucred *
    455 crget()
    456 {
    457 	register struct ucred *cr;
    458 
    459 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
    460 	bzero((caddr_t)cr, sizeof(*cr));
    461 	cr->cr_ref = 1;
    462 	return (cr);
    463 }
    464 
    465 /*
    466  * Free a cred structure.
    467  * Throws away space when ref count gets to 0.
    468  */
    469 void
    470 crfree(cr)
    471 	struct ucred *cr;
    472 {
    473 	int s;
    474 
    475 	s = splimp();				/* ??? */
    476 	if (--cr->cr_ref == 0)
    477 		FREE((caddr_t)cr, M_CRED);
    478 	(void) splx(s);
    479 }
    480 
    481 /*
    482  * Copy cred structure to a new one and free the old one.
    483  */
    484 struct ucred *
    485 crcopy(cr)
    486 	struct ucred *cr;
    487 {
    488 	struct ucred *newcr;
    489 
    490 	if (cr->cr_ref == 1)
    491 		return (cr);
    492 	newcr = crget();
    493 	*newcr = *cr;
    494 	crfree(cr);
    495 	newcr->cr_ref = 1;
    496 	return (newcr);
    497 }
    498 
    499 /*
    500  * Dup cred struct to a new held one.
    501  */
    502 struct ucred *
    503 crdup(cr)
    504 	struct ucred *cr;
    505 {
    506 	struct ucred *newcr;
    507 
    508 	newcr = crget();
    509 	*newcr = *cr;
    510 	newcr->cr_ref = 1;
    511 	return (newcr);
    512 }
    513 
    514 /*
    515  * Get login name, if available.
    516  */
    517 /* ARGSUSED */
    518 int
    519 sys_getlogin(p, v, retval)
    520 	struct proc *p;
    521 	void *v;
    522 	register_t *retval;
    523 {
    524 	struct sys_getlogin_args /* {
    525 		syscallarg(char *) namebuf;
    526 		syscallarg(u_int) namelen;
    527 	} */ *uap = v;
    528 
    529 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
    530 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
    531 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
    532 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
    533 }
    534 
    535 /*
    536  * Set login name.
    537  */
    538 /* ARGSUSED */
    539 int
    540 sys_setlogin(p, v, retval)
    541 	struct proc *p;
    542 	void *v;
    543 	register_t *retval;
    544 {
    545 	struct sys_setlogin_args /* {
    546 		syscallarg(char *) namebuf;
    547 	} */ *uap = v;
    548 	int error;
    549 
    550 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    551 		return (error);
    552 	error = copyinstr((caddr_t) SCARG(uap, namebuf),
    553 	    (caddr_t) p->p_pgrp->pg_session->s_login,
    554 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
    555 	if (error == ENAMETOOLONG)
    556 		error = EINVAL;
    557 	return (error);
    558 }
    559