xref: /csrg-svn/sys/kern/kern_prot.c (revision 65512)
123372Smckusick /*
263182Sbostic  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
363182Sbostic  *	Regents of the University of California.  All rights reserved.
423372Smckusick  *
544439Sbostic  * %sccs.include.redist.c%
637578Smckusick  *
7*65512Smckusick  *	@(#)kern_prot.c	8.3 (Berkeley) 01/05/94
823372Smckusick  */
97420Sroot 
107420Sroot /*
117498Sroot  * System calls related to processes and protection
127420Sroot  */
137420Sroot 
1457048Smckusick #include <sys/param.h>
1557048Smckusick #include <sys/acct.h>
1657048Smckusick #include <sys/systm.h>
1757048Smckusick #include <sys/ucred.h>
1857048Smckusick #include <sys/proc.h>
1957048Smckusick #include <sys/timeb.h>
2057048Smckusick #include <sys/times.h>
2157048Smckusick #include <sys/malloc.h>
227420Sroot 
2354925Storek struct args {
2454925Storek 	int	dummy;
2554925Storek };
2654925Storek 
2743393Skarels /* ARGSUSED */
2843393Skarels getpid(p, uap, retval)
2943393Skarels 	struct proc *p;
3054925Storek 	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;
4454925Storek 	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;
5554925Storek 	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;
6654925Storek 	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;
8054925Storek 	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;
9154925Storek 	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;
11054925Storek 	struct args *uap;
11143393Skarels 	int *retval;
11243393Skarels {
11347540Skarels 
11447540Skarels 	*retval = p->p_ucred->cr_groups[0];
11544405Skarels 	return (0);
11643393Skarels }
11743393Skarels 
11854925Storek struct getgroups_args {
11954925Storek 	u_int	gidsetsize;
12055162Smckusick 	gid_t	*gidset;
12154925Storek };
12243393Skarels getgroups(p, uap, retval)
12343393Skarels 	struct proc *p;
12454925Storek 	register struct	getgroups_args *uap;
12543393Skarels 	int *retval;
12643393Skarels {
12747540Skarels 	register struct pcred *pc = p->p_cred;
12844994Skarels 	register u_int ngrp;
12943393Skarels 	int error;
1307498Sroot 
13144994Skarels 	if ((ngrp = uap->gidsetsize) == 0) {
13247540Skarels 		*retval = pc->pc_ucred->cr_ngroups;
13344405Skarels 		return (0);
13437578Smckusick 	}
13547540Skarels 	if (ngrp < pc->pc_ucred->cr_ngroups)
13644405Skarels 		return (EINVAL);
13747540Skarels 	ngrp = pc->pc_ucred->cr_ngroups;
13855162Smckusick 	if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
13955162Smckusick 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))
14044405Skarels 		return (error);
14144994Skarels 	*retval = ngrp;
14244405Skarels 	return (0);
1437498Sroot }
1447498Sroot 
14543393Skarels /* ARGSUSED */
14643393Skarels setsid(p, uap, retval)
14747540Skarels 	register struct proc *p;
14854925Storek 	struct args *uap;
14943393Skarels 	int *retval;
15037579Smckusick {
15137579Smckusick 
15243393Skarels 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
15344405Skarels 		return (EPERM);
15443393Skarels 	} else {
15557049Smarc 		(void)enterpgrp(p, p->p_pid, 1);
15643393Skarels 		*retval = p->p_pid;
15744405Skarels 		return (0);
15837579Smckusick 	}
15937579Smckusick }
16037579Smckusick 
16137579Smckusick /*
16247540Skarels  * set process group (setpgid/old setpgrp)
16337579Smckusick  *
16447972Smarc  * caller does setpgid(targpid, targpgid)
16540667Skarels  *
16640667Skarels  * pid must be caller or child of caller (ESRCH)
16740667Skarels  * if a child
16840667Skarels  *	pid must be in same session (EPERM)
16940667Skarels  *	pid can't have done an exec (EACCES)
17040667Skarels  * if pgid != pid
17140667Skarels  * 	there must exist some pid in same session having pgid (EPERM)
17240667Skarels  * pid must not be session leader (EPERM)
17337579Smckusick  */
17454925Storek struct setpgid_args {
17554925Storek 	int	pid;	/* target process id */
17654925Storek 	int	pgid;	/* target pgrp id */
17754925Storek };
17843393Skarels /* ARGSUSED */
17947972Smarc setpgid(curp, uap, retval)
18047972Smarc 	struct proc *curp;
18154925Storek 	register struct setpgid_args *uap;
18243393Skarels 	int *retval;
18343393Skarels {
18447972Smarc 	register struct proc *targp;		/* target process */
18548990Skarels 	register struct pgrp *pgrp;		/* target pgrp */
1867498Sroot 
18748990Skarels 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
18848990Skarels 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
18944405Skarels 			return (ESRCH);
19047972Smarc 		if (targp->p_session != curp->p_session)
19144405Skarels 			return (EPERM);
19264586Sbostic 		if (targp->p_flag & P_EXEC)
19344405Skarels 			return (EACCES);
19443393Skarels 	} else
19547972Smarc 		targp = curp;
19647972Smarc 	if (SESS_LEADER(targp))
19744405Skarels 		return (EPERM);
19848990Skarels 	if (uap->pgid == 0)
19948990Skarels 		uap->pgid = targp->p_pid;
20048990Skarels 	else if (uap->pgid != targp->p_pid)
20148990Skarels 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
20248990Skarels 	            pgrp->pg_session != curp->p_session)
20345908Sbostic 			return (EPERM);
20457049Smarc 	return (enterpgrp(targp, uap->pgid, 0));
2057498Sroot }
2067498Sroot 
20754925Storek struct setuid_args {
20855162Smckusick 	uid_t	uid;
20954925Storek };
21043393Skarels /* ARGSUSED */
21143393Skarels setuid(p, uap, retval)
21247540Skarels 	struct proc *p;
21354925Storek 	struct setuid_args *uap;
21443393Skarels 	int *retval;
2157420Sroot {
21647540Skarels 	register struct pcred *pc = p->p_cred;
21743393Skarels 	register uid_t uid;
21843393Skarels 	int error;
21943393Skarels 
22043393Skarels 	uid = uap->uid;
22147540Skarels 	if (uid != pc->p_ruid &&
22247540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
22344405Skarels 		return (error);
22443393Skarels 	/*
22555403Smckusick 	 * Everything's okay, do it.
22655403Smckusick 	 * Transfer proc count to new user.
22755403Smckusick 	 * Copy credentials so other references do not see our changes.
22843393Skarels 	 */
22955403Smckusick 	(void)chgproccnt(pc->p_ruid, -1);
23055403Smckusick 	(void)chgproccnt(uid, 1);
23147540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
23247540Skarels 	pc->pc_ucred->cr_uid = uid;
23347540Skarels 	pc->p_ruid = uid;
23447540Skarels 	pc->p_svuid = uid;
23564586Sbostic 	p->p_flag |= P_SUGID;
23644405Skarels 	return (0);
23743393Skarels }
23843393Skarels 
23954925Storek struct seteuid_args {
24055162Smckusick 	uid_t	euid;
24154925Storek };
24243393Skarels /* ARGSUSED */
24343393Skarels seteuid(p, uap, retval)
24447540Skarels 	struct proc *p;
24554925Storek 	struct seteuid_args *uap;
24643393Skarels 	int *retval;
24743393Skarels {
24847540Skarels 	register struct pcred *pc = p->p_cred;
24943393Skarels 	register uid_t euid;
25043393Skarels 	int error;
25143393Skarels 
25243393Skarels 	euid = uap->euid;
25347540Skarels 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
25447540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
25544405Skarels 		return (error);
25643393Skarels 	/*
25745908Sbostic 	 * Everything's okay, do it.  Copy credentials so other references do
25845908Sbostic 	 * not see our changes.
25943393Skarels 	 */
26047540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
26147540Skarels 	pc->pc_ucred->cr_uid = euid;
26264586Sbostic 	p->p_flag |= P_SUGID;
26344405Skarels 	return (0);
26443393Skarels }
26543393Skarels 
26654925Storek struct setgid_args {
26755162Smckusick 	gid_t	gid;
26854925Storek };
26943393Skarels /* ARGSUSED */
27043393Skarels setgid(p, uap, retval)
27143393Skarels 	struct proc *p;
27254925Storek 	struct setgid_args *uap;
27343393Skarels 	int *retval;
27443393Skarels {
27547540Skarels 	register struct pcred *pc = p->p_cred;
27643393Skarels 	register gid_t gid;
27743393Skarels 	int error;
27843393Skarels 
27943393Skarels 	gid = uap->gid;
28047540Skarels 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
28144405Skarels 		return (error);
28247540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
28347540Skarels 	pc->pc_ucred->cr_groups[0] = gid;
28447540Skarels 	pc->p_rgid = gid;
28547540Skarels 	pc->p_svgid = gid;		/* ??? */
28664586Sbostic 	p->p_flag |= P_SUGID;
28744405Skarels 	return (0);
28843393Skarels }
28943393Skarels 
29054925Storek struct setegid_args {
29155162Smckusick 	gid_t	egid;
29254925Storek };
29343393Skarels /* ARGSUSED */
29443393Skarels setegid(p, uap, retval)
29543393Skarels 	struct proc *p;
29654925Storek 	struct setegid_args *uap;
29743393Skarels 	int *retval;
29843393Skarels {
29947540Skarels 	register struct pcred *pc = p->p_cred;
30043393Skarels 	register gid_t egid;
30143393Skarels 	int error;
30243393Skarels 
30343393Skarels 	egid = uap->egid;
30447540Skarels 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
30547540Skarels 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
30644405Skarels 		return (error);
30747540Skarels 	pc->pc_ucred = crcopy(pc->pc_ucred);
30847540Skarels 	pc->pc_ucred->cr_groups[0] = egid;
30964586Sbostic 	p->p_flag |= P_SUGID;
31044405Skarels 	return (0);
31143393Skarels }
31243393Skarels 
31354925Storek struct setgroups_args {
31454925Storek 	u_int	gidsetsize;
31555162Smckusick 	gid_t	*gidset;
31654925Storek };
31743393Skarels /* ARGSUSED */
31843393Skarels setgroups(p, uap, retval)
31943393Skarels 	struct proc *p;
32054925Storek 	struct setgroups_args *uap;
32143393Skarels 	int *retval;
32243393Skarels {
32347540Skarels 	register struct pcred *pc = p->p_cred;
32444994Skarels 	register u_int ngrp;
32555162Smckusick 	int error;
3267498Sroot 
32747540Skarels 	if (error = suser(pc->pc_ucred, &p->p_acflag))
32844405Skarels 		return (error);
32944994Skarels 	if ((ngrp = uap->gidsetsize) > NGROUPS)
33044405Skarels 		return (EINVAL);
33155162Smckusick 	pc->pc_ucred = crcopy(pc->pc_ucred);
33255162Smckusick 	if (error = copyin((caddr_t)uap->gidset,
33355162Smckusick 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
33444405Skarels 		return (error);
33547540Skarels 	pc->pc_ucred->cr_ngroups = ngrp;
33664586Sbostic 	p->p_flag |= P_SUGID;
33744405Skarels 	return (0);
3387498Sroot }
3397498Sroot 
34055163Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
34155163Smckusick struct setreuid_args {
34255163Smckusick 	int	ruid;
34355163Smckusick 	int	euid;
34455163Smckusick };
34555163Smckusick /* ARGSUSED */
34655163Smckusick osetreuid(p, uap, retval)
34755163Smckusick 	register struct proc *p;
34855163Smckusick 	struct setreuid_args *uap;
34955163Smckusick 	int *retval;
35055163Smckusick {
35155163Smckusick 	register struct pcred *pc = p->p_cred;
35255163Smckusick 	struct seteuid_args args;
35355163Smckusick 
35455163Smckusick 	/*
35555163Smckusick 	 * we assume that the intent of setting ruid is to be able to get
35655163Smckusick 	 * back ruid priviledge. So we make sure that we will be able to
35755163Smckusick 	 * do so, but do not actually set the ruid.
35855163Smckusick 	 */
359*65512Smckusick 	if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid &&
36055163Smckusick 	    uap->ruid != pc->p_svuid)
36155163Smckusick 		return (EPERM);
362*65512Smckusick 	if (uap->euid == (uid_t)-1)
36355163Smckusick 		return (0);
36455163Smckusick 	args.euid = uap->euid;
36555163Smckusick 	return (seteuid(p, &args, retval));
36655163Smckusick }
36755163Smckusick 
36855163Smckusick struct setregid_args {
36955163Smckusick 	int	rgid;
37055163Smckusick 	int	egid;
37155163Smckusick };
37255163Smckusick /* ARGSUSED */
37355163Smckusick osetregid(p, uap, retval)
37455163Smckusick 	register struct proc *p;
37555163Smckusick 	struct setregid_args *uap;
37655163Smckusick 	int *retval;
37755163Smckusick {
37855163Smckusick 	register struct pcred *pc = p->p_cred;
37955163Smckusick 	struct setegid_args args;
38055163Smckusick 
38155163Smckusick 	/*
38255163Smckusick 	 * we assume that the intent of setting rgid is to be able to get
38355163Smckusick 	 * back rgid priviledge. So we make sure that we will be able to
38455163Smckusick 	 * do so, but do not actually set the rgid.
38555163Smckusick 	 */
386*65512Smckusick 	if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid &&
38755163Smckusick 	    uap->rgid != pc->p_svgid)
38855163Smckusick 		return (EPERM);
389*65512Smckusick 	if (uap->egid == (gid_t)-1)
39055163Smckusick 		return (0);
39155163Smckusick 	args.egid = uap->egid;
39255163Smckusick 	return (setegid(p, &args, retval));
39355163Smckusick }
39455163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
39555163Smckusick 
3967498Sroot /*
39737578Smckusick  * Check if gid is a member of the group set.
39811810Ssam  */
39937578Smckusick groupmember(gid, cred)
40026275Skarels 	gid_t gid;
40137578Smckusick 	register struct ucred *cred;
4027866Sroot {
40318362Skarels 	register gid_t *gp;
40437578Smckusick 	gid_t *egp;
4057866Sroot 
40637578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
40737578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
4087866Sroot 		if (*gp == gid)
40937578Smckusick 			return (1);
41037578Smckusick 	return (0);
4117866Sroot }
4127866Sroot 
41311810Ssam /*
41446293Skarels  * Test whether the specified credentials imply "super-user"
41546293Skarels  * privilege; if so, and we have accounting info, set the flag
41646293Skarels  * indicating use of super-powers.
41746293Skarels  * Returns 0 or error.
41811810Ssam  */
41937578Smckusick suser(cred, acflag)
42037578Smckusick 	struct ucred *cred;
42137578Smckusick 	short *acflag;
4227866Sroot {
42337578Smckusick 	if (cred->cr_uid == 0) {
42437578Smckusick 		if (acflag)
42537578Smckusick 			*acflag |= ASU;
42637578Smckusick 		return (0);
42718362Skarels 	}
42837578Smckusick 	return (EPERM);
4297866Sroot }
43011810Ssam 
43111810Ssam /*
43237578Smckusick  * Allocate a zeroed cred structure.
43311810Ssam  */
43437578Smckusick struct ucred *
43537578Smckusick crget()
43611810Ssam {
43737578Smckusick 	register struct ucred *cr;
43811810Ssam 
43937578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
44037578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
44137578Smckusick 	cr->cr_ref = 1;
44243393Skarels 	return (cr);
44311810Ssam }
44437085Skfall 
44537085Skfall /*
44637578Smckusick  * Free a cred structure.
44737578Smckusick  * Throws away space when ref count gets to 0.
44837085Skfall  */
44937578Smckusick crfree(cr)
45037578Smckusick 	struct ucred *cr;
45137578Smckusick {
45247540Skarels 	int s = splimp();			/* ??? */
45337085Skfall 
45437578Smckusick 	if (--cr->cr_ref != 0) {
45537578Smckusick 		(void) splx(s);
45637578Smckusick 		return;
45737578Smckusick 	}
45837578Smckusick 	FREE((caddr_t)cr, M_CRED);
45937578Smckusick 	(void) splx(s);
46037578Smckusick }
46137578Smckusick 
46237578Smckusick /*
46337578Smckusick  * Copy cred structure to a new one and free the old one.
46437578Smckusick  */
46537578Smckusick struct ucred *
46637578Smckusick crcopy(cr)
46737578Smckusick 	struct ucred *cr;
46837085Skfall {
46937578Smckusick 	struct ucred *newcr;
47037085Skfall 
47145908Sbostic 	if (cr->cr_ref == 1)
47245908Sbostic 		return (cr);
47337578Smckusick 	newcr = crget();
47437578Smckusick 	*newcr = *cr;
47537578Smckusick 	crfree(cr);
47637578Smckusick 	newcr->cr_ref = 1;
47743393Skarels 	return (newcr);
47837085Skfall }
47937085Skfall 
48037085Skfall /*
48137578Smckusick  * Dup cred struct to a new held one.
48237085Skfall  */
48337578Smckusick struct ucred *
48437578Smckusick crdup(cr)
48537578Smckusick 	struct ucred *cr;
48637085Skfall {
48737578Smckusick 	struct ucred *newcr;
48837085Skfall 
48937578Smckusick 	newcr = crget();
49037578Smckusick 	*newcr = *cr;
49137578Smckusick 	newcr->cr_ref = 1;
49243393Skarels 	return (newcr);
49337085Skfall }
49437579Smckusick 
49537579Smckusick /*
49640667Skarels  * Get login name, if available.
49737579Smckusick  */
49854925Storek struct getlogin_args {
49954925Storek 	char	*namebuf;
50054925Storek 	u_int	namelen;
50154925Storek };
50243393Skarels /* ARGSUSED */
50343393Skarels getlogin(p, uap, retval)
50443393Skarels 	struct proc *p;
50554925Storek 	struct getlogin_args *uap;
50643393Skarels 	int *retval;
50743393Skarels {
50837579Smckusick 
50947540Skarels 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
51047540Skarels 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
51147540Skarels 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
51247540Skarels 	    (caddr_t) uap->namebuf, uap->namelen));
51337579Smckusick }
51437579Smckusick 
51537579Smckusick /*
51640667Skarels  * Set login name.
51737579Smckusick  */
51854925Storek struct setlogin_args {
51954925Storek 	char	*namebuf;
52054925Storek };
52143393Skarels /* ARGSUSED */
52243393Skarels setlogin(p, uap, retval)
52343393Skarels 	struct proc *p;
52454925Storek 	struct setlogin_args *uap;
52543393Skarels 	int *retval;
52637579Smckusick {
52740667Skarels 	int error;
52837579Smckusick 
52947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
53044405Skarels 		return (error);
53147540Skarels 	error = copyinstr((caddr_t) uap->namebuf,
53247540Skarels 	    (caddr_t) p->p_pgrp->pg_session->s_login,
53347540Skarels 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
53447540Skarels 	if (error == ENAMETOOLONG)
53540667Skarels 		error = EINVAL;
53644405Skarels 	return (error);
53737579Smckusick }
538