Home | History | Annotate | Line # | Download | only in kern
kern_prot.c revision 1.1.1.3
      1 /*
      2  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
      3  *	The Regents of the University of California.  All rights reserved.
      4  * (c) UNIX System Laboratories, Inc.
      5  * All or some portions of this file are derived from material licensed
      6  * to the University of California by American Telephone and Telegraph
      7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      8  * the permission of UNIX System Laboratories, Inc.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  *
     38  *	@(#)kern_prot.c	8.9 (Berkeley) 2/14/95
     39  */
     40 
     41 /*
     42  * System calls related to processes and protection
     43  */
     44 
     45 #include <sys/param.h>
     46 #include <sys/acct.h>
     47 #include <sys/systm.h>
     48 #include <sys/ucred.h>
     49 #include <sys/proc.h>
     50 #include <sys/timeb.h>
     51 #include <sys/times.h>
     52 #include <sys/malloc.h>
     53 
     54 #include <sys/mount.h>
     55 #include <sys/syscallargs.h>
     56 
     57 /* ARGSUSED */
     58 int
     59 getpid(p, uap, retval)
     60 	struct proc *p;
     61 	void *uap;
     62 	register_t *retval;
     63 {
     64 
     65 	*retval = p->p_pid;
     66 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
     67 	retval[1] = p->p_pptr->p_pid;
     68 #endif
     69 	return (0);
     70 }
     71 
     72 /* ARGSUSED */
     73 int
     74 getppid(p, uap, retval)
     75 	struct proc *p;
     76 	void *uap;
     77 	register_t *retval;
     78 {
     79 
     80 	*retval = p->p_pptr->p_pid;
     81 	return (0);
     82 }
     83 
     84 /* Get process group ID; note that POSIX getpgrp takes no parameter */
     85 int
     86 getpgrp(p, uap, retval)
     87 	struct proc *p;
     88 	void *uap;
     89 	register_t *retval;
     90 {
     91 
     92 	*retval = p->p_pgrp->pg_id;
     93 	return (0);
     94 }
     95 
     96 /* ARGSUSED */
     97 int
     98 getuid(p, uap, retval)
     99 	struct proc *p;
    100 	void *uap;
    101 	register_t *retval;
    102 {
    103 
    104 	*retval = p->p_cred->p_ruid;
    105 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    106 	retval[1] = p->p_ucred->cr_uid;
    107 #endif
    108 	return (0);
    109 }
    110 
    111 /* ARGSUSED */
    112 int
    113 geteuid(p, uap, retval)
    114 	struct proc *p;
    115 	void *uap;
    116 	register_t *retval;
    117 {
    118 
    119 	*retval = p->p_ucred->cr_uid;
    120 	return (0);
    121 }
    122 
    123 /* ARGSUSED */
    124 int
    125 getgid(p, uap, retval)
    126 	struct proc *p;
    127 	void *uap;
    128 	register_t *retval;
    129 {
    130 
    131 	*retval = p->p_cred->p_rgid;
    132 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    133 	retval[1] = p->p_ucred->cr_groups[0];
    134 #endif
    135 	return (0);
    136 }
    137 
    138 /*
    139  * Get effective group ID.  The "egid" is groups[0], and could be obtained
    140  * via getgroups.  This syscall exists because it is somewhat painful to do
    141  * correctly in a library function.
    142  */
    143 /* ARGSUSED */
    144 int
    145 getegid(p, uap, retval)
    146 	struct proc *p;
    147 	void *uap;
    148 	register_t *retval;
    149 {
    150 
    151 	*retval = p->p_ucred->cr_groups[0];
    152 	return (0);
    153 }
    154 
    155 int
    156 getgroups(p, uap, retval)
    157 	struct proc *p;
    158 	register struct getgroups_args /* {
    159 		syscallarg(u_int) gidsetsize;
    160 		syscallarg(gid_t *) gidset;
    161 	} */ *uap;
    162 	register_t *retval;
    163 {
    164 	register struct pcred *pc = p->p_cred;
    165 	register u_int ngrp;
    166 	int error;
    167 
    168 	if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
    169 		*retval = pc->pc_ucred->cr_ngroups;
    170 		return (0);
    171 	}
    172 	if (ngrp < pc->pc_ucred->cr_ngroups)
    173 		return (EINVAL);
    174 	ngrp = pc->pc_ucred->cr_ngroups;
    175 	if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
    176 	    (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)))
    177 		return (error);
    178 	*retval = ngrp;
    179 	return (0);
    180 }
    181 
    182 /* ARGSUSED */
    183 int
    184 setsid(p, uap, retval)
    185 	register struct proc *p;
    186 	void *uap;
    187 	register_t *retval;
    188 {
    189 
    190 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
    191 		return (EPERM);
    192 	} else {
    193 		(void)enterpgrp(p, p->p_pid, 1);
    194 		*retval = p->p_pid;
    195 		return (0);
    196 	}
    197 }
    198 
    199 /*
    200  * set process group (setpgid/old setpgrp)
    201  *
    202  * caller does setpgid(targpid, targpgid)
    203  *
    204  * pid must be caller or child of caller (ESRCH)
    205  * if a child
    206  *	pid must be in same session (EPERM)
    207  *	pid can't have done an exec (EACCES)
    208  * if pgid != pid
    209  * 	there must exist some pid in same session having pgid (EPERM)
    210  * pid must not be session leader (EPERM)
    211  */
    212 /* ARGSUSED */
    213 int
    214 setpgid(curp, uap, retval)
    215 	struct proc *curp;
    216 	register struct setpgid_args /* {
    217 		syscallarg(int) pid;
    218 		syscallarg(int) pgid;
    219 	} */ *uap;
    220 	register_t *retval;
    221 {
    222 	register struct proc *targp;		/* target process */
    223 	register struct pgrp *pgrp;		/* target pgrp */
    224 
    225 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
    226 		if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
    227 			return (ESRCH);
    228 		if (targp->p_session != curp->p_session)
    229 			return (EPERM);
    230 		if (targp->p_flag & P_EXEC)
    231 			return (EACCES);
    232 	} else
    233 		targp = curp;
    234 	if (SESS_LEADER(targp))
    235 		return (EPERM);
    236 	if (SCARG(uap, pgid) == 0)
    237 		SCARG(uap, pgid) = targp->p_pid;
    238 	else if (SCARG(uap, pgid) != targp->p_pid)
    239 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
    240 	            pgrp->pg_session != curp->p_session)
    241 			return (EPERM);
    242 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
    243 }
    244 
    245 /* ARGSUSED */
    246 int
    247 setuid(p, uap, retval)
    248 	struct proc *p;
    249 	struct setuid_args /* {
    250 		syscallarg(uid_t) uid;
    251 	} */ *uap;
    252 	register_t *retval;
    253 {
    254 	register struct pcred *pc = p->p_cred;
    255 	register uid_t uid;
    256 	int error;
    257 
    258 	uid = SCARG(uap, uid);
    259 	if (uid != pc->p_ruid &&
    260 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    261 		return (error);
    262 	/*
    263 	 * Everything's okay, do it.
    264 	 * Transfer proc count to new user.
    265 	 * Copy credentials so other references do not see our changes.
    266 	 */
    267 	(void)chgproccnt(pc->p_ruid, -1);
    268 	(void)chgproccnt(uid, 1);
    269 	pc->pc_ucred = crcopy(pc->pc_ucred);
    270 	pc->pc_ucred->cr_uid = uid;
    271 	pc->p_ruid = uid;
    272 	pc->p_svuid = uid;
    273 	p->p_flag |= P_SUGID;
    274 	return (0);
    275 }
    276 
    277 /* ARGSUSED */
    278 int
    279 seteuid(p, uap, retval)
    280 	struct proc *p;
    281 	struct seteuid_args /* {
    282 		syscallarg(uid_t) euid;
    283 	} */ *uap;
    284 	register_t *retval;
    285 {
    286 	register struct pcred *pc = p->p_cred;
    287 	register uid_t euid;
    288 	int error;
    289 
    290 	euid = SCARG(uap, euid);
    291 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
    292 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    293 		return (error);
    294 	/*
    295 	 * Everything's okay, do it.  Copy credentials so other references do
    296 	 * not see our changes.
    297 	 */
    298 	pc->pc_ucred = crcopy(pc->pc_ucred);
    299 	pc->pc_ucred->cr_uid = euid;
    300 	p->p_flag |= P_SUGID;
    301 	return (0);
    302 }
    303 
    304 /* ARGSUSED */
    305 int
    306 setgid(p, uap, retval)
    307 	struct proc *p;
    308 	struct setgid_args /* {
    309 		syscallarg(gid_t) gid;
    310 	} */ *uap;
    311 	register_t *retval;
    312 {
    313 	register struct pcred *pc = p->p_cred;
    314 	register gid_t gid;
    315 	int error;
    316 
    317 	gid = SCARG(uap, gid);
    318 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
    319 		return (error);
    320 	pc->pc_ucred = crcopy(pc->pc_ucred);
    321 	pc->pc_ucred->cr_groups[0] = gid;
    322 	pc->p_rgid = gid;
    323 	pc->p_svgid = gid;		/* ??? */
    324 	p->p_flag |= P_SUGID;
    325 	return (0);
    326 }
    327 
    328 /* ARGSUSED */
    329 int
    330 setegid(p, uap, retval)
    331 	struct proc *p;
    332 	struct setegid_args /* {
    333 		syscallarg(gid_t) egid;
    334 	} */ *uap;
    335 	register_t *retval;
    336 {
    337 	register struct pcred *pc = p->p_cred;
    338 	register gid_t egid;
    339 	int error;
    340 
    341 	egid = SCARG(uap, egid);
    342 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
    343 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    344 		return (error);
    345 	pc->pc_ucred = crcopy(pc->pc_ucred);
    346 	pc->pc_ucred->cr_groups[0] = egid;
    347 	p->p_flag |= P_SUGID;
    348 	return (0);
    349 }
    350 
    351 /* ARGSUSED */
    352 int
    353 setgroups(p, uap, retval)
    354 	struct proc *p;
    355 	struct setgroups_args /* {
    356 		syscallarg(u_int) gidsetsize;
    357 		syscallarg(gid_t *) gidset;
    358 	} */ *uap;
    359 	register_t *retval;
    360 {
    361 	register struct pcred *pc = p->p_cred;
    362 	register u_int ngrp;
    363 	int error;
    364 
    365 	if (error = suser(pc->pc_ucred, &p->p_acflag))
    366 		return (error);
    367 	ngrp = SCARG(uap, gidsetsize);
    368 	if (ngrp < 1 || ngrp > NGROUPS)
    369 		return (EINVAL);
    370 	pc->pc_ucred = crcopy(pc->pc_ucred);
    371 	if (error = copyin((caddr_t)SCARG(uap, gidset),
    372 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
    373 		return (error);
    374 	pc->pc_ucred->cr_ngroups = ngrp;
    375 	p->p_flag |= P_SUGID;
    376 	return (0);
    377 }
    378 
    379 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
    380 /* ARGSUSED */
    381 int
    382 compat_43_setreuid(p, uap, retval)
    383 	register struct proc *p;
    384 	struct compat_43_setreuid_args /* {
    385 		syscallarg(int) ruid;
    386 		syscallarg(int) euid;
    387 	} */ *uap;
    388 	register_t *retval;
    389 {
    390 	register struct pcred *pc = p->p_cred;
    391 	union {
    392 		struct setuid_args sa;
    393 		struct seteuid_args ea;
    394 	} args;
    395 
    396 	/*
    397 	 * If ruid == euid then setreuid is being used to emulate setuid,
    398 	 * just do it.
    399 	 */
    400 	if (SCARG(uap, ruid) != -1 && SCARG(uap, ruid) == SCARG(uap, euid)) {
    401 		SCARG(&args.sa, uid) = SCARG(uap, ruid);
    402 		return (setuid(p, &args.sa, retval));
    403 	}
    404 	/*
    405 	 * Otherwise we assume that the intent of setting ruid is to be
    406 	 * able to get back ruid priviledge (i.e. swapping ruid and euid).
    407 	 * So we make sure that we will be able to do so, but do not
    408 	 * actually set the ruid.
    409 	 */
    410 	if (SCARG(uap, ruid) != (uid_t)-1 && SCARG(uap, ruid) != pc->p_ruid &&
    411 	    SCARG(uap, ruid) != pc->p_svuid)
    412 		return (EPERM);
    413 	if (SCARG(uap, euid) == (uid_t)-1)
    414 		return (0);
    415 	SCARG(&args.ea, euid) = SCARG(uap, euid);
    416 	return (seteuid(p, &args.ea, retval));
    417 }
    418 
    419 /* ARGSUSED */
    420 int
    421 compat_43_setregid(p, uap, retval)
    422 	register struct proc *p;
    423 	struct compat_43_setregid_args /* {
    424 		syscallarg(int) rgid;
    425 		syscallarg(int) egid;
    426 	} */ *uap;
    427 	register_t *retval;
    428 {
    429 	register struct pcred *pc = p->p_cred;
    430 	union {
    431 		struct setgid_args sa;
    432 		struct setegid_args ea;
    433 	} args;
    434 
    435 	/*
    436 	 * If rgid == egid then setreuid is being used to emulate setgid,
    437 	 * just do it.
    438 	 */
    439 	if (SCARG(uap, rgid) != -1 && SCARG(uap, rgid) == SCARG(uap, egid)) {
    440 		SCARG(&args.sa, gid) = SCARG(uap, rgid);
    441 		return (setgid(p, &args.sa, retval));
    442 	}
    443 	/*
    444 	 * Otherwise we assume that the intent of setting rgid is to be
    445 	 * able to get back rgid priviledge (i.e. swapping rgid and egid).
    446 	 * So we make sure that we will be able to do so, but do not
    447 	 * actually set the rgid.
    448 	 */
    449 	if (SCARG(uap, rgid) != (gid_t)-1 && SCARG(uap, rgid) != pc->p_rgid &&
    450 	    SCARG(uap, rgid) != pc->p_svgid)
    451 		return (EPERM);
    452 	if (SCARG(uap, egid) == (gid_t)-1)
    453 		return (0);
    454 	SCARG(&args.ea, egid) = SCARG(uap, egid);
    455 	return (setegid(p, &args.ea, retval));
    456 }
    457 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
    458 
    459 /*
    460  * Check if gid is a member of the group set.
    461  */
    462 int
    463 groupmember(gid, cred)
    464 	gid_t gid;
    465 	register struct ucred *cred;
    466 {
    467 	register gid_t *gp;
    468 	gid_t *egp;
    469 
    470 	egp = &(cred->cr_groups[cred->cr_ngroups]);
    471 	for (gp = cred->cr_groups; gp < egp; gp++)
    472 		if (*gp == gid)
    473 			return (1);
    474 	return (0);
    475 }
    476 
    477 /*
    478  * Test whether the specified credentials imply "super-user"
    479  * privilege; if so, and we have accounting info, set the flag
    480  * indicating use of super-powers.
    481  * Returns 0 or error.
    482  */
    483 int
    484 suser(cred, acflag)
    485 	struct ucred *cred;
    486 	u_short *acflag;
    487 {
    488 	if (cred->cr_uid == 0) {
    489 		if (acflag)
    490 			*acflag |= ASU;
    491 		return (0);
    492 	}
    493 	return (EPERM);
    494 }
    495 
    496 /*
    497  * Allocate a zeroed cred structure.
    498  */
    499 struct ucred *
    500 crget()
    501 {
    502 	register struct ucred *cr;
    503 
    504 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
    505 	bzero((caddr_t)cr, sizeof(*cr));
    506 	cr->cr_ref = 1;
    507 	return (cr);
    508 }
    509 
    510 /*
    511  * Free a cred structure.
    512  * Throws away space when ref count gets to 0.
    513  */
    514 void
    515 crfree(cr)
    516 	struct ucred *cr;
    517 {
    518 	int s;
    519 
    520 	s = splimp();				/* ??? */
    521 	if (--cr->cr_ref == 0)
    522 		FREE((caddr_t)cr, M_CRED);
    523 	(void) splx(s);
    524 }
    525 
    526 /*
    527  * Copy cred structure to a new one and free the old one.
    528  */
    529 struct ucred *
    530 crcopy(cr)
    531 	struct ucred *cr;
    532 {
    533 	struct ucred *newcr;
    534 
    535 	if (cr->cr_ref == 1)
    536 		return (cr);
    537 	newcr = crget();
    538 	*newcr = *cr;
    539 	crfree(cr);
    540 	newcr->cr_ref = 1;
    541 	return (newcr);
    542 }
    543 
    544 /*
    545  * Dup cred struct to a new held one.
    546  */
    547 struct ucred *
    548 crdup(cr)
    549 	struct ucred *cr;
    550 {
    551 	struct ucred *newcr;
    552 
    553 	newcr = crget();
    554 	*newcr = *cr;
    555 	newcr->cr_ref = 1;
    556 	return (newcr);
    557 }
    558 
    559 /*
    560  * Get login name, if available.
    561  */
    562 /* ARGSUSED */
    563 int
    564 getlogin(p, uap, retval)
    565 	struct proc *p;
    566 	struct getlogin_args /* {
    567 		syscallarg(char *) namebuf;
    568 		syscallarg(u_int) namelen;
    569 	} */ *uap;
    570 	register_t *retval;
    571 {
    572 
    573 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
    574 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
    575 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
    576 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
    577 }
    578 
    579 /*
    580  * Set login name.
    581  */
    582 /* ARGSUSED */
    583 int
    584 setlogin(p, uap, retval)
    585 	struct proc *p;
    586 	struct setlogin_args /* {
    587 		syscallarg(char *) namebuf;
    588 	} */ *uap;
    589 	register_t *retval;
    590 {
    591 	int error;
    592 
    593 	if (error = suser(p->p_ucred, &p->p_acflag))
    594 		return (error);
    595 	error = copyinstr((caddr_t) SCARG(uap, namebuf),
    596 	    (caddr_t) p->p_pgrp->pg_session->s_login,
    597 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
    598 	if (error == ENAMETOOLONG)
    599 		error = EINVAL;
    600 	return (error);
    601 }
    602