xref: /csrg-svn/sys/kern/kern_prot.c (revision 44439)
123372Smckusick /*
243393Skarels  * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California.
337578Smckusick  * All rights reserved.
423372Smckusick  *
5*44439Sbostic  * %sccs.include.redist.c%
637578Smckusick  *
7*44439Sbostic  *	@(#)kern_prot.c	7.13 (Berkeley) 06/28/90
823372Smckusick  */
97420Sroot 
107420Sroot /*
117498Sroot  * System calls related to processes and protection
127420Sroot  */
137420Sroot 
1417092Sbloom #include "param.h"
1537578Smckusick #include "acct.h"
1617092Sbloom #include "systm.h"
1744405Skarels #include "user.h"
1817092Sbloom #include "proc.h"
1917092Sbloom #include "timeb.h"
2017092Sbloom #include "times.h"
2137578Smckusick #include "malloc.h"
227420Sroot 
2343393Skarels /* ARGSUSED */
2443393Skarels getpid(p, uap, retval)
2543393Skarels 	struct proc *p;
2643393Skarels 	void *uap;
2743393Skarels 	int *retval;
2843393Skarels {
2937579Smckusick 
3043393Skarels 	*retval = p->p_pid;
3143393Skarels #ifdef COMPAT_43
3243393Skarels 	retval[1] = p->p_ppid;
3343393Skarels #endif
3444405Skarels 	return (0);
3543393Skarels }
3643393Skarels 
3743393Skarels /* ARGSUSED */
3843393Skarels getppid(p, uap, retval)
3943393Skarels 	struct proc *p;
4043393Skarels 	void *uap;
4143393Skarels 	int *retval;
427498Sroot {
437498Sroot 
4443393Skarels 	*retval = p->p_ppid;
4544405Skarels 	return (0);
467498Sroot }
477498Sroot 
4843393Skarels getpgrp(p, uap, retval)
4943393Skarels 	struct proc *p;
5043393Skarels 	struct args {
5143393Skarels 		int	pid;
5243393Skarels 	} *uap;
5343393Skarels 	int *retval;
547498Sroot {
557498Sroot 
5643393Skarels 	if (uap->pid != 0 && (p = pfind(uap->pid)) == 0)
5744405Skarels 		return (ESRCH);
5843393Skarels 	*retval = p->p_pgrp->pg_id;
5944405Skarels 	return (0);
607498Sroot }
617498Sroot 
6243393Skarels /* ARGSUSED */
6343393Skarels getuid(p, uap, retval)
6443393Skarels 	struct proc *p;
6543393Skarels 	void *uap;
6643393Skarels 	int *retval;
677420Sroot {
687420Sroot 
6943393Skarels 	*retval = p->p_ruid;
7043393Skarels #ifdef COMPAT_43
7143393Skarels 	retval[1] = u.u_cred->cr_uid;
7243393Skarels #endif
7344405Skarels 	return (0);
747420Sroot }
757420Sroot 
7643393Skarels /* ARGSUSED */
7743393Skarels geteuid(p, uap, retval)
7843393Skarels 	struct proc *p;
7943393Skarels 	void *uap;
8043393Skarels 	int *retval;
817498Sroot {
827498Sroot 
8343393Skarels 	*retval = u.u_cred->cr_uid;
8444405Skarels 	return (0);
857498Sroot }
867498Sroot 
8743393Skarels /* ARGSUSED */
8843393Skarels getgid(p, uap, retval)
8943393Skarels 	struct proc *p;
9043393Skarels 	void *uap;
9143393Skarels 	int *retval;
927498Sroot {
9343393Skarels 
9443393Skarels 	*retval = p->p_rgid;
9543393Skarels #ifdef COMPAT_43
9643393Skarels 	retval[1] = u.u_cred->cr_groups[0];
9743393Skarels #endif
9844405Skarels 	return (0);
9943393Skarels }
10043393Skarels 
10143393Skarels /*
10243393Skarels  * Get effective group ID.
10343393Skarels  * The "egid" is groups[0], and thus could be obtained via getgroups;
10443393Skarels  * this is somewhat painful to do correctly in a library function,
10543393Skarels  * this the existence of this syscall.
10643393Skarels  */
10743393Skarels /* ARGSUSED */
10843393Skarels getegid(p, uap, retval)
10943393Skarels 	struct proc *p;
11043393Skarels 	void *uap;
11143393Skarels 	int *retval;
11243393Skarels {
11343393Skarels 
11443393Skarels 	*retval = u.u_cred->cr_groups[0];
11544405Skarels 	return (0);
11643393Skarels }
11743393Skarels 
11843393Skarels getgroups(p, uap, retval)
11943393Skarels 	struct proc *p;
12043393Skarels 	register struct	arg {
1218624Sroot 		u_int	gidsetsize;
12243393Skarels 		int	*gidset;		/* XXX not yet POSIX */
12343393Skarels 	} *uap;
12443393Skarels 	int *retval;
12543393Skarels {
12618362Skarels 	register gid_t *gp;
12718362Skarels 	register int *lp;
12818362Skarels 	int groups[NGROUPS];
12943393Skarels 	int error;
1307498Sroot 
13137578Smckusick 	if (uap->gidsetsize == 0) {
13243393Skarels 		*retval = u.u_cred->cr_ngroups;
13344405Skarels 		return (0);
13437578Smckusick 	}
13543393Skarels 	if (uap->gidsetsize < u.u_cred->cr_ngroups)
13644405Skarels 		return (EINVAL);
13740667Skarels 	uap->gidsetsize = u.u_cred->cr_ngroups;
13840667Skarels 	gp = u.u_cred->cr_groups;
13937578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
14018362Skarels 		*lp++ = *gp++;
14143393Skarels 	if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
14243393Skarels 	    uap->gidsetsize * sizeof (groups[0])))
14344405Skarels 		return (error);
14443393Skarels 	*retval = uap->gidsetsize;
14544405Skarels 	return (0);
1467498Sroot }
1477498Sroot 
14843393Skarels /* ARGSUSED */
14943393Skarels setsid(p, uap, retval)
15043393Skarels 	struct proc *p;
15143393Skarels 	void *uap;
15243393Skarels 	int *retval;
15337579Smckusick {
15437579Smckusick 
15543393Skarels 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
15644405Skarels 		return (EPERM);
15743393Skarels 	} else {
15837579Smckusick 		pgmv(p, p->p_pid, 1);
15943393Skarels 		*retval = p->p_pid;
16044405Skarels 		return (0);
16137579Smckusick 	}
16237579Smckusick }
16337579Smckusick 
16437579Smckusick /*
16543393Skarels  * set process group (setpgrp/setpgid)
16637579Smckusick  *
16740667Skarels  * caller does setpgrp(pid, pgid)
16840667Skarels  *
16940667Skarels  * pid must be caller or child of caller (ESRCH)
17040667Skarels  * if a child
17140667Skarels  *	pid must be in same session (EPERM)
17240667Skarels  *	pid can't have done an exec (EACCES)
17340667Skarels  * if pgid != pid
17440667Skarels  * 	there must exist some pid in same session having pgid (EPERM)
17540667Skarels  * pid must not be session leader (EPERM)
17637579Smckusick  */
17743393Skarels /* ARGSUSED */
17843393Skarels setpgrp(cp, uap, retval)
17943393Skarels 	struct proc *cp;
18043393Skarels 	register struct args {
1817498Sroot 		int	pid;
18237579Smckusick 		int	pgid;
18343393Skarels 	} *uap;
18443393Skarels 	int *retval;
18543393Skarels {
18637579Smckusick 	register struct proc *p;
18737579Smckusick 	register struct pgrp *pgrp;
1887498Sroot 
18943393Skarels 	if (uap->pid != 0) {
19043393Skarels 		if ((p = pfind(uap->pid)) == 0 || !inferior(p))
19144405Skarels 			return (ESRCH);
19243393Skarels 		if (p->p_session != cp->p_session)
19344405Skarels 			return (EPERM);
19443393Skarels 		if (p->p_flag&SEXEC)
19544405Skarels 			return (EACCES);
19643393Skarels 	} else
19743393Skarels 		p = cp;
19843393Skarels 	if (SESS_LEADER(p))
19944405Skarels 		return (EPERM);
20037579Smckusick 	if (uap->pgid == 0)
20137579Smckusick 		uap->pgid = p->p_pid;
20237579Smckusick 	else if ((uap->pgid != p->p_pid) &&
20337579Smckusick 		(((pgrp = pgfind(uap->pgid)) == 0) ||
20437579Smckusick 		   pgrp->pg_mem == NULL ||
20543393Skarels 	           pgrp->pg_session != u.u_procp->p_session))
20644405Skarels 		return (EPERM);
20737579Smckusick 	/*
20843393Skarels 	 * done checking, now do it
20937579Smckusick 	 */
21037579Smckusick 	pgmv(p, uap->pgid, 0);
21144405Skarels 	return (0);
2127498Sroot }
2137498Sroot 
21443393Skarels /* ARGSUSED */
21543393Skarels setuid(p, uap, retval)
21643393Skarels 	register struct proc *p;
21743393Skarels 	struct args {
21843393Skarels 		int	uid;
21943393Skarels 	} *uap;
22043393Skarels 	int *retval;
2217420Sroot {
22243393Skarels 	register uid_t uid;
22343393Skarels 	int error;
22443393Skarels 
22543393Skarels 	uid = uap->uid;
22643393Skarels 	if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
22744405Skarels 		return (error);
22843393Skarels 	/*
22943393Skarels 	 * Everything's okay, do it.
23043393Skarels 	 * Copy credentials so other references do not
23143393Skarels 	 * see our changes.
23243393Skarels 	 */
23343393Skarels 	if (u.u_cred->cr_ref > 1)
23443393Skarels 		u.u_cred = crcopy(u.u_cred);
23543393Skarels 	u.u_cred->cr_uid = uid;
23643393Skarels 	p->p_uid = uid;
23743393Skarels 	p->p_ruid = uid;
23843393Skarels 	p->p_svuid = uid;
23944405Skarels 	return (0);
24043393Skarels }
24143393Skarels 
24243393Skarels /* ARGSUSED */
24343393Skarels seteuid(p, uap, retval)
24443393Skarels 	register struct proc *p;
24543393Skarels 	struct args {
24643393Skarels 		int	euid;
24743393Skarels 	} *uap;
24843393Skarels 	int *retval;
24943393Skarels {
25043393Skarels 	register uid_t euid;
25143393Skarels 	int error;
25243393Skarels 
25343393Skarels 	euid = uap->euid;
25443393Skarels 	if (euid != p->p_ruid && euid != p->p_svuid &&
25543393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
25644405Skarels 		return (error);
25743393Skarels 	/*
25843393Skarels 	 * Everything's okay, do it.
25943393Skarels 	 * Copy credentials so other references do not
26043393Skarels 	 * see our changes.
26143393Skarels 	 */
26243393Skarels 	if (u.u_cred->cr_ref > 1)
26343393Skarels 		u.u_cred = crcopy(u.u_cred);
26443393Skarels 	u.u_cred->cr_uid = euid;
26543393Skarels 	p->p_uid = euid;
26644405Skarels 	return (0);
26743393Skarels }
26843393Skarels 
26943393Skarels /* ARGSUSED */
27043393Skarels setgid(p, uap, retval)
27143393Skarels 	struct proc *p;
27243393Skarels 	struct args {
27343393Skarels 		int	gid;
27443393Skarels 	} *uap;
27543393Skarels 	int *retval;
27643393Skarels {
27743393Skarels 	register gid_t gid;
27843393Skarels 	int error;
27943393Skarels 
28043393Skarels 	gid = uap->gid;
28143393Skarels 	if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
28244405Skarels 		return (error);
28343393Skarels 	if (u.u_cred->cr_ref > 1)
28443393Skarels 		u.u_cred = crcopy(u.u_cred);
28543393Skarels 	p->p_rgid = gid;
28643393Skarels 	u.u_cred->cr_groups[0] = gid;
28743393Skarels 	p->p_svgid = gid;		/* ??? */
28844405Skarels 	return (0);
28943393Skarels }
29043393Skarels 
29143393Skarels /* ARGSUSED */
29243393Skarels setegid(p, uap, retval)
29343393Skarels 	struct proc *p;
29443393Skarels 	struct args {
29543393Skarels 		int	egid;
29643393Skarels 	} *uap;
29743393Skarels 	int *retval;
29843393Skarels {
29943393Skarels 	register gid_t egid;
30043393Skarels 	int error;
30143393Skarels 
30243393Skarels 	egid = uap->egid;
30343393Skarels 	if (egid != p->p_rgid && egid != p->p_svgid &&
30443393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
30544405Skarels 		return (error);
30643393Skarels 	if (u.u_cred->cr_ref > 1)
30743393Skarels 		u.u_cred = crcopy(u.u_cred);
30843393Skarels 	u.u_cred->cr_groups[0] = egid;
30944405Skarels 	return (0);
31043393Skarels }
31143393Skarels 
31243393Skarels #ifdef COMPAT_43
31343393Skarels /* ARGSUSED */
31443393Skarels osetreuid(p, uap, retval)
31543393Skarels 	register struct proc *p;
31643393Skarels 	struct args {
3179160Ssam 		int	ruid;
3189160Ssam 		int	euid;
3199160Ssam 	} *uap;
32043393Skarels 	int *retval;
32143393Skarels {
32243393Skarels 	register uid_t ruid, euid;
32343393Skarels 	int error;
3249160Ssam 
32543393Skarels 	if (uap->ruid == -1)
32640667Skarels 		ruid = p->p_ruid;
32743393Skarels 	else
32843393Skarels 		ruid = uap->ruid;
32943393Skarels 	/*
33043393Skarels 	 * Allow setting real uid to previous effective,
33143393Skarels 	 * for swapping real and effective.
33243393Skarels 	 * This should be:
33343393Skarels 	 *   if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
33443393Skarels 	 */
33540667Skarels 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
33643393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
33744405Skarels 		return (error);
33843393Skarels 	if (uap->euid == -1)
33940667Skarels 		euid = u.u_cred->cr_uid;
34043393Skarels 	else
34143393Skarels 		euid = uap->euid;
34240667Skarels 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
34343393Skarels 	    euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag)))
34444405Skarels 		return (error);
3459160Ssam 	/*
3469160Ssam 	 * Everything's okay, do it.
34737578Smckusick 	 * Copy credentials so other references do not
34837578Smckusick 	 * see our changes.
3499160Ssam 	 */
35037578Smckusick 	if (u.u_cred->cr_ref > 1)
35137578Smckusick 		u.u_cred = crcopy(u.u_cred);
35240667Skarels 	u.u_cred->cr_uid = euid;
35340667Skarels 	p->p_uid = euid;
35440667Skarels 	p->p_ruid = ruid;
35544405Skarels 	return (0);
3569160Ssam }
3579160Ssam 
35843393Skarels /* ARGSUSED */
35943393Skarels osetregid(p, uap, retval)
36043393Skarels 	struct proc *p;
36143393Skarels 	struct args {
3629160Ssam 		int	rgid;
3639160Ssam 		int	egid;
3649160Ssam 	} *uap;
36543393Skarels 	int *retval;
36643393Skarels {
36743393Skarels 	register gid_t rgid, egid;
36843393Skarels 	int error;
3699160Ssam 
37043393Skarels 	if (uap->rgid == -1)
37140667Skarels 		rgid = p->p_rgid;
37243393Skarels 	else
37343393Skarels 		rgid = uap->rgid;
37443393Skarels 	/*
37543393Skarels 	 * Allow setting real gid to previous effective,
37643393Skarels 	 * for swapping real and effective.  This didn't really work
37743393Skarels 	 * correctly in 4.[23], but is preserved so old stuff doesn't fail.
37843393Skarels 	 * This should be:
37943393Skarels 	 *  if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
38043393Skarels 	 */
38140667Skarels 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
38243393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
38344405Skarels 		return (error);
38443393Skarels 	if (uap->egid == -1)
38540667Skarels 		egid = u.u_cred->cr_groups[0];
38643393Skarels 	else
38743393Skarels 		egid = uap->egid;
38840667Skarels 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
38943393Skarels 	    egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag)))
39044405Skarels 		return (error);
39137578Smckusick 	if (u.u_cred->cr_ref > 1)
39237578Smckusick 		u.u_cred = crcopy(u.u_cred);
39340667Skarels 	p->p_rgid = rgid;
39440667Skarels 	u.u_cred->cr_groups[0] = egid;
39544405Skarels 	return (0);
3969160Ssam }
39743393Skarels #endif
3989160Ssam 
39943393Skarels /* ARGSUSED */
40043393Skarels setgroups(p, uap, retval)
40143393Skarels 	struct proc *p;
40243393Skarels 	struct args {
4038624Sroot 		u_int	gidsetsize;
4047498Sroot 		int	*gidset;
40543393Skarels 	} *uap;
40643393Skarels 	int *retval;
40743393Skarels {
40818362Skarels 	register gid_t *gp;
40918362Skarels 	register int *lp;
41043393Skarels 	int error, ngrp, groups[NGROUPS];
4117498Sroot 
41243393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
41344405Skarels 		return (error);
41440667Skarels 	ngrp = uap->gidsetsize;
41543393Skarels 	if (ngrp > NGROUPS)
41644405Skarels 		return (EINVAL);
41743393Skarels 	error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
41818362Skarels 	    uap->gidsetsize * sizeof (groups[0]));
41943393Skarels 	if (error)
42044405Skarels 		return (error);
42140667Skarels 	gp = u.u_cred->cr_groups;
42237578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
42318362Skarels 		*gp++ = *lp++;
42440667Skarels 	u.u_cred->cr_ngroups = ngrp;
42544405Skarels 	return (0);
4267498Sroot }
4277498Sroot 
4287498Sroot /*
42937578Smckusick  * Check if gid is a member of the group set.
43011810Ssam  */
43137578Smckusick groupmember(gid, cred)
43226275Skarels 	gid_t gid;
43337578Smckusick 	register struct ucred *cred;
4347866Sroot {
43518362Skarels 	register gid_t *gp;
43637578Smckusick 	gid_t *egp;
4377866Sroot 
43837578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
43937578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
4407866Sroot 		if (*gp == gid)
44137578Smckusick 			return (1);
44237578Smckusick 	return (0);
4437866Sroot }
4447866Sroot 
44511810Ssam /*
44637578Smckusick  * Test if the current user is the super user.
44711810Ssam  */
44837578Smckusick suser(cred, acflag)
44937578Smckusick 	struct ucred *cred;
45037578Smckusick 	short *acflag;
4517866Sroot {
4527866Sroot 
45337578Smckusick 	if (cred->cr_uid == 0) {
45437578Smckusick 		if (acflag)
45537578Smckusick 			*acflag |= ASU;
45637578Smckusick 		return (0);
45718362Skarels 	}
45837578Smckusick 	return (EPERM);
4597866Sroot }
46011810Ssam 
46111810Ssam /*
46237578Smckusick  * Allocate a zeroed cred structure.
46311810Ssam  */
46437578Smckusick struct ucred *
46537578Smckusick crget()
46611810Ssam {
46737578Smckusick 	register struct ucred *cr;
46811810Ssam 
46937578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
47037578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
47137578Smckusick 	cr->cr_ref = 1;
47243393Skarels 	return (cr);
47311810Ssam }
47437085Skfall 
47537085Skfall /*
47637578Smckusick  * Free a cred structure.
47737578Smckusick  * Throws away space when ref count gets to 0.
47837085Skfall  */
47937578Smckusick crfree(cr)
48037578Smckusick 	struct ucred *cr;
48137578Smckusick {
48243393Skarels 	int s = splimp();
48337085Skfall 
48437578Smckusick 	if (--cr->cr_ref != 0) {
48537578Smckusick 		(void) splx(s);
48637578Smckusick 		return;
48737578Smckusick 	}
48837578Smckusick 	FREE((caddr_t)cr, M_CRED);
48937578Smckusick 	(void) splx(s);
49037578Smckusick }
49137578Smckusick 
49237578Smckusick /*
49337578Smckusick  * Copy cred structure to a new one and free the old one.
49437578Smckusick  */
49537578Smckusick struct ucred *
49637578Smckusick crcopy(cr)
49737578Smckusick 	struct ucred *cr;
49837085Skfall {
49937578Smckusick 	struct ucred *newcr;
50037085Skfall 
50137578Smckusick 	newcr = crget();
50237578Smckusick 	*newcr = *cr;
50337578Smckusick 	crfree(cr);
50437578Smckusick 	newcr->cr_ref = 1;
50543393Skarels 	return (newcr);
50637085Skfall }
50737085Skfall 
50837085Skfall /*
50937578Smckusick  * Dup cred struct to a new held one.
51037085Skfall  */
51137578Smckusick struct ucred *
51237578Smckusick crdup(cr)
51337578Smckusick 	struct ucred *cr;
51437085Skfall {
51537578Smckusick 	struct ucred *newcr;
51637085Skfall 
51737578Smckusick 	newcr = crget();
51837578Smckusick 	*newcr = *cr;
51937578Smckusick 	newcr->cr_ref = 1;
52043393Skarels 	return (newcr);
52137085Skfall }
52237579Smckusick 
52337579Smckusick /*
52440667Skarels  * Get login name, if available.
52537579Smckusick  */
52643393Skarels /* ARGSUSED */
52743393Skarels getlogin(p, uap, retval)
52843393Skarels 	struct proc *p;
52943393Skarels 	struct args {
53037579Smckusick 		char	*namebuf;
53137579Smckusick 		u_int	namelen;
53243393Skarels 	} *uap;
53343393Skarels 	int *retval;
53443393Skarels {
53537579Smckusick 
53643393Skarels 	if (uap->namelen > sizeof (p->p_logname))
53743393Skarels 		uap->namelen = sizeof (p->p_logname);
53844405Skarels 	return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf,
53943393Skarels 	    uap->namelen));
54037579Smckusick }
54137579Smckusick 
54237579Smckusick /*
54340667Skarels  * Set login name.
54437579Smckusick  */
54543393Skarels /* ARGSUSED */
54643393Skarels setlogin(p, uap, retval)
54743393Skarels 	struct proc *p;
54843393Skarels 	struct args {
54943393Skarels 		char	*namebuf;
55043393Skarels 	} *uap;
55143393Skarels 	int *retval;
55237579Smckusick {
55340667Skarels 	int error;
55437579Smckusick 
55543393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
55644405Skarels 		return (error);
55743393Skarels 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname,
55843393Skarels 	    sizeof (p->p_logname) - 1, (int *) 0);
55940667Skarels 	if (error == ENOENT)		/* name too long */
56040667Skarels 		error = EINVAL;
56144405Skarels 	return (error);
56237579Smckusick }
563