xref: /csrg-svn/sys/kern/kern_prot.c (revision 46293)
123372Smckusick /*
243393Skarels  * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California.
337578Smckusick  * All rights reserved.
423372Smckusick  *
544439Sbostic  * %sccs.include.redist.c%
637578Smckusick  *
7*46293Skarels  *	@(#)kern_prot.c	7.18 (Berkeley) 02/06/91
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 /*
10245908Sbostic  * Get effective group ID.  The "egid" is groups[0], and could be obtained
10345908Sbostic  * via getgroups.  This syscall exists because it is somewhat painful to do
10445908Sbostic  * correctly in a library function.
10543393Skarels  */
10643393Skarels /* ARGSUSED */
10743393Skarels getegid(p, uap, retval)
10843393Skarels 	struct proc *p;
10943393Skarels 	void *uap;
11043393Skarels 	int *retval;
11143393Skarels {
11243393Skarels 	*retval = u.u_cred->cr_groups[0];
11344405Skarels 	return (0);
11443393Skarels }
11543393Skarels 
11643393Skarels getgroups(p, uap, retval)
11743393Skarels 	struct proc *p;
11843393Skarels 	register struct	arg {
1198624Sroot 		u_int	gidsetsize;
12043393Skarels 		int	*gidset;		/* XXX not yet POSIX */
12143393Skarels 	} *uap;
12243393Skarels 	int *retval;
12343393Skarels {
12418362Skarels 	register gid_t *gp;
12518362Skarels 	register int *lp;
12644994Skarels 	register u_int ngrp;
12718362Skarels 	int groups[NGROUPS];
12843393Skarels 	int error;
1297498Sroot 
13044994Skarels 	if ((ngrp = uap->gidsetsize) == 0) {
13143393Skarels 		*retval = u.u_cred->cr_ngroups;
13244405Skarels 		return (0);
13337578Smckusick 	}
13444994Skarels 	if (ngrp < u.u_cred->cr_ngroups)
13544405Skarels 		return (EINVAL);
13644994Skarels 	ngrp = u.u_cred->cr_ngroups;
13744994Skarels 	for (gp = u.u_cred->cr_groups, lp = groups; lp < &groups[ngrp]; )
13818362Skarels 		*lp++ = *gp++;
13943393Skarels 	if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
14044994Skarels 	    ngrp * sizeof (groups[0])))
14144405Skarels 		return (error);
14244994Skarels 	*retval = ngrp;
14344405Skarels 	return (0);
1447498Sroot }
1457498Sroot 
14643393Skarels /* ARGSUSED */
14743393Skarels setsid(p, uap, retval)
14843393Skarels 	struct proc *p;
14943393Skarels 	void *uap;
15043393Skarels 	int *retval;
15137579Smckusick {
15237579Smckusick 
15343393Skarels 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
15444405Skarels 		return (EPERM);
15543393Skarels 	} else {
15637579Smckusick 		pgmv(p, p->p_pid, 1);
15743393Skarels 		*retval = p->p_pid;
15844405Skarels 		return (0);
15937579Smckusick 	}
16037579Smckusick }
16137579Smckusick 
16237579Smckusick /*
16343393Skarels  * set process group (setpgrp/setpgid)
16437579Smckusick  *
16540667Skarels  * caller does setpgrp(pid, pgid)
16640667Skarels  *
16740667Skarels  * pid must be caller or child of caller (ESRCH)
16840667Skarels  * if a child
16940667Skarels  *	pid must be in same session (EPERM)
17040667Skarels  *	pid can't have done an exec (EACCES)
17140667Skarels  * if pgid != pid
17240667Skarels  * 	there must exist some pid in same session having pgid (EPERM)
17340667Skarels  * pid must not be session leader (EPERM)
17437579Smckusick  */
17543393Skarels /* ARGSUSED */
17643393Skarels setpgrp(cp, uap, retval)
17743393Skarels 	struct proc *cp;
17843393Skarels 	register struct args {
1797498Sroot 		int	pid;
18037579Smckusick 		int	pgid;
18143393Skarels 	} *uap;
18243393Skarels 	int *retval;
18343393Skarels {
18437579Smckusick 	register struct proc *p;
18537579Smckusick 	register struct pgrp *pgrp;
1867498Sroot 
18743393Skarels 	if (uap->pid != 0) {
18843393Skarels 		if ((p = pfind(uap->pid)) == 0 || !inferior(p))
18944405Skarels 			return (ESRCH);
19043393Skarels 		if (p->p_session != cp->p_session)
19144405Skarels 			return (EPERM);
19243393Skarels 		if (p->p_flag&SEXEC)
19344405Skarels 			return (EACCES);
19443393Skarels 	} else
19543393Skarels 		p = cp;
19643393Skarels 	if (SESS_LEADER(p))
19744405Skarels 		return (EPERM);
19837579Smckusick 	if (uap->pgid == 0)
19937579Smckusick 		uap->pgid = p->p_pid;
20045908Sbostic 	else if (uap->pgid != p->p_pid)
20145908Sbostic 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
20245908Sbostic 		    pgrp->pg_mem == NULL ||
20345908Sbostic 	            pgrp->pg_session != cp->p_session)
20445908Sbostic 			return (EPERM);
20537579Smckusick 	pgmv(p, uap->pgid, 0);
20644405Skarels 	return (0);
2077498Sroot }
2087498Sroot 
20943393Skarels /* ARGSUSED */
21043393Skarels setuid(p, uap, retval)
21143393Skarels 	register struct proc *p;
21243393Skarels 	struct args {
21343393Skarels 		int	uid;
21443393Skarels 	} *uap;
21543393Skarels 	int *retval;
2167420Sroot {
21743393Skarels 	register uid_t uid;
21843393Skarels 	int error;
21943393Skarels 
22043393Skarels 	uid = uap->uid;
22143393Skarels 	if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
22244405Skarels 		return (error);
22343393Skarels 	/*
22445908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
22545908Sbostic 	 * not see our changes.
22643393Skarels 	 */
22745908Sbostic 	u.u_cred = crcopy(u.u_cred);
22843393Skarels 	u.u_cred->cr_uid = uid;
22943393Skarels 	p->p_uid = uid;
23043393Skarels 	p->p_ruid = uid;
23143393Skarels 	p->p_svuid = uid;
23244405Skarels 	return (0);
23343393Skarels }
23443393Skarels 
23543393Skarels /* ARGSUSED */
23643393Skarels seteuid(p, uap, retval)
23743393Skarels 	register struct proc *p;
23843393Skarels 	struct args {
23943393Skarels 		int	euid;
24043393Skarels 	} *uap;
24143393Skarels 	int *retval;
24243393Skarels {
24343393Skarels 	register uid_t euid;
24443393Skarels 	int error;
24543393Skarels 
24643393Skarels 	euid = uap->euid;
24743393Skarels 	if (euid != p->p_ruid && euid != p->p_svuid &&
24843393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
24944405Skarels 		return (error);
25043393Skarels 	/*
25145908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
25245908Sbostic 	 * not see our changes.
25343393Skarels 	 */
25445908Sbostic 	u.u_cred = crcopy(u.u_cred);
25543393Skarels 	u.u_cred->cr_uid = euid;
25643393Skarels 	p->p_uid = euid;
25744405Skarels 	return (0);
25843393Skarels }
25943393Skarels 
26043393Skarels /* ARGSUSED */
26143393Skarels setgid(p, uap, retval)
26243393Skarels 	struct proc *p;
26343393Skarels 	struct args {
26443393Skarels 		int	gid;
26543393Skarels 	} *uap;
26643393Skarels 	int *retval;
26743393Skarels {
26843393Skarels 	register gid_t gid;
26943393Skarels 	int error;
27043393Skarels 
27143393Skarels 	gid = uap->gid;
27243393Skarels 	if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
27344405Skarels 		return (error);
27445908Sbostic 	u.u_cred = crcopy(u.u_cred);
27543393Skarels 	p->p_rgid = gid;
27643393Skarels 	u.u_cred->cr_groups[0] = gid;
27743393Skarels 	p->p_svgid = gid;		/* ??? */
27844405Skarels 	return (0);
27943393Skarels }
28043393Skarels 
28143393Skarels /* ARGSUSED */
28243393Skarels setegid(p, uap, retval)
28343393Skarels 	struct proc *p;
28443393Skarels 	struct args {
28543393Skarels 		int	egid;
28643393Skarels 	} *uap;
28743393Skarels 	int *retval;
28843393Skarels {
28943393Skarels 	register gid_t egid;
29043393Skarels 	int error;
29143393Skarels 
29243393Skarels 	egid = uap->egid;
29343393Skarels 	if (egid != p->p_rgid && egid != p->p_svgid &&
29443393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
29544405Skarels 		return (error);
29645908Sbostic 	u.u_cred = crcopy(u.u_cred);
29743393Skarels 	u.u_cred->cr_groups[0] = egid;
29844405Skarels 	return (0);
29943393Skarels }
30043393Skarels 
30143393Skarels #ifdef COMPAT_43
30243393Skarels /* ARGSUSED */
30343393Skarels osetreuid(p, uap, retval)
30443393Skarels 	register struct proc *p;
30543393Skarels 	struct args {
3069160Ssam 		int	ruid;
3079160Ssam 		int	euid;
3089160Ssam 	} *uap;
30943393Skarels 	int *retval;
31043393Skarels {
31143393Skarels 	register uid_t ruid, euid;
31243393Skarels 	int error;
3139160Ssam 
31443393Skarels 	if (uap->ruid == -1)
31540667Skarels 		ruid = p->p_ruid;
31643393Skarels 	else
31743393Skarels 		ruid = uap->ruid;
31843393Skarels 	/*
31945908Sbostic 	 * Allow setting real uid to previous effective, for swapping real and
32045908Sbostic 	 * effective.  This should be:
32145908Sbostic 	 *
32245908Sbostic 	 * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
32343393Skarels 	 */
32445908Sbostic 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
32543393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
32644405Skarels 		return (error);
32743393Skarels 	if (uap->euid == -1)
32840667Skarels 		euid = u.u_cred->cr_uid;
32943393Skarels 	else
33043393Skarels 		euid = uap->euid;
33140667Skarels 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
33243393Skarels 	    euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag)))
33344405Skarels 		return (error);
3349160Ssam 	/*
33545908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
33645908Sbostic 	 * not see our changes.
3379160Ssam 	 */
33845908Sbostic 	u.u_cred = crcopy(u.u_cred);
33940667Skarels 	u.u_cred->cr_uid = euid;
34040667Skarels 	p->p_uid = euid;
34140667Skarels 	p->p_ruid = ruid;
34244405Skarels 	return (0);
3439160Ssam }
3449160Ssam 
34543393Skarels /* ARGSUSED */
34643393Skarels osetregid(p, uap, retval)
34743393Skarels 	struct proc *p;
34843393Skarels 	struct args {
3499160Ssam 		int	rgid;
3509160Ssam 		int	egid;
3519160Ssam 	} *uap;
35243393Skarels 	int *retval;
35343393Skarels {
35443393Skarels 	register gid_t rgid, egid;
35543393Skarels 	int error;
3569160Ssam 
35743393Skarels 	if (uap->rgid == -1)
35840667Skarels 		rgid = p->p_rgid;
35943393Skarels 	else
36043393Skarels 		rgid = uap->rgid;
36143393Skarels 	/*
36245908Sbostic 	 * Allow setting real gid to previous effective, for swapping real and
36345908Sbostic 	 * effective.  This didn't really work correctly in 4.[23], but is
36445908Sbostic 	 * preserved so old stuff doesn't fail.  This should be:
36545908Sbostic 	 *
36645908Sbostic 	 * if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
36743393Skarels 	 */
36840667Skarels 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
36943393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
37044405Skarels 		return (error);
37143393Skarels 	if (uap->egid == -1)
37240667Skarels 		egid = u.u_cred->cr_groups[0];
37343393Skarels 	else
37443393Skarels 		egid = uap->egid;
37545908Sbostic 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
37643393Skarels 	    egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag)))
37744405Skarels 		return (error);
37845908Sbostic 	u.u_cred = crcopy(u.u_cred);
37940667Skarels 	p->p_rgid = rgid;
38040667Skarels 	u.u_cred->cr_groups[0] = egid;
38144405Skarels 	return (0);
3829160Ssam }
38343393Skarels #endif
3849160Ssam 
38543393Skarels /* ARGSUSED */
38643393Skarels setgroups(p, uap, retval)
38743393Skarels 	struct proc *p;
38843393Skarels 	struct args {
3898624Sroot 		u_int	gidsetsize;
3907498Sroot 		int	*gidset;
39143393Skarels 	} *uap;
39243393Skarels 	int *retval;
39343393Skarels {
39418362Skarels 	register gid_t *gp;
39544994Skarels 	register u_int ngrp;
39618362Skarels 	register int *lp;
39744942Sbostic 	int error, groups[NGROUPS];
3987498Sroot 
39943393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
40044405Skarels 		return (error);
40144994Skarels 	if ((ngrp = uap->gidsetsize) > NGROUPS)
40244405Skarels 		return (EINVAL);
40344942Sbostic 	if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
40444994Skarels 	    ngrp * sizeof (groups[0])))
40544405Skarels 		return (error);
40645908Sbostic 	u.u_cred = crcopy(u.u_cred);
40744994Skarels 	u.u_cred->cr_ngroups = ngrp;
40844942Sbostic 	/* convert from int's to gid_t's */
40944994Skarels 	for (gp = u.u_cred->cr_groups, lp = groups; ngrp--; )
41044994Skarels 		*gp++ = *lp++;
41144405Skarels 	return (0);
4127498Sroot }
4137498Sroot 
4147498Sroot /*
41537578Smckusick  * Check if gid is a member of the group set.
41611810Ssam  */
41737578Smckusick groupmember(gid, cred)
41826275Skarels 	gid_t gid;
41937578Smckusick 	register struct ucred *cred;
4207866Sroot {
42118362Skarels 	register gid_t *gp;
42237578Smckusick 	gid_t *egp;
4237866Sroot 
42437578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
42537578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
4267866Sroot 		if (*gp == gid)
42737578Smckusick 			return (1);
42837578Smckusick 	return (0);
4297866Sroot }
4307866Sroot 
43111810Ssam /*
432*46293Skarels  * Test whether the specified credentials imply "super-user"
433*46293Skarels  * privilege; if so, and we have accounting info, set the flag
434*46293Skarels  * indicating use of super-powers.
435*46293Skarels  * Returns 0 or error.
43611810Ssam  */
43737578Smckusick suser(cred, acflag)
43837578Smckusick 	struct ucred *cred;
43937578Smckusick 	short *acflag;
4407866Sroot {
44137578Smckusick 	if (cred->cr_uid == 0) {
44237578Smckusick 		if (acflag)
44337578Smckusick 			*acflag |= ASU;
44437578Smckusick 		return (0);
44518362Skarels 	}
44637578Smckusick 	return (EPERM);
4477866Sroot }
44811810Ssam 
44911810Ssam /*
45037578Smckusick  * Allocate a zeroed cred structure.
45111810Ssam  */
45237578Smckusick struct ucred *
45337578Smckusick crget()
45411810Ssam {
45537578Smckusick 	register struct ucred *cr;
45611810Ssam 
45737578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
45837578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
45937578Smckusick 	cr->cr_ref = 1;
46043393Skarels 	return (cr);
46111810Ssam }
46237085Skfall 
46337085Skfall /*
46437578Smckusick  * Free a cred structure.
46537578Smckusick  * Throws away space when ref count gets to 0.
46637085Skfall  */
46737578Smckusick crfree(cr)
46837578Smckusick 	struct ucred *cr;
46937578Smckusick {
47043393Skarels 	int s = splimp();
47137085Skfall 
47237578Smckusick 	if (--cr->cr_ref != 0) {
47337578Smckusick 		(void) splx(s);
47437578Smckusick 		return;
47537578Smckusick 	}
47637578Smckusick 	FREE((caddr_t)cr, M_CRED);
47737578Smckusick 	(void) splx(s);
47837578Smckusick }
47937578Smckusick 
48037578Smckusick /*
48137578Smckusick  * Copy cred structure to a new one and free the old one.
48237578Smckusick  */
48337578Smckusick struct ucred *
48437578Smckusick crcopy(cr)
48537578Smckusick 	struct ucred *cr;
48637085Skfall {
48737578Smckusick 	struct ucred *newcr;
48837085Skfall 
48945908Sbostic 	if (cr->cr_ref == 1)
49045908Sbostic 		return (cr);
49137578Smckusick 	newcr = crget();
49237578Smckusick 	*newcr = *cr;
49337578Smckusick 	crfree(cr);
49437578Smckusick 	newcr->cr_ref = 1;
49543393Skarels 	return (newcr);
49637085Skfall }
49737085Skfall 
49837085Skfall /*
49937578Smckusick  * Dup cred struct to a new held one.
50037085Skfall  */
50137578Smckusick struct ucred *
50237578Smckusick crdup(cr)
50337578Smckusick 	struct ucred *cr;
50437085Skfall {
50537578Smckusick 	struct ucred *newcr;
50637085Skfall 
50737578Smckusick 	newcr = crget();
50837578Smckusick 	*newcr = *cr;
50937578Smckusick 	newcr->cr_ref = 1;
51043393Skarels 	return (newcr);
51137085Skfall }
51237579Smckusick 
51337579Smckusick /*
51440667Skarels  * Get login name, if available.
51537579Smckusick  */
51643393Skarels /* ARGSUSED */
51743393Skarels getlogin(p, uap, retval)
51843393Skarels 	struct proc *p;
51943393Skarels 	struct args {
52037579Smckusick 		char	*namebuf;
52137579Smckusick 		u_int	namelen;
52243393Skarels 	} *uap;
52343393Skarels 	int *retval;
52443393Skarels {
52537579Smckusick 
52643393Skarels 	if (uap->namelen > sizeof (p->p_logname))
52743393Skarels 		uap->namelen = sizeof (p->p_logname);
52844405Skarels 	return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf,
52943393Skarels 	    uap->namelen));
53037579Smckusick }
53137579Smckusick 
53237579Smckusick /*
53340667Skarels  * Set login name.
53437579Smckusick  */
53543393Skarels /* ARGSUSED */
53643393Skarels setlogin(p, uap, retval)
53743393Skarels 	struct proc *p;
53843393Skarels 	struct args {
53943393Skarels 		char	*namebuf;
54043393Skarels 	} *uap;
54143393Skarels 	int *retval;
54237579Smckusick {
54340667Skarels 	int error;
54437579Smckusick 
54543393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
54644405Skarels 		return (error);
54743393Skarels 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname,
54845908Sbostic 	    sizeof (p->p_logname) - 1, (u_int *)0);
54945356Smckusick 	if (error == ENAMETOOLONG)		/* name too long */
55040667Skarels 		error = EINVAL;
55144405Skarels 	return (error);
55237579Smckusick }
553