xref: /csrg-svn/sys/kern/kern_prot.c (revision 65771)
123372Smckusick /*
263182Sbostic  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
363182Sbostic  *	Regents of the University of California.  All rights reserved.
4*65771Sbostic  * (c) UNIX System Laboratories, Inc.
5*65771Sbostic  * All or some portions of this file are derived from material licensed
6*65771Sbostic  * to the University of California by American Telephone and Telegraph
7*65771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*65771Sbostic  * the permission of UNIX System Laboratories, Inc.
923372Smckusick  *
1044439Sbostic  * %sccs.include.redist.c%
1137578Smckusick  *
12*65771Sbostic  *	@(#)kern_prot.c	8.5 (Berkeley) 01/21/94
1323372Smckusick  */
147420Sroot 
157420Sroot /*
167498Sroot  * System calls related to processes and protection
177420Sroot  */
187420Sroot 
1957048Smckusick #include <sys/param.h>
2057048Smckusick #include <sys/acct.h>
2157048Smckusick #include <sys/systm.h>
2257048Smckusick #include <sys/ucred.h>
2357048Smckusick #include <sys/proc.h>
2457048Smckusick #include <sys/timeb.h>
2557048Smckusick #include <sys/times.h>
2657048Smckusick #include <sys/malloc.h>
277420Sroot 
2854925Storek struct args {
2954925Storek 	int	dummy;
3054925Storek };
3154925Storek 
3243393Skarels /* ARGSUSED */
3343393Skarels getpid(p, uap, retval)
3443393Skarels 	struct proc *p;
3554925Storek 	struct args *uap;
3643393Skarels 	int *retval;
3743393Skarels {
3837579Smckusick 
3943393Skarels 	*retval = p->p_pid;
4052495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
4147540Skarels 	retval[1] = p->p_pptr->p_pid;
4243393Skarels #endif
4344405Skarels 	return (0);
4443393Skarels }
4543393Skarels 
4643393Skarels /* ARGSUSED */
4743393Skarels getppid(p, uap, retval)
4843393Skarels 	struct proc *p;
4954925Storek 	struct args *uap;
5043393Skarels 	int *retval;
517498Sroot {
527498Sroot 
5347540Skarels 	*retval = p->p_pptr->p_pid;
5444405Skarels 	return (0);
557498Sroot }
567498Sroot 
5747540Skarels /* Get process group ID; note that POSIX getpgrp takes no parameter */
5843393Skarels getpgrp(p, uap, retval)
5943393Skarels 	struct proc *p;
6054925Storek 	struct args *uap;
6143393Skarels 	int *retval;
627498Sroot {
637498Sroot 
6443393Skarels 	*retval = p->p_pgrp->pg_id;
6544405Skarels 	return (0);
667498Sroot }
677498Sroot 
6843393Skarels /* ARGSUSED */
6943393Skarels getuid(p, uap, retval)
7043393Skarels 	struct proc *p;
7154925Storek 	struct args *uap;
7243393Skarels 	int *retval;
737420Sroot {
747420Sroot 
7547540Skarels 	*retval = p->p_cred->p_ruid;
7652495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
7747540Skarels 	retval[1] = p->p_ucred->cr_uid;
7843393Skarels #endif
7944405Skarels 	return (0);
807420Sroot }
817420Sroot 
8243393Skarels /* ARGSUSED */
8343393Skarels geteuid(p, uap, retval)
8443393Skarels 	struct proc *p;
8554925Storek 	struct args *uap;
8643393Skarels 	int *retval;
877498Sroot {
887498Sroot 
8947540Skarels 	*retval = p->p_ucred->cr_uid;
9044405Skarels 	return (0);
917498Sroot }
927498Sroot 
9343393Skarels /* ARGSUSED */
9443393Skarels getgid(p, uap, retval)
9543393Skarels 	struct proc *p;
9654925Storek 	struct args *uap;
9743393Skarels 	int *retval;
987498Sroot {
9943393Skarels 
10047540Skarels 	*retval = p->p_cred->p_rgid;
10152495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10247540Skarels 	retval[1] = p->p_ucred->cr_groups[0];
10343393Skarels #endif
10444405Skarels 	return (0);
10543393Skarels }
10643393Skarels 
10743393Skarels /*
10845908Sbostic  * Get effective group ID.  The "egid" is groups[0], and could be obtained
10945908Sbostic  * via getgroups.  This syscall exists because it is somewhat painful to do
11045908Sbostic  * correctly in a library function.
11143393Skarels  */
11243393Skarels /* ARGSUSED */
11343393Skarels getegid(p, uap, retval)
11443393Skarels 	struct proc *p;
11554925Storek 	struct args *uap;
11643393Skarels 	int *retval;
11743393Skarels {
11847540Skarels 
11947540Skarels 	*retval = p->p_ucred->cr_groups[0];
12044405Skarels 	return (0);
12143393Skarels }
12243393Skarels 
12354925Storek struct getgroups_args {
12454925Storek 	u_int	gidsetsize;
12555162Smckusick 	gid_t	*gidset;
12654925Storek };
12743393Skarels getgroups(p, uap, retval)
12843393Skarels 	struct proc *p;
12954925Storek 	register struct	getgroups_args *uap;
13043393Skarels 	int *retval;
13143393Skarels {
13247540Skarels 	register struct pcred *pc = p->p_cred;
13344994Skarels 	register u_int ngrp;
13443393Skarels 	int error;
1357498Sroot 
13644994Skarels 	if ((ngrp = uap->gidsetsize) == 0) {
13747540Skarels 		*retval = pc->pc_ucred->cr_ngroups;
13844405Skarels 		return (0);
13937578Smckusick 	}
14047540Skarels 	if (ngrp < pc->pc_ucred->cr_ngroups)
14144405Skarels 		return (EINVAL);
14247540Skarels 	ngrp = pc->pc_ucred->cr_ngroups;
14355162Smckusick 	if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
14455162Smckusick 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))
14544405Skarels 		return (error);
14644994Skarels 	*retval = ngrp;
14744405Skarels 	return (0);
1487498Sroot }
1497498Sroot 
15043393Skarels /* ARGSUSED */
15143393Skarels setsid(p, uap, retval)
15247540Skarels 	register struct proc *p;
15354925Storek 	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 {
16057049Smarc 		(void)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  */
17954925Storek struct setpgid_args {
18054925Storek 	int	pid;	/* target process id */
18154925Storek 	int	pgid;	/* target pgrp id */
18254925Storek };
18343393Skarels /* ARGSUSED */
18447972Smarc setpgid(curp, uap, retval)
18547972Smarc 	struct proc *curp;
18654925Storek 	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);
19764586Sbostic 		if (targp->p_flag & P_EXEC)
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);
20957049Smarc 	return (enterpgrp(targp, uap->pgid, 0));
2107498Sroot }
2117498Sroot 
21254925Storek struct setuid_args {
21355162Smckusick 	uid_t	uid;
21454925Storek };
21543393Skarels /* ARGSUSED */
21643393Skarels setuid(p, uap, retval)
21747540Skarels 	struct proc *p;
21854925Storek 	struct setuid_args *uap;
21943393Skarels 	int *retval;
2207420Sroot {
22147540Skarels 	register struct pcred *pc = p->p_cred;
22243393Skarels 	register uid_t uid;
22343393Skarels 	int error;
22443393Skarels 
22543393Skarels 	uid = uap->uid;
22647540Skarels 	if (uid != pc->p_ruid &&
22747540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
22844405Skarels 		return (error);
22943393Skarels 	/*
23055403Smckusick 	 * Everything's okay, do it.
23155403Smckusick 	 * Transfer proc count to new user.
23255403Smckusick 	 * Copy credentials so other references do not see our changes.
23343393Skarels 	 */
23455403Smckusick 	(void)chgproccnt(pc->p_ruid, -1);
23555403Smckusick 	(void)chgproccnt(uid, 1);
23647540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
23747540Skarels 	pc->pc_ucred->cr_uid = uid;
23847540Skarels 	pc->p_ruid = uid;
23947540Skarels 	pc->p_svuid = uid;
24064586Sbostic 	p->p_flag |= P_SUGID;
24144405Skarels 	return (0);
24243393Skarels }
24343393Skarels 
24454925Storek struct seteuid_args {
24555162Smckusick 	uid_t	euid;
24654925Storek };
24743393Skarels /* ARGSUSED */
24843393Skarels seteuid(p, uap, retval)
24947540Skarels 	struct proc *p;
25054925Storek 	struct seteuid_args *uap;
25143393Skarels 	int *retval;
25243393Skarels {
25347540Skarels 	register struct pcred *pc = p->p_cred;
25443393Skarels 	register uid_t euid;
25543393Skarels 	int error;
25643393Skarels 
25743393Skarels 	euid = uap->euid;
25847540Skarels 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
25947540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
26044405Skarels 		return (error);
26143393Skarels 	/*
26245908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
26345908Sbostic 	 * not see our changes.
26443393Skarels 	 */
26547540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
26647540Skarels 	pc->pc_ucred->cr_uid = euid;
26764586Sbostic 	p->p_flag |= P_SUGID;
26844405Skarels 	return (0);
26943393Skarels }
27043393Skarels 
27154925Storek struct setgid_args {
27255162Smckusick 	gid_t	gid;
27354925Storek };
27443393Skarels /* ARGSUSED */
27543393Skarels setgid(p, uap, retval)
27643393Skarels 	struct proc *p;
27754925Storek 	struct setgid_args *uap;
27843393Skarels 	int *retval;
27943393Skarels {
28047540Skarels 	register struct pcred *pc = p->p_cred;
28143393Skarels 	register gid_t gid;
28243393Skarels 	int error;
28343393Skarels 
28443393Skarels 	gid = uap->gid;
28547540Skarels 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
28644405Skarels 		return (error);
28747540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
28847540Skarels 	pc->pc_ucred->cr_groups[0] = gid;
28947540Skarels 	pc->p_rgid = gid;
29047540Skarels 	pc->p_svgid = gid;		/* ??? */
29164586Sbostic 	p->p_flag |= P_SUGID;
29244405Skarels 	return (0);
29343393Skarels }
29443393Skarels 
29554925Storek struct setegid_args {
29655162Smckusick 	gid_t	egid;
29754925Storek };
29843393Skarels /* ARGSUSED */
29943393Skarels setegid(p, uap, retval)
30043393Skarels 	struct proc *p;
30154925Storek 	struct setegid_args *uap;
30243393Skarels 	int *retval;
30343393Skarels {
30447540Skarels 	register struct pcred *pc = p->p_cred;
30543393Skarels 	register gid_t egid;
30643393Skarels 	int error;
30743393Skarels 
30843393Skarels 	egid = uap->egid;
30947540Skarels 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
31047540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
31144405Skarels 		return (error);
31247540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
31347540Skarels 	pc->pc_ucred->cr_groups[0] = egid;
31464586Sbostic 	p->p_flag |= P_SUGID;
31544405Skarels 	return (0);
31643393Skarels }
31743393Skarels 
31854925Storek struct setgroups_args {
31954925Storek 	u_int	gidsetsize;
32055162Smckusick 	gid_t	*gidset;
32154925Storek };
32243393Skarels /* ARGSUSED */
32343393Skarels setgroups(p, uap, retval)
32443393Skarels 	struct proc *p;
32554925Storek 	struct setgroups_args *uap;
32643393Skarels 	int *retval;
32743393Skarels {
32847540Skarels 	register struct pcred *pc = p->p_cred;
32944994Skarels 	register u_int ngrp;
33055162Smckusick 	int error;
3317498Sroot 
33247540Skarels 	if (error = suser(pc->pc_ucred, &p->p_acflag))
33344405Skarels 		return (error);
33444994Skarels 	if ((ngrp = uap->gidsetsize) > NGROUPS)
33544405Skarels 		return (EINVAL);
33655162Smckusick 	pc->pc_ucred = crcopy(pc->pc_ucred);
33755162Smckusick 	if (error = copyin((caddr_t)uap->gidset,
33855162Smckusick 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
33944405Skarels 		return (error);
34047540Skarels 	pc->pc_ucred->cr_ngroups = ngrp;
34164586Sbostic 	p->p_flag |= P_SUGID;
34244405Skarels 	return (0);
3437498Sroot }
3447498Sroot 
34555163Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
34655163Smckusick struct setreuid_args {
34755163Smckusick 	int	ruid;
34855163Smckusick 	int	euid;
34955163Smckusick };
35055163Smckusick /* ARGSUSED */
35155163Smckusick osetreuid(p, uap, retval)
35255163Smckusick 	register struct proc *p;
35355163Smckusick 	struct setreuid_args *uap;
35455163Smckusick 	int *retval;
35555163Smckusick {
35655163Smckusick 	register struct pcred *pc = p->p_cred;
35755163Smckusick 	struct seteuid_args args;
35855163Smckusick 
35955163Smckusick 	/*
36055163Smckusick 	 * we assume that the intent of setting ruid is to be able to get
36155163Smckusick 	 * back ruid priviledge. So we make sure that we will be able to
36255163Smckusick 	 * do so, but do not actually set the ruid.
36355163Smckusick 	 */
36465512Smckusick 	if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid &&
36555163Smckusick 	    uap->ruid != pc->p_svuid)
36655163Smckusick 		return (EPERM);
36765512Smckusick 	if (uap->euid == (uid_t)-1)
36855163Smckusick 		return (0);
36955163Smckusick 	args.euid = uap->euid;
37055163Smckusick 	return (seteuid(p, &args, retval));
37155163Smckusick }
37255163Smckusick 
37355163Smckusick struct setregid_args {
37455163Smckusick 	int	rgid;
37555163Smckusick 	int	egid;
37655163Smckusick };
37755163Smckusick /* ARGSUSED */
37855163Smckusick osetregid(p, uap, retval)
37955163Smckusick 	register struct proc *p;
38055163Smckusick 	struct setregid_args *uap;
38155163Smckusick 	int *retval;
38255163Smckusick {
38355163Smckusick 	register struct pcred *pc = p->p_cred;
38455163Smckusick 	struct setegid_args args;
38555163Smckusick 
38655163Smckusick 	/*
38755163Smckusick 	 * we assume that the intent of setting rgid is to be able to get
38855163Smckusick 	 * back rgid priviledge. So we make sure that we will be able to
38955163Smckusick 	 * do so, but do not actually set the rgid.
39055163Smckusick 	 */
39165512Smckusick 	if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid &&
39255163Smckusick 	    uap->rgid != pc->p_svgid)
39355163Smckusick 		return (EPERM);
39465512Smckusick 	if (uap->egid == (gid_t)-1)
39555163Smckusick 		return (0);
39655163Smckusick 	args.egid = uap->egid;
39755163Smckusick 	return (setegid(p, &args, retval));
39855163Smckusick }
39955163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
40055163Smckusick 
4017498Sroot /*
40237578Smckusick  * Check if gid is a member of the group set.
40311810Ssam  */
40437578Smckusick groupmember(gid, cred)
40526275Skarels 	gid_t gid;
40637578Smckusick 	register struct ucred *cred;
4077866Sroot {
40818362Skarels 	register gid_t *gp;
40937578Smckusick 	gid_t *egp;
4107866Sroot 
41137578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
41237578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
4137866Sroot 		if (*gp == gid)
41437578Smckusick 			return (1);
41537578Smckusick 	return (0);
4167866Sroot }
4177866Sroot 
41811810Ssam /*
41946293Skarels  * Test whether the specified credentials imply "super-user"
42046293Skarels  * privilege; if so, and we have accounting info, set the flag
42146293Skarels  * indicating use of super-powers.
42246293Skarels  * Returns 0 or error.
42311810Ssam  */
42437578Smckusick suser(cred, acflag)
42537578Smckusick 	struct ucred *cred;
42637578Smckusick 	short *acflag;
4277866Sroot {
42837578Smckusick 	if (cred->cr_uid == 0) {
42937578Smckusick 		if (acflag)
43037578Smckusick 			*acflag |= ASU;
43137578Smckusick 		return (0);
43218362Skarels 	}
43337578Smckusick 	return (EPERM);
4347866Sroot }
43511810Ssam 
43611810Ssam /*
43737578Smckusick  * Allocate a zeroed cred structure.
43811810Ssam  */
43937578Smckusick struct ucred *
44037578Smckusick crget()
44111810Ssam {
44237578Smckusick 	register struct ucred *cr;
44311810Ssam 
44437578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
44537578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
44637578Smckusick 	cr->cr_ref = 1;
44743393Skarels 	return (cr);
44811810Ssam }
44937085Skfall 
45037085Skfall /*
45137578Smckusick  * Free a cred structure.
45237578Smckusick  * Throws away space when ref count gets to 0.
45337085Skfall  */
45437578Smckusick crfree(cr)
45537578Smckusick 	struct ucred *cr;
45637578Smckusick {
45765537Sbostic 	int s;
45837085Skfall 
45965537Sbostic 	s = splimp();				/* ??? */
46065537Sbostic 	if (--cr->cr_ref == 0)
46165537Sbostic 		FREE((caddr_t)cr, M_CRED);
46237578Smckusick 	(void) splx(s);
46337578Smckusick }
46437578Smckusick 
46537578Smckusick /*
46637578Smckusick  * Copy cred structure to a new one and free the old one.
46737578Smckusick  */
46837578Smckusick struct ucred *
46937578Smckusick crcopy(cr)
47037578Smckusick 	struct ucred *cr;
47137085Skfall {
47237578Smckusick 	struct ucred *newcr;
47337085Skfall 
47445908Sbostic 	if (cr->cr_ref == 1)
47545908Sbostic 		return (cr);
47637578Smckusick 	newcr = crget();
47737578Smckusick 	*newcr = *cr;
47837578Smckusick 	crfree(cr);
47937578Smckusick 	newcr->cr_ref = 1;
48043393Skarels 	return (newcr);
48137085Skfall }
48237085Skfall 
48337085Skfall /*
48437578Smckusick  * Dup cred struct to a new held one.
48537085Skfall  */
48637578Smckusick struct ucred *
48737578Smckusick crdup(cr)
48837578Smckusick 	struct ucred *cr;
48937085Skfall {
49037578Smckusick 	struct ucred *newcr;
49137085Skfall 
49237578Smckusick 	newcr = crget();
49337578Smckusick 	*newcr = *cr;
49437578Smckusick 	newcr->cr_ref = 1;
49543393Skarels 	return (newcr);
49637085Skfall }
49737579Smckusick 
49837579Smckusick /*
49940667Skarels  * Get login name, if available.
50037579Smckusick  */
50154925Storek struct getlogin_args {
50254925Storek 	char	*namebuf;
50354925Storek 	u_int	namelen;
50454925Storek };
50543393Skarels /* ARGSUSED */
50643393Skarels getlogin(p, uap, retval)
50743393Skarels 	struct proc *p;
50854925Storek 	struct getlogin_args *uap;
50943393Skarels 	int *retval;
51043393Skarels {
51137579Smckusick 
51247540Skarels 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
51347540Skarels 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
51447540Skarels 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
51547540Skarels 	    (caddr_t) uap->namebuf, uap->namelen));
51637579Smckusick }
51737579Smckusick 
51837579Smckusick /*
51940667Skarels  * Set login name.
52037579Smckusick  */
52154925Storek struct setlogin_args {
52254925Storek 	char	*namebuf;
52354925Storek };
52443393Skarels /* ARGSUSED */
52543393Skarels setlogin(p, uap, retval)
52643393Skarels 	struct proc *p;
52754925Storek 	struct setlogin_args *uap;
52843393Skarels 	int *retval;
52937579Smckusick {
53040667Skarels 	int error;
53137579Smckusick 
53247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
53344405Skarels 		return (error);
53447540Skarels 	error = copyinstr((caddr_t) uap->namebuf,
53547540Skarels 	    (caddr_t) p->p_pgrp->pg_session->s_login,
53647540Skarels 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
53747540Skarels 	if (error == ENAMETOOLONG)
53840667Skarels 		error = EINVAL;
53944405Skarels 	return (error);
54037579Smckusick }
541