xref: /csrg-svn/sys/kern/kern_prot.c (revision 45908)
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*45908Sbostic  *	@(#)kern_prot.c	7.17 (Berkeley) 01/10/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 /*
102*45908Sbostic  * Get effective group ID.  The "egid" is groups[0], and could be obtained
103*45908Sbostic  * via getgroups.  This syscall exists because it is somewhat painful to do
104*45908Sbostic  * 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;
200*45908Sbostic 	else if (uap->pgid != p->p_pid)
201*45908Sbostic 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
202*45908Sbostic 		    pgrp->pg_mem == NULL ||
203*45908Sbostic 	            pgrp->pg_session != cp->p_session)
204*45908Sbostic 			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 	/*
224*45908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
225*45908Sbostic 	 * not see our changes.
22643393Skarels 	 */
227*45908Sbostic 	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 	/*
251*45908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
252*45908Sbostic 	 * not see our changes.
25343393Skarels 	 */
254*45908Sbostic 	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);
274*45908Sbostic 	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);
296*45908Sbostic 	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 	/*
319*45908Sbostic 	 * Allow setting real uid to previous effective, for swapping real and
320*45908Sbostic 	 * effective.  This should be:
321*45908Sbostic 	 *
322*45908Sbostic 	 * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
32343393Skarels 	 */
324*45908Sbostic 	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 	/*
335*45908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
336*45908Sbostic 	 * not see our changes.
3379160Ssam 	 */
338*45908Sbostic 	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 	/*
362*45908Sbostic 	 * Allow setting real gid to previous effective, for swapping real and
363*45908Sbostic 	 * effective.  This didn't really work correctly in 4.[23], but is
364*45908Sbostic 	 * preserved so old stuff doesn't fail.  This should be:
365*45908Sbostic 	 *
366*45908Sbostic 	 * 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;
375*45908Sbostic 	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);
378*45908Sbostic 	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);
406*45908Sbostic 	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 /*
43237578Smckusick  * Test if the current user is the super user.
43311810Ssam  */
43437578Smckusick suser(cred, acflag)
43537578Smckusick 	struct ucred *cred;
43637578Smckusick 	short *acflag;
4377866Sroot {
43837578Smckusick 	if (cred->cr_uid == 0) {
43937578Smckusick 		if (acflag)
44037578Smckusick 			*acflag |= ASU;
44137578Smckusick 		return (0);
44218362Skarels 	}
44337578Smckusick 	return (EPERM);
4447866Sroot }
44511810Ssam 
44611810Ssam /*
44737578Smckusick  * Allocate a zeroed cred structure.
44811810Ssam  */
44937578Smckusick struct ucred *
45037578Smckusick crget()
45111810Ssam {
45237578Smckusick 	register struct ucred *cr;
45311810Ssam 
45437578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
45537578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
45637578Smckusick 	cr->cr_ref = 1;
45743393Skarels 	return (cr);
45811810Ssam }
45937085Skfall 
46037085Skfall /*
46137578Smckusick  * Free a cred structure.
46237578Smckusick  * Throws away space when ref count gets to 0.
46337085Skfall  */
46437578Smckusick crfree(cr)
46537578Smckusick 	struct ucred *cr;
46637578Smckusick {
46743393Skarels 	int s = splimp();
46837085Skfall 
46937578Smckusick 	if (--cr->cr_ref != 0) {
47037578Smckusick 		(void) splx(s);
47137578Smckusick 		return;
47237578Smckusick 	}
47337578Smckusick 	FREE((caddr_t)cr, M_CRED);
47437578Smckusick 	(void) splx(s);
47537578Smckusick }
47637578Smckusick 
47737578Smckusick /*
47837578Smckusick  * Copy cred structure to a new one and free the old one.
47937578Smckusick  */
48037578Smckusick struct ucred *
48137578Smckusick crcopy(cr)
48237578Smckusick 	struct ucred *cr;
48337085Skfall {
48437578Smckusick 	struct ucred *newcr;
48537085Skfall 
486*45908Sbostic 	if (cr->cr_ref == 1)
487*45908Sbostic 		return (cr);
48837578Smckusick 	newcr = crget();
48937578Smckusick 	*newcr = *cr;
49037578Smckusick 	crfree(cr);
49137578Smckusick 	newcr->cr_ref = 1;
49243393Skarels 	return (newcr);
49337085Skfall }
49437085Skfall 
49537085Skfall /*
49637578Smckusick  * Dup cred struct to a new held one.
49737085Skfall  */
49837578Smckusick struct ucred *
49937578Smckusick crdup(cr)
50037578Smckusick 	struct ucred *cr;
50137085Skfall {
50237578Smckusick 	struct ucred *newcr;
50337085Skfall 
50437578Smckusick 	newcr = crget();
50537578Smckusick 	*newcr = *cr;
50637578Smckusick 	newcr->cr_ref = 1;
50743393Skarels 	return (newcr);
50837085Skfall }
50937579Smckusick 
51037579Smckusick /*
51140667Skarels  * Get login name, if available.
51237579Smckusick  */
51343393Skarels /* ARGSUSED */
51443393Skarels getlogin(p, uap, retval)
51543393Skarels 	struct proc *p;
51643393Skarels 	struct args {
51737579Smckusick 		char	*namebuf;
51837579Smckusick 		u_int	namelen;
51943393Skarels 	} *uap;
52043393Skarels 	int *retval;
52143393Skarels {
52237579Smckusick 
52343393Skarels 	if (uap->namelen > sizeof (p->p_logname))
52443393Skarels 		uap->namelen = sizeof (p->p_logname);
52544405Skarels 	return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf,
52643393Skarels 	    uap->namelen));
52737579Smckusick }
52837579Smckusick 
52937579Smckusick /*
53040667Skarels  * Set login name.
53137579Smckusick  */
53243393Skarels /* ARGSUSED */
53343393Skarels setlogin(p, uap, retval)
53443393Skarels 	struct proc *p;
53543393Skarels 	struct args {
53643393Skarels 		char	*namebuf;
53743393Skarels 	} *uap;
53843393Skarels 	int *retval;
53937579Smckusick {
54040667Skarels 	int error;
54137579Smckusick 
54243393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
54344405Skarels 		return (error);
54443393Skarels 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname,
545*45908Sbostic 	    sizeof (p->p_logname) - 1, (u_int *)0);
54645356Smckusick 	if (error == ENAMETOOLONG)		/* name too long */
54740667Skarels 		error = EINVAL;
54844405Skarels 	return (error);
54937579Smckusick }
550