xref: /csrg-svn/sys/kern/kern_prot.c (revision 54925)
123372Smckusick /*
247540Skarels  * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University
347540Skarels  * of California.  All rights reserved.
423372Smckusick  *
544439Sbostic  * %sccs.include.redist.c%
637578Smckusick  *
7*54925Storek  *	@(#)kern_prot.c	7.25 (Berkeley) 07/10/92
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"
1747540Skarels #include "ucred.h"
1817092Sbloom #include "proc.h"
1917092Sbloom #include "timeb.h"
2017092Sbloom #include "times.h"
2137578Smckusick #include "malloc.h"
227420Sroot 
23*54925Storek struct args {
24*54925Storek 	int	dummy;
25*54925Storek };
26*54925Storek 
2743393Skarels /* ARGSUSED */
2843393Skarels getpid(p, uap, retval)
2943393Skarels 	struct proc *p;
30*54925Storek 	struct args *uap;
3143393Skarels 	int *retval;
3243393Skarels {
3337579Smckusick 
3443393Skarels 	*retval = p->p_pid;
3552495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
3647540Skarels 	retval[1] = p->p_pptr->p_pid;
3743393Skarels #endif
3844405Skarels 	return (0);
3943393Skarels }
4043393Skarels 
4143393Skarels /* ARGSUSED */
4243393Skarels getppid(p, uap, retval)
4343393Skarels 	struct proc *p;
44*54925Storek 	struct args *uap;
4543393Skarels 	int *retval;
467498Sroot {
477498Sroot 
4847540Skarels 	*retval = p->p_pptr->p_pid;
4944405Skarels 	return (0);
507498Sroot }
517498Sroot 
5247540Skarels /* Get process group ID; note that POSIX getpgrp takes no parameter */
5343393Skarels getpgrp(p, uap, retval)
5443393Skarels 	struct proc *p;
55*54925Storek 	struct args *uap;
5643393Skarels 	int *retval;
577498Sroot {
587498Sroot 
5943393Skarels 	*retval = p->p_pgrp->pg_id;
6044405Skarels 	return (0);
617498Sroot }
627498Sroot 
6343393Skarels /* ARGSUSED */
6443393Skarels getuid(p, uap, retval)
6543393Skarels 	struct proc *p;
66*54925Storek 	struct args *uap;
6743393Skarels 	int *retval;
687420Sroot {
697420Sroot 
7047540Skarels 	*retval = p->p_cred->p_ruid;
7152495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
7247540Skarels 	retval[1] = p->p_ucred->cr_uid;
7343393Skarels #endif
7444405Skarels 	return (0);
757420Sroot }
767420Sroot 
7743393Skarels /* ARGSUSED */
7843393Skarels geteuid(p, uap, retval)
7943393Skarels 	struct proc *p;
80*54925Storek 	struct args *uap;
8143393Skarels 	int *retval;
827498Sroot {
837498Sroot 
8447540Skarels 	*retval = p->p_ucred->cr_uid;
8544405Skarels 	return (0);
867498Sroot }
877498Sroot 
8843393Skarels /* ARGSUSED */
8943393Skarels getgid(p, uap, retval)
9043393Skarels 	struct proc *p;
91*54925Storek 	struct args *uap;
9243393Skarels 	int *retval;
937498Sroot {
9443393Skarels 
9547540Skarels 	*retval = p->p_cred->p_rgid;
9652495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9747540Skarels 	retval[1] = p->p_ucred->cr_groups[0];
9843393Skarels #endif
9944405Skarels 	return (0);
10043393Skarels }
10143393Skarels 
10243393Skarels /*
10345908Sbostic  * Get effective group ID.  The "egid" is groups[0], and could be obtained
10445908Sbostic  * via getgroups.  This syscall exists because it is somewhat painful to do
10545908Sbostic  * correctly in a library function.
10643393Skarels  */
10743393Skarels /* ARGSUSED */
10843393Skarels getegid(p, uap, retval)
10943393Skarels 	struct proc *p;
110*54925Storek 	struct args *uap;
11143393Skarels 	int *retval;
11243393Skarels {
11347540Skarels 
11447540Skarels 	*retval = p->p_ucred->cr_groups[0];
11544405Skarels 	return (0);
11643393Skarels }
11743393Skarels 
118*54925Storek struct getgroups_args {
119*54925Storek 	u_int	gidsetsize;
120*54925Storek 	int	*gidset;		/* XXX not yet POSIX */
121*54925Storek };
12243393Skarels getgroups(p, uap, retval)
12343393Skarels 	struct proc *p;
124*54925Storek 	register struct	getgroups_args *uap;
12543393Skarels 	int *retval;
12643393Skarels {
12747540Skarels 	register struct pcred *pc = p->p_cred;
12818362Skarels 	register gid_t *gp;
12918362Skarels 	register int *lp;
13044994Skarels 	register u_int ngrp;
13118362Skarels 	int groups[NGROUPS];
13243393Skarels 	int error;
1337498Sroot 
13444994Skarels 	if ((ngrp = uap->gidsetsize) == 0) {
13547540Skarels 		*retval = pc->pc_ucred->cr_ngroups;
13644405Skarels 		return (0);
13737578Smckusick 	}
13847540Skarels 	if (ngrp < pc->pc_ucred->cr_ngroups)
13944405Skarels 		return (EINVAL);
14047540Skarels 	ngrp = pc->pc_ucred->cr_ngroups;
14147540Skarels 	for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; )
14218362Skarels 		*lp++ = *gp++;
14343393Skarels 	if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
14444994Skarels 	    ngrp * sizeof (groups[0])))
14544405Skarels 		return (error);
14644994Skarels 	*retval = ngrp;
14744405Skarels 	return (0);
1487498Sroot }
1497498Sroot 
15043393Skarels /* ARGSUSED */
15143393Skarels setsid(p, uap, retval)
15247540Skarels 	register struct proc *p;
153*54925Storek 	struct args *uap;
15443393Skarels 	int *retval;
15537579Smckusick {
15637579Smckusick 
15743393Skarels 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
15844405Skarels 		return (EPERM);
15943393Skarels 	} else {
16047540Skarels 		enterpgrp(p, p->p_pid, 1);
16143393Skarels 		*retval = p->p_pid;
16244405Skarels 		return (0);
16337579Smckusick 	}
16437579Smckusick }
16537579Smckusick 
16637579Smckusick /*
16747540Skarels  * set process group (setpgid/old setpgrp)
16837579Smckusick  *
16947972Smarc  * caller does setpgid(targpid, targpgid)
17040667Skarels  *
17140667Skarels  * pid must be caller or child of caller (ESRCH)
17240667Skarels  * if a child
17340667Skarels  *	pid must be in same session (EPERM)
17440667Skarels  *	pid can't have done an exec (EACCES)
17540667Skarels  * if pgid != pid
17640667Skarels  * 	there must exist some pid in same session having pgid (EPERM)
17740667Skarels  * pid must not be session leader (EPERM)
17837579Smckusick  */
179*54925Storek struct setpgid_args {
180*54925Storek 	int	pid;	/* target process id */
181*54925Storek 	int	pgid;	/* target pgrp id */
182*54925Storek };
18343393Skarels /* ARGSUSED */
18447972Smarc setpgid(curp, uap, retval)
18547972Smarc 	struct proc *curp;
186*54925Storek 	register struct setpgid_args *uap;
18743393Skarels 	int *retval;
18843393Skarels {
18947972Smarc 	register struct proc *targp;		/* target process */
19048990Skarels 	register struct pgrp *pgrp;		/* target pgrp */
1917498Sroot 
19248990Skarels 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
19348990Skarels 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
19444405Skarels 			return (ESRCH);
19547972Smarc 		if (targp->p_session != curp->p_session)
19644405Skarels 			return (EPERM);
19747972Smarc 		if (targp->p_flag&SEXEC)
19844405Skarels 			return (EACCES);
19943393Skarels 	} else
20047972Smarc 		targp = curp;
20147972Smarc 	if (SESS_LEADER(targp))
20244405Skarels 		return (EPERM);
20348990Skarels 	if (uap->pgid == 0)
20448990Skarels 		uap->pgid = targp->p_pid;
20548990Skarels 	else if (uap->pgid != targp->p_pid)
20648990Skarels 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
20748990Skarels 	            pgrp->pg_session != curp->p_session)
20845908Sbostic 			return (EPERM);
20948990Skarels 	enterpgrp(targp, uap->pgid, 0);
21044405Skarels 	return (0);
2117498Sroot }
2127498Sroot 
213*54925Storek struct setuid_args {
214*54925Storek 	int	uid;
215*54925Storek };
21643393Skarels /* ARGSUSED */
21743393Skarels setuid(p, uap, retval)
21847540Skarels 	struct proc *p;
219*54925Storek 	struct setuid_args *uap;
22043393Skarels 	int *retval;
2217420Sroot {
22247540Skarels 	register struct pcred *pc = p->p_cred;
22343393Skarels 	register uid_t uid;
22443393Skarels 	int error;
22543393Skarels 
22643393Skarels 	uid = uap->uid;
22747540Skarels 	if (uid != pc->p_ruid &&
22847540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
22944405Skarels 		return (error);
23043393Skarels 	/*
23145908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
23245908Sbostic 	 * not see our changes.
23343393Skarels 	 */
23447540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
23547540Skarels 	pc->pc_ucred->cr_uid = uid;
23647540Skarels 	pc->p_ruid = uid;
23747540Skarels 	pc->p_svuid = uid;
23854339Smckusick 	p->p_flag |= SUGID;
23944405Skarels 	return (0);
24043393Skarels }
24143393Skarels 
242*54925Storek struct seteuid_args {
243*54925Storek 	int	euid;
244*54925Storek };
24543393Skarels /* ARGSUSED */
24643393Skarels seteuid(p, uap, retval)
24747540Skarels 	struct proc *p;
248*54925Storek 	struct seteuid_args *uap;
24943393Skarels 	int *retval;
25043393Skarels {
25147540Skarels 	register struct pcred *pc = p->p_cred;
25243393Skarels 	register uid_t euid;
25343393Skarels 	int error;
25443393Skarels 
25543393Skarels 	euid = uap->euid;
25647540Skarels 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
25747540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
25844405Skarels 		return (error);
25943393Skarels 	/*
26045908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
26145908Sbostic 	 * not see our changes.
26243393Skarels 	 */
26347540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
26447540Skarels 	pc->pc_ucred->cr_uid = euid;
26554339Smckusick 	p->p_flag |= SUGID;
26644405Skarels 	return (0);
26743393Skarels }
26843393Skarels 
269*54925Storek struct setgid_args {
270*54925Storek 	int	gid;
271*54925Storek };
27243393Skarels /* ARGSUSED */
27343393Skarels setgid(p, uap, retval)
27443393Skarels 	struct proc *p;
275*54925Storek 	struct setgid_args *uap;
27643393Skarels 	int *retval;
27743393Skarels {
27847540Skarels 	register struct pcred *pc = p->p_cred;
27943393Skarels 	register gid_t gid;
28043393Skarels 	int error;
28143393Skarels 
28243393Skarels 	gid = uap->gid;
28347540Skarels 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
28444405Skarels 		return (error);
28547540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
28647540Skarels 	pc->pc_ucred->cr_groups[0] = gid;
28747540Skarels 	pc->p_rgid = gid;
28847540Skarels 	pc->p_svgid = gid;		/* ??? */
28954339Smckusick 	p->p_flag |= SUGID;
29044405Skarels 	return (0);
29143393Skarels }
29243393Skarels 
293*54925Storek struct setegid_args {
294*54925Storek 	int	egid;
295*54925Storek };
29643393Skarels /* ARGSUSED */
29743393Skarels setegid(p, uap, retval)
29843393Skarels 	struct proc *p;
299*54925Storek 	struct setegid_args *uap;
30043393Skarels 	int *retval;
30143393Skarels {
30247540Skarels 	register struct pcred *pc = p->p_cred;
30343393Skarels 	register gid_t egid;
30443393Skarels 	int error;
30543393Skarels 
30643393Skarels 	egid = uap->egid;
30747540Skarels 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
30847540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
30944405Skarels 		return (error);
31047540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
31147540Skarels 	pc->pc_ucred->cr_groups[0] = egid;
31254339Smckusick 	p->p_flag |= SUGID;
31344405Skarels 	return (0);
31443393Skarels }
31543393Skarels 
316*54925Storek struct setgroups_args {
317*54925Storek 	u_int	gidsetsize;
318*54925Storek 	int	*gidset;
319*54925Storek };
32043393Skarels /* ARGSUSED */
32143393Skarels setgroups(p, uap, retval)
32243393Skarels 	struct proc *p;
323*54925Storek 	struct setgroups_args *uap;
32443393Skarels 	int *retval;
32543393Skarels {
32647540Skarels 	register struct pcred *pc = p->p_cred;
32718362Skarels 	register gid_t *gp;
32844994Skarels 	register u_int ngrp;
32918362Skarels 	register int *lp;
33044942Sbostic 	int error, groups[NGROUPS];
3317498Sroot 
33247540Skarels 	if (error = suser(pc->pc_ucred, &p->p_acflag))
33344405Skarels 		return (error);
33444994Skarels 	if ((ngrp = uap->gidsetsize) > NGROUPS)
33544405Skarels 		return (EINVAL);
33644942Sbostic 	if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
33744994Skarels 	    ngrp * sizeof (groups[0])))
33844405Skarels 		return (error);
33947540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
34047540Skarels 	pc->pc_ucred->cr_ngroups = ngrp;
34144942Sbostic 	/* convert from int's to gid_t's */
34247540Skarels 	for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; )
34344994Skarels 		*gp++ = *lp++;
34454339Smckusick 	p->p_flag |= SUGID;
34544405Skarels 	return (0);
3467498Sroot }
3477498Sroot 
3487498Sroot /*
34937578Smckusick  * Check if gid is a member of the group set.
35011810Ssam  */
35137578Smckusick groupmember(gid, cred)
35226275Skarels 	gid_t gid;
35337578Smckusick 	register struct ucred *cred;
3547866Sroot {
35518362Skarels 	register gid_t *gp;
35637578Smckusick 	gid_t *egp;
3577866Sroot 
35837578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
35937578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
3607866Sroot 		if (*gp == gid)
36137578Smckusick 			return (1);
36237578Smckusick 	return (0);
3637866Sroot }
3647866Sroot 
36511810Ssam /*
36646293Skarels  * Test whether the specified credentials imply "super-user"
36746293Skarels  * privilege; if so, and we have accounting info, set the flag
36846293Skarels  * indicating use of super-powers.
36946293Skarels  * Returns 0 or error.
37011810Ssam  */
37137578Smckusick suser(cred, acflag)
37237578Smckusick 	struct ucred *cred;
37337578Smckusick 	short *acflag;
3747866Sroot {
37537578Smckusick 	if (cred->cr_uid == 0) {
37637578Smckusick 		if (acflag)
37737578Smckusick 			*acflag |= ASU;
37837578Smckusick 		return (0);
37918362Skarels 	}
38037578Smckusick 	return (EPERM);
3817866Sroot }
38211810Ssam 
38311810Ssam /*
38437578Smckusick  * Allocate a zeroed cred structure.
38511810Ssam  */
38637578Smckusick struct ucred *
38737578Smckusick crget()
38811810Ssam {
38937578Smckusick 	register struct ucred *cr;
39011810Ssam 
39137578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
39237578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
39337578Smckusick 	cr->cr_ref = 1;
39443393Skarels 	return (cr);
39511810Ssam }
39637085Skfall 
39737085Skfall /*
39837578Smckusick  * Free a cred structure.
39937578Smckusick  * Throws away space when ref count gets to 0.
40037085Skfall  */
40137578Smckusick crfree(cr)
40237578Smckusick 	struct ucred *cr;
40337578Smckusick {
40447540Skarels 	int s = splimp();			/* ??? */
40537085Skfall 
40637578Smckusick 	if (--cr->cr_ref != 0) {
40737578Smckusick 		(void) splx(s);
40837578Smckusick 		return;
40937578Smckusick 	}
41037578Smckusick 	FREE((caddr_t)cr, M_CRED);
41137578Smckusick 	(void) splx(s);
41237578Smckusick }
41337578Smckusick 
41437578Smckusick /*
41537578Smckusick  * Copy cred structure to a new one and free the old one.
41637578Smckusick  */
41737578Smckusick struct ucred *
41837578Smckusick crcopy(cr)
41937578Smckusick 	struct ucred *cr;
42037085Skfall {
42137578Smckusick 	struct ucred *newcr;
42237085Skfall 
42345908Sbostic 	if (cr->cr_ref == 1)
42445908Sbostic 		return (cr);
42537578Smckusick 	newcr = crget();
42637578Smckusick 	*newcr = *cr;
42737578Smckusick 	crfree(cr);
42837578Smckusick 	newcr->cr_ref = 1;
42943393Skarels 	return (newcr);
43037085Skfall }
43137085Skfall 
43237085Skfall /*
43337578Smckusick  * Dup cred struct to a new held one.
43437085Skfall  */
43537578Smckusick struct ucred *
43637578Smckusick crdup(cr)
43737578Smckusick 	struct ucred *cr;
43837085Skfall {
43937578Smckusick 	struct ucred *newcr;
44037085Skfall 
44137578Smckusick 	newcr = crget();
44237578Smckusick 	*newcr = *cr;
44337578Smckusick 	newcr->cr_ref = 1;
44443393Skarels 	return (newcr);
44537085Skfall }
44637579Smckusick 
44737579Smckusick /*
44840667Skarels  * Get login name, if available.
44937579Smckusick  */
450*54925Storek struct getlogin_args {
451*54925Storek 	char	*namebuf;
452*54925Storek 	u_int	namelen;
453*54925Storek };
45443393Skarels /* ARGSUSED */
45543393Skarels getlogin(p, uap, retval)
45643393Skarels 	struct proc *p;
457*54925Storek 	struct getlogin_args *uap;
45843393Skarels 	int *retval;
45943393Skarels {
46037579Smckusick 
46147540Skarels 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
46247540Skarels 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
46347540Skarels 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
46447540Skarels 	    (caddr_t) uap->namebuf, uap->namelen));
46537579Smckusick }
46637579Smckusick 
46737579Smckusick /*
46840667Skarels  * Set login name.
46937579Smckusick  */
470*54925Storek struct setlogin_args {
471*54925Storek 	char	*namebuf;
472*54925Storek };
47343393Skarels /* ARGSUSED */
47443393Skarels setlogin(p, uap, retval)
47543393Skarels 	struct proc *p;
476*54925Storek 	struct setlogin_args *uap;
47743393Skarels 	int *retval;
47837579Smckusick {
47940667Skarels 	int error;
48037579Smckusick 
48147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48244405Skarels 		return (error);
48347540Skarels 	error = copyinstr((caddr_t) uap->namebuf,
48447540Skarels 	    (caddr_t) p->p_pgrp->pg_session->s_login,
48547540Skarels 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
48647540Skarels 	if (error == ENAMETOOLONG)
48740667Skarels 		error = EINVAL;
48844405Skarels 	return (error);
48937579Smckusick }
490