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