kern_prot.c revision 72093
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
3950477Speter * $FreeBSD: head/sys/kern/kern_prot.c 72093 2001-02-06 12:05:58Z asmodai $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
4631778Seivind#include "opt_compat.h"
4731778Seivind
481541Srgrimes#include <sys/param.h>
491541Srgrimes#include <sys/acct.h>
501541Srgrimes#include <sys/systm.h>
5112221Sbde#include <sys/sysproto.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
541541Srgrimes#include <sys/proc.h>
551541Srgrimes#include <sys/malloc.h>
5631891Ssef#include <sys/pioctl.h>
5765495Struckman#include <sys/resourcevar.h>
5861287Srwatson#include <sys/sysctl.h>
591541Srgrimes
6030354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6130354Sphk
6212221Sbde#ifndef _SYS_SYSPROTO_H_
6311332Sswallacestruct getpid_args {
641541Srgrimes	int	dummy;
651541Srgrimes};
6612221Sbde#endif
671541Srgrimes
6858717Sdillon/*
6970317Sjake * getpid - MP SAFE
7058717Sdillon */
7170317Sjake
721541Srgrimes/* ARGSUSED */
731549Srgrimesint
7430994Sphkgetpid(p, uap)
751541Srgrimes	struct proc *p;
7611332Sswallace	struct getpid_args *uap;
771541Srgrimes{
781541Srgrimes
7930994Sphk	p->p_retval[0] = p->p_pid;
801541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8170317Sjake	PROCTREE_LOCK(PT_SHARED);
8230994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
8370317Sjake	PROCTREE_LOCK(PT_RELEASE);
841541Srgrimes#endif
851541Srgrimes	return (0);
861541Srgrimes}
871541Srgrimes
8870317Sjake/*
8970317Sjake * getppid - MP SAFE
9070317Sjake */
9170317Sjake
9212221Sbde#ifndef _SYS_SYSPROTO_H_
9311332Sswallacestruct getppid_args {
9411332Sswallace        int     dummy;
9511332Sswallace};
9612221Sbde#endif
971541Srgrimes/* ARGSUSED */
981549Srgrimesint
9930994Sphkgetppid(p, uap)
1001541Srgrimes	struct proc *p;
10111332Sswallace	struct getppid_args *uap;
1021541Srgrimes{
1031541Srgrimes
10470317Sjake	PROCTREE_LOCK(PT_SHARED);
10530994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
10670317Sjake	PROCTREE_LOCK(PT_RELEASE);
1071541Srgrimes	return (0);
1081541Srgrimes}
1091541Srgrimes
11058717Sdillon/*
11158717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter
11258717Sdillon *
11358717Sdillon * MP SAFE
11458717Sdillon */
11512221Sbde#ifndef _SYS_SYSPROTO_H_
11611332Sswallacestruct getpgrp_args {
11711332Sswallace        int     dummy;
11811332Sswallace};
11912221Sbde#endif
12011332Sswallace
1211549Srgrimesint
12230994Sphkgetpgrp(p, uap)
1231541Srgrimes	struct proc *p;
12411332Sswallace	struct getpgrp_args *uap;
1251541Srgrimes{
1261541Srgrimes
12730994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1281541Srgrimes	return (0);
1291541Srgrimes}
1301541Srgrimes
13128401Speter/* Get an arbitary pid's process group id */
13212221Sbde#ifndef _SYS_SYSPROTO_H_
13328401Speterstruct getpgid_args {
13428401Speter	pid_t	pid;
13528401Speter};
13628401Speter#endif
13728401Speter
13828401Speterint
13930994Sphkgetpgid(p, uap)
14028401Speter	struct proc *p;
14128401Speter	struct getpgid_args *uap;
14228401Speter{
14341726Struckman	struct proc *pt;
14441726Struckman
14541726Struckman	pt = p;
14628401Speter	if (uap->pid == 0)
14728401Speter		goto found;
14828401Speter
14941726Struckman	if ((pt = pfind(uap->pid)) == 0)
15028401Speter		return ESRCH;
15128401Speterfound:
15241726Struckman	p->p_retval[0] = pt->p_pgrp->pg_id;
15328401Speter	return 0;
15428401Speter}
15528401Speter
15628401Speter/*
15728401Speter * Get an arbitary pid's session id.
15828401Speter */
15928401Speter#ifndef _SYS_SYSPROTO_H_
16028401Speterstruct getsid_args {
16128401Speter	pid_t	pid;
16228401Speter};
16328401Speter#endif
16428401Speter
16528401Speterint
16630994Sphkgetsid(p, uap)
16728401Speter	struct proc *p;
16828401Speter	struct getsid_args *uap;
16928401Speter{
17041726Struckman	struct proc *pt;
17141726Struckman
17241726Struckman	pt = p;
17328401Speter	if (uap->pid == 0)
17428401Speter		goto found;
17528401Speter
17671002Sben	if ((pt = pfind(uap->pid)) == 0)
17728401Speter		return ESRCH;
17828401Speterfound:
17941726Struckman	p->p_retval[0] = pt->p_session->s_sid;
18028401Speter	return 0;
18128401Speter}
18228401Speter
18328401Speter
18458941Sdillon/*
18558941Sdillon * getuid() - MP SAFE
18658941Sdillon */
18728401Speter#ifndef _SYS_SYSPROTO_H_
18811332Sswallacestruct getuid_args {
18911332Sswallace        int     dummy;
19011332Sswallace};
19112221Sbde#endif
19211332Sswallace
1931541Srgrimes/* ARGSUSED */
1941549Srgrimesint
19530994Sphkgetuid(p, uap)
1961541Srgrimes	struct proc *p;
19711332Sswallace	struct getuid_args *uap;
1981541Srgrimes{
1991541Srgrimes
20030994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
2011541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
20230994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
2031541Srgrimes#endif
2041541Srgrimes	return (0);
2051541Srgrimes}
2061541Srgrimes
20758941Sdillon/*
20858941Sdillon * geteuid() - MP SAFE
20958941Sdillon */
21012221Sbde#ifndef _SYS_SYSPROTO_H_
21111332Sswallacestruct geteuid_args {
21211332Sswallace        int     dummy;
21311332Sswallace};
21412221Sbde#endif
21511332Sswallace
2161541Srgrimes/* ARGSUSED */
2171549Srgrimesint
21830994Sphkgeteuid(p, uap)
2191541Srgrimes	struct proc *p;
22011332Sswallace	struct geteuid_args *uap;
2211541Srgrimes{
2221541Srgrimes
22330994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2241541Srgrimes	return (0);
2251541Srgrimes}
2261541Srgrimes
22758941Sdillon/*
22858941Sdillon * getgid() - MP SAFE
22958941Sdillon */
23012221Sbde#ifndef _SYS_SYSPROTO_H_
23111332Sswallacestruct getgid_args {
23211332Sswallace        int     dummy;
23311332Sswallace};
23412221Sbde#endif
23511332Sswallace
2361541Srgrimes/* ARGSUSED */
2371549Srgrimesint
23830994Sphkgetgid(p, uap)
2391541Srgrimes	struct proc *p;
24011332Sswallace	struct getgid_args *uap;
2411541Srgrimes{
2421541Srgrimes
24330994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2441541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
24530994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2461541Srgrimes#endif
2471541Srgrimes	return (0);
2481541Srgrimes}
2491541Srgrimes
2501541Srgrimes/*
2511541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2521541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2531541Srgrimes * correctly in a library function.
2541541Srgrimes */
25512221Sbde#ifndef _SYS_SYSPROTO_H_
25611332Sswallacestruct getegid_args {
25711332Sswallace        int     dummy;
25811332Sswallace};
25912221Sbde#endif
26011332Sswallace
2611541Srgrimes/* ARGSUSED */
2621549Srgrimesint
26330994Sphkgetegid(p, uap)
2641541Srgrimes	struct proc *p;
26511332Sswallace	struct getegid_args *uap;
2661541Srgrimes{
2671541Srgrimes
26830994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2691541Srgrimes	return (0);
2701541Srgrimes}
2711541Srgrimes
27212221Sbde#ifndef _SYS_SYSPROTO_H_
2731541Srgrimesstruct getgroups_args {
2741541Srgrimes	u_int	gidsetsize;
2751541Srgrimes	gid_t	*gidset;
2761541Srgrimes};
27712221Sbde#endif
2781549Srgrimesint
27930994Sphkgetgroups(p, uap)
2801541Srgrimes	struct proc *p;
2811541Srgrimes	register struct	getgroups_args *uap;
2821541Srgrimes{
2831541Srgrimes	register struct pcred *pc = p->p_cred;
2841541Srgrimes	register u_int ngrp;
2851541Srgrimes	int error;
2861541Srgrimes
2871541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
28830994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2891541Srgrimes		return (0);
2901541Srgrimes	}
2911541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2921541Srgrimes		return (EINVAL);
2931541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2943098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2953098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2961541Srgrimes		return (error);
29730994Sphk	p->p_retval[0] = ngrp;
2981541Srgrimes	return (0);
2991541Srgrimes}
3001541Srgrimes
30112221Sbde#ifndef _SYS_SYSPROTO_H_
30212207Sbdestruct setsid_args {
30311332Sswallace        int     dummy;
30411332Sswallace};
30512221Sbde#endif
30611332Sswallace
3071541Srgrimes/* ARGSUSED */
3081549Srgrimesint
30930994Sphksetsid(p, uap)
3101541Srgrimes	register struct proc *p;
31112207Sbde	struct setsid_args *uap;
3121541Srgrimes{
3131541Srgrimes
3141541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3151541Srgrimes		return (EPERM);
3161541Srgrimes	} else {
3171541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
31830994Sphk		p->p_retval[0] = p->p_pid;
3191541Srgrimes		return (0);
3201541Srgrimes	}
3211541Srgrimes}
3221541Srgrimes
3231541Srgrimes/*
3241541Srgrimes * set process group (setpgid/old setpgrp)
3251541Srgrimes *
3261541Srgrimes * caller does setpgid(targpid, targpgid)
3271541Srgrimes *
3281541Srgrimes * pid must be caller or child of caller (ESRCH)
3291541Srgrimes * if a child
3301541Srgrimes *	pid must be in same session (EPERM)
3311541Srgrimes *	pid can't have done an exec (EACCES)
3321541Srgrimes * if pgid != pid
3331541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3341541Srgrimes * pid must not be session leader (EPERM)
3351541Srgrimes */
33612221Sbde#ifndef _SYS_SYSPROTO_H_
3371541Srgrimesstruct setpgid_args {
3381541Srgrimes	int	pid;	/* target process id */
3391541Srgrimes	int	pgid;	/* target pgrp id */
3401541Srgrimes};
34112221Sbde#endif
3421541Srgrimes/* ARGSUSED */
3431549Srgrimesint
34430994Sphksetpgid(curp, uap)
3451541Srgrimes	struct proc *curp;
3461541Srgrimes	register struct setpgid_args *uap;
3471541Srgrimes{
3481541Srgrimes	register struct proc *targp;		/* target process */
3491541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
3501541Srgrimes
35120677Sbde	if (uap->pgid < 0)
35220677Sbde		return (EINVAL);
3531541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3541541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3551541Srgrimes			return (ESRCH);
35615985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3571541Srgrimes			return (EPERM);
3581541Srgrimes		if (targp->p_flag & P_EXEC)
3591541Srgrimes			return (EACCES);
3601541Srgrimes	} else
3611541Srgrimes		targp = curp;
3621541Srgrimes	if (SESS_LEADER(targp))
3631541Srgrimes		return (EPERM);
3641541Srgrimes	if (uap->pgid == 0)
3651541Srgrimes		uap->pgid = targp->p_pid;
3661541Srgrimes	else if (uap->pgid != targp->p_pid)
3671541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3681541Srgrimes	            pgrp->pg_session != curp->p_session)
3691541Srgrimes			return (EPERM);
3701541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3711541Srgrimes}
3721541Srgrimes
37324448Speter/*
37424448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
37572093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
37624448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
37724448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
37824448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
37924448Speter * does not set the saved id - this is dangerous for traditional BSD
38024448Speter * programs.  For this reason, we *really* do not want to set
38124448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
38224448Speter */
38324448Speter#define POSIX_APPENDIX_B_4_2_2
38424448Speter
38512221Sbde#ifndef _SYS_SYSPROTO_H_
3861541Srgrimesstruct setuid_args {
3871541Srgrimes	uid_t	uid;
3881541Srgrimes};
38912221Sbde#endif
3901541Srgrimes/* ARGSUSED */
3911549Srgrimesint
39230994Sphksetuid(p, uap)
3931541Srgrimes	struct proc *p;
3941541Srgrimes	struct setuid_args *uap;
3951541Srgrimes{
3961541Srgrimes	register struct pcred *pc = p->p_cred;
3971541Srgrimes	register uid_t uid;
3981541Srgrimes	int error;
3991541Srgrimes
40024448Speter	/*
40124448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
40224448Speter	 *
40324448Speter	 * Note that setuid(geteuid()) is a special case of
40424448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
40572093Sasmodai	 * to use this clause to be compatible with traditional BSD
40624448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
40724448Speter	 * three id's (assuming you have privs).
40824448Speter	 *
40924448Speter	 * Notes on the logic.  We do things in three steps.
41024448Speter	 * 1: We determine if the euid is going to change, and do EPERM
41124448Speter	 *    right away.  We unconditionally change the euid later if this
41224448Speter	 *    test is satisfied, simplifying that part of the logic.
41324448Speter	 * 2: We determine if the real and/or saved uid's are going to
41424448Speter	 *    change.  Determined by compile options.
41524448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
41624448Speter	 */
4171541Srgrimes	uid = uap->uid;
41824448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
41917994Sache#ifdef _POSIX_SAVED_IDS
42024448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
42117994Sache#endif
42224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
42324448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
42424448Speter#endif
42546155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4261541Srgrimes		return (error);
42724448Speter
42824448Speter#ifdef _POSIX_SAVED_IDS
4291541Srgrimes	/*
43024448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
43124448Speter	 * If so, we are changing the real uid and/or saved uid.
4321541Srgrimes	 */
43317994Sache	if (
43424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
43524448Speter	    uid == pc->pc_ucred->cr_uid ||
43617994Sache#endif
43746155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
43817994Sache#endif
43924448Speter	{
44024448Speter		/*
44165495Struckman		 * Set the real uid and transfer proc count to new user.
44224448Speter		 */
44324448Speter		if (uid != pc->p_ruid) {
44465495Struckman			change_ruid(p, uid);
44565495Struckman			setsugid(p);
44624448Speter		}
44724448Speter		/*
44824448Speter		 * Set saved uid
44924448Speter		 *
45024448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
45124448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
45224448Speter		 * is important that we should do this.
45324448Speter		 */
45424448Speter		if (pc->p_svuid != uid) {
45524448Speter			pc->p_svuid = uid;
45631891Ssef			setsugid(p);
45724448Speter		}
4588141Sache	}
45924448Speter
46024448Speter	/*
46124448Speter	 * In all permitted cases, we are changing the euid.
46224448Speter	 * Copy credentials so other references do not see our changes.
46324448Speter	 */
46424448Speter	if (pc->pc_ucred->cr_uid != uid) {
46565495Struckman		change_euid(p, uid);
46631891Ssef		setsugid(p);
46724448Speter	}
4681541Srgrimes	return (0);
4691541Srgrimes}
4701541Srgrimes
47112221Sbde#ifndef _SYS_SYSPROTO_H_
4721541Srgrimesstruct seteuid_args {
4731541Srgrimes	uid_t	euid;
4741541Srgrimes};
47512221Sbde#endif
4761541Srgrimes/* ARGSUSED */
4771549Srgrimesint
47830994Sphkseteuid(p, uap)
4791541Srgrimes	struct proc *p;
4801541Srgrimes	struct seteuid_args *uap;
4811541Srgrimes{
4821541Srgrimes	register struct pcred *pc = p->p_cred;
4831541Srgrimes	register uid_t euid;
4841541Srgrimes	int error;
4851541Srgrimes
4861541Srgrimes	euid = uap->euid;
48724449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
48824449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
48946155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4901541Srgrimes		return (error);
4911541Srgrimes	/*
4921541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4931541Srgrimes	 * not see our changes.
4941541Srgrimes	 */
49524449Speter	if (pc->pc_ucred->cr_uid != euid) {
49665495Struckman		change_euid(p, euid);
49731891Ssef		setsugid(p);
49824449Speter	}
4991541Srgrimes	return (0);
5001541Srgrimes}
5011541Srgrimes
50212221Sbde#ifndef _SYS_SYSPROTO_H_
5031541Srgrimesstruct setgid_args {
5041541Srgrimes	gid_t	gid;
5051541Srgrimes};
50612221Sbde#endif
5071541Srgrimes/* ARGSUSED */
5081549Srgrimesint
50930994Sphksetgid(p, uap)
5101541Srgrimes	struct proc *p;
5111541Srgrimes	struct setgid_args *uap;
5121541Srgrimes{
5131541Srgrimes	register struct pcred *pc = p->p_cred;
5141541Srgrimes	register gid_t gid;
5151541Srgrimes	int error;
5161541Srgrimes
51724448Speter	/*
51824448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
51924448Speter	 *
52024448Speter	 * Note that setgid(getegid()) is a special case of
52124448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52272093Sasmodai	 * to use this clause to be compatible with traditional BSD
52324448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
52424448Speter	 * three id's (assuming you have privs).
52524448Speter	 *
52624448Speter	 * For notes on the logic here, see setuid() above.
52724448Speter	 */
5281541Srgrimes	gid = uap->gid;
52924448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
53017994Sache#ifdef _POSIX_SAVED_IDS
53124448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
53217994Sache#endif
53324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53424448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
53524448Speter#endif
53646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5371541Srgrimes		return (error);
53824448Speter
53917994Sache#ifdef _POSIX_SAVED_IDS
54024448Speter	/*
54124448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
54224448Speter	 * If so, we are changing the real uid and saved gid.
54324448Speter	 */
54424448Speter	if (
54524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
54624448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
54717994Sache#endif
54846155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
54924448Speter#endif
55024448Speter	{
55124448Speter		/*
55224448Speter		 * Set real gid
55324448Speter		 */
55424448Speter		if (pc->p_rgid != gid) {
55524448Speter			pc->p_rgid = gid;
55631891Ssef			setsugid(p);
55724448Speter		}
55824448Speter		/*
55924448Speter		 * Set saved gid
56024448Speter		 *
56124448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
56224448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
56324448Speter		 * is important that we should do this.
56424448Speter		 */
56524448Speter		if (pc->p_svgid != gid) {
56624448Speter			pc->p_svgid = gid;
56731891Ssef			setsugid(p);
56824448Speter		}
5698141Sache	}
57024448Speter	/*
57124448Speter	 * In all cases permitted cases, we are changing the egid.
57224448Speter	 * Copy credentials so other references do not see our changes.
57324448Speter	 */
57424448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
57524448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
57624448Speter		pc->pc_ucred->cr_groups[0] = gid;
57731891Ssef		setsugid(p);
57824448Speter	}
5791541Srgrimes	return (0);
5801541Srgrimes}
5811541Srgrimes
58212221Sbde#ifndef _SYS_SYSPROTO_H_
5831541Srgrimesstruct setegid_args {
5841541Srgrimes	gid_t	egid;
5851541Srgrimes};
58612221Sbde#endif
5871541Srgrimes/* ARGSUSED */
5881549Srgrimesint
58930994Sphksetegid(p, uap)
5901541Srgrimes	struct proc *p;
5911541Srgrimes	struct setegid_args *uap;
5921541Srgrimes{
5931541Srgrimes	register struct pcred *pc = p->p_cred;
5941541Srgrimes	register gid_t egid;
5951541Srgrimes	int error;
5961541Srgrimes
5971541Srgrimes	egid = uap->egid;
59824449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
59924449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
60046155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
6011541Srgrimes		return (error);
60224449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
60324449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
60424449Speter		pc->pc_ucred->cr_groups[0] = egid;
60531891Ssef		setsugid(p);
60624449Speter	}
6071541Srgrimes	return (0);
6081541Srgrimes}
6091541Srgrimes
61012221Sbde#ifndef _SYS_SYSPROTO_H_
6111541Srgrimesstruct setgroups_args {
6121541Srgrimes	u_int	gidsetsize;
6131541Srgrimes	gid_t	*gidset;
6141541Srgrimes};
61512221Sbde#endif
6161541Srgrimes/* ARGSUSED */
6171549Srgrimesint
61830994Sphksetgroups(p, uap)
6191541Srgrimes	struct proc *p;
6201541Srgrimes	struct setgroups_args *uap;
6211541Srgrimes{
6221541Srgrimes	register struct pcred *pc = p->p_cred;
6231541Srgrimes	register u_int ngrp;
6241541Srgrimes	int error;
6251541Srgrimes
62646155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
6271541Srgrimes		return (error);
62812063Sdg	ngrp = uap->gidsetsize;
62924447Speter	if (ngrp > NGROUPS)
6301541Srgrimes		return (EINVAL);
63124447Speter	/*
63224447Speter	 * XXX A little bit lazy here.  We could test if anything has
63324447Speter	 * changed before crcopy() and setting P_SUGID.
63424447Speter	 */
6351541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
63624447Speter	if (ngrp < 1) {
63724447Speter		/*
63824447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
63924447Speter		 * groups vector on non-BSD systems (which generally do not
64024447Speter		 * have the egid in the groups[0]).  We risk security holes
64124447Speter		 * when running non-BSD software if we do not do the same.
64224447Speter		 */
64324447Speter		pc->pc_ucred->cr_ngroups = 1;
64424447Speter	} else {
64524447Speter		if ((error = copyin((caddr_t)uap->gidset,
64624447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
64724447Speter			return (error);
64824447Speter		pc->pc_ucred->cr_ngroups = ngrp;
64924447Speter	}
65031891Ssef	setsugid(p);
6511541Srgrimes	return (0);
6521541Srgrimes}
6531541Srgrimes
65412221Sbde#ifndef _SYS_SYSPROTO_H_
6551541Srgrimesstruct setreuid_args {
6569238Sache	uid_t	ruid;
6579238Sache	uid_t	euid;
6581541Srgrimes};
65912221Sbde#endif
6601541Srgrimes/* ARGSUSED */
6611549Srgrimesint
66230994Sphksetreuid(p, uap)
6631541Srgrimes	register struct proc *p;
6641541Srgrimes	struct setreuid_args *uap;
6651541Srgrimes{
6661541Srgrimes	register struct pcred *pc = p->p_cred;
6679238Sache	register uid_t ruid, euid;
6688135Sache	int error;
6691541Srgrimes
6709238Sache	ruid = uap->ruid;
6719238Sache	euid = uap->euid;
67243311Sdillon	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
67343311Sdillon	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
67443311Sdillon	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
67546155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
6768135Sache		return (error);
6779238Sache
67824450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
67965495Struckman		change_euid(p, euid);
68031891Ssef		setsugid(p);
68124450Speter	}
68224450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
68365495Struckman		change_ruid(p, ruid);
68431891Ssef		setsugid(p);
6858135Sache	}
68624559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
68724559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6888111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
68931891Ssef		setsugid(p);
69024450Speter	}
6918135Sache	return (0);
6921541Srgrimes}
6931541Srgrimes
69412221Sbde#ifndef _SYS_SYSPROTO_H_
6951541Srgrimesstruct setregid_args {
6969238Sache	gid_t	rgid;
6979238Sache	gid_t	egid;
6981541Srgrimes};
69912221Sbde#endif
7001541Srgrimes/* ARGSUSED */
7011549Srgrimesint
70230994Sphksetregid(p, uap)
7031541Srgrimes	register struct proc *p;
7041541Srgrimes	struct setregid_args *uap;
7051541Srgrimes{
7061541Srgrimes	register struct pcred *pc = p->p_cred;
7079238Sache	register gid_t rgid, egid;
7088135Sache	int error;
7091541Srgrimes
7109238Sache	rgid = uap->rgid;
7119238Sache	egid = uap->egid;
71243311Sdillon	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
71343311Sdillon	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
71443311Sdillon	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
71546155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
7168135Sache		return (error);
7179238Sache
71824450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
71924450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
7209238Sache		pc->pc_ucred->cr_groups[0] = egid;
72131891Ssef		setsugid(p);
72224450Speter	}
72324450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7249238Sache		pc->p_rgid = rgid;
72531891Ssef		setsugid(p);
72624450Speter	}
72724559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
72824559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7298111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
73031891Ssef		setsugid(p);
73124450Speter	}
7328135Sache	return (0);
7331541Srgrimes}
7341541Srgrimes
73556115Speter/*
73656115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
73756115Speter * saved uid is explicit.
73856115Speter */
73956115Speter
74024453Speter#ifndef _SYS_SYSPROTO_H_
74156115Speterstruct setresuid_args {
74256115Speter	uid_t	ruid;
74356115Speter	uid_t	euid;
74456115Speter	uid_t	suid;
74556115Speter};
74656115Speter#endif
74756115Speter/* ARGSUSED */
74856115Speterint
74956115Spetersetresuid(p, uap)
75056115Speter	register struct proc *p;
75156115Speter	struct setresuid_args *uap;
75256115Speter{
75356115Speter	register struct pcred *pc = p->p_cred;
75456115Speter	register uid_t ruid, euid, suid;
75556115Speter	int error;
75656115Speter
75756115Speter	ruid = uap->ruid;
75856115Speter	euid = uap->euid;
75956115Speter	suid = uap->suid;
76056115Speter	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
76156115Speter	      ruid != pc->pc_ucred->cr_uid) ||
76256115Speter	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
76356115Speter	      euid != pc->pc_ucred->cr_uid) ||
76456115Speter	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
76556115Speter	      suid != pc->pc_ucred->cr_uid)) &&
76656115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
76756115Speter		return (error);
76856115Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
76965495Struckman		change_euid(p, euid);
77056115Speter		setsugid(p);
77156115Speter	}
77256115Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
77365495Struckman		change_ruid(p, ruid);
77456115Speter		setsugid(p);
77556115Speter	}
77656115Speter	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
77756115Speter		pc->p_svuid = suid;
77856115Speter		setsugid(p);
77956115Speter	}
78056115Speter	return (0);
78156115Speter}
78256115Speter
78356115Speter/*
78456115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
78556115Speter * saved gid is explicit.
78656115Speter */
78756115Speter
78856115Speter#ifndef _SYS_SYSPROTO_H_
78956115Speterstruct setresgid_args {
79056115Speter	gid_t	rgid;
79156115Speter	gid_t	egid;
79256115Speter	gid_t	sgid;
79356115Speter};
79456115Speter#endif
79556115Speter/* ARGSUSED */
79656115Speterint
79756115Spetersetresgid(p, uap)
79856115Speter	register struct proc *p;
79956115Speter	struct setresgid_args *uap;
80056115Speter{
80156115Speter	register struct pcred *pc = p->p_cred;
80256115Speter	register gid_t rgid, egid, sgid;
80356115Speter	int error;
80456115Speter
80556115Speter	rgid = uap->rgid;
80656115Speter	egid = uap->egid;
80756115Speter	sgid = uap->sgid;
80856115Speter	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
80956115Speter	      rgid != pc->pc_ucred->cr_groups[0]) ||
81056115Speter	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
81156115Speter	      egid != pc->pc_ucred->cr_groups[0]) ||
81256115Speter	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
81356115Speter	      sgid != pc->pc_ucred->cr_groups[0])) &&
81456115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
81556115Speter		return (error);
81656115Speter
81756115Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
81856115Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
81956115Speter		pc->pc_ucred->cr_groups[0] = egid;
82056115Speter		setsugid(p);
82156115Speter	}
82256115Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
82356115Speter		pc->p_rgid = rgid;
82456115Speter		setsugid(p);
82556115Speter	}
82656115Speter	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
82756115Speter		pc->p_svgid = sgid;
82856115Speter		setsugid(p);
82956115Speter	}
83056115Speter	return (0);
83156115Speter}
83256115Speter
83356115Speter#ifndef _SYS_SYSPROTO_H_
83456115Speterstruct getresuid_args {
83556115Speter	uid_t	*ruid;
83656115Speter	uid_t	*euid;
83756115Speter	uid_t	*suid;
83856115Speter};
83956115Speter#endif
84056115Speter/* ARGSUSED */
84156115Speterint
84256115Spetergetresuid(p, uap)
84356115Speter	register struct proc *p;
84456115Speter	struct getresuid_args *uap;
84556115Speter{
84656115Speter	struct pcred *pc = p->p_cred;
84756115Speter	int error1 = 0, error2 = 0, error3 = 0;
84856115Speter
84956115Speter	if (uap->ruid)
85056115Speter		error1 = copyout((caddr_t)&pc->p_ruid,
85156115Speter		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
85256115Speter	if (uap->euid)
85356115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
85456115Speter		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
85556115Speter	if (uap->suid)
85656115Speter		error3 = copyout((caddr_t)&pc->p_svuid,
85756115Speter		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
85856115Speter	return error1 ? error1 : (error2 ? error2 : error3);
85956115Speter}
86056115Speter
86156115Speter#ifndef _SYS_SYSPROTO_H_
86256115Speterstruct getresgid_args {
86356115Speter	gid_t	*rgid;
86456115Speter	gid_t	*egid;
86556115Speter	gid_t	*sgid;
86656115Speter};
86756115Speter#endif
86856115Speter/* ARGSUSED */
86956115Speterint
87056115Spetergetresgid(p, uap)
87156115Speter	register struct proc *p;
87256115Speter	struct getresgid_args *uap;
87356115Speter{
87456115Speter	struct pcred *pc = p->p_cred;
87556115Speter	int error1 = 0, error2 = 0, error3 = 0;
87656115Speter
87756115Speter	if (uap->rgid)
87856115Speter		error1 = copyout((caddr_t)&pc->p_rgid,
87956115Speter		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
88056115Speter	if (uap->egid)
88156115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
88256115Speter		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
88356115Speter	if (uap->sgid)
88456115Speter		error3 = copyout((caddr_t)&pc->p_svgid,
88556115Speter		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
88656115Speter	return error1 ? error1 : (error2 ? error2 : error3);
88756115Speter}
88856115Speter
88956115Speter
89056115Speter#ifndef _SYS_SYSPROTO_H_
89124453Speterstruct issetugid_args {
89224453Speter	int dummy;
89324453Speter};
89424453Speter#endif
89524453Speter/* ARGSUSED */
89624453Speterint
89730994Sphkissetugid(p, uap)
89824453Speter	register struct proc *p;
89924453Speter	struct issetugid_args *uap;
90024453Speter{
90124453Speter	/*
90224453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
90324453Speter	 * we use P_SUGID because we consider changing the owners as
90424453Speter	 * "tainting" as well.
90524453Speter	 * This is significant for procs that start as root and "become"
90624453Speter	 * a user without an exec - programs cannot know *everything*
90724453Speter	 * that libc *might* have put in their data segment.
90824453Speter	 */
90960216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
91024453Speter	return (0);
91124453Speter}
91224453Speter
9131541Srgrimes/*
9141541Srgrimes * Check if gid is a member of the group set.
9151541Srgrimes */
9161549Srgrimesint
9171541Srgrimesgroupmember(gid, cred)
9181541Srgrimes	gid_t gid;
9191541Srgrimes	register struct ucred *cred;
9201541Srgrimes{
9211541Srgrimes	register gid_t *gp;
9221541Srgrimes	gid_t *egp;
9231541Srgrimes
9241541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
9251541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
9261541Srgrimes		if (*gp == gid)
9271541Srgrimes			return (1);
9281541Srgrimes	return (0);
9291541Srgrimes}
9301541Srgrimes
93161287Srwatsonstatic int suser_permitted = 1;
93261287Srwatson
93361287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
93461287Srwatson    "processes with uid 0 have privilege");
93561287Srwatson
9361541Srgrimes/*
9371541Srgrimes * Test whether the specified credentials imply "super-user"
9381541Srgrimes * privilege; if so, and we have accounting info, set the flag
9391541Srgrimes * indicating use of super-powers.
9401541Srgrimes * Returns 0 or error.
9411541Srgrimes */
9421549Srgrimesint
94346112Sphksuser(p)
94465237Srwatson	const struct proc *p;
94546112Sphk{
94646155Sphk	return suser_xxx(0, p, 0);
94746112Sphk}
94846112Sphk
94946112Sphkint
95046155Sphksuser_xxx(cred, proc, flag)
95165237Srwatson	const struct ucred *cred;
95265237Srwatson	const struct proc *proc;
95346155Sphk	int flag;
9541541Srgrimes{
95561282Srwatson	if (!suser_permitted)
95661282Srwatson		return (EPERM);
95746155Sphk	if (!cred && !proc) {
95846155Sphk		printf("suser_xxx(): THINK!\n");
95946155Sphk		return (EPERM);
9601541Srgrimes	}
96146155Sphk	if (!cred)
96246155Sphk		cred = proc->p_ucred;
96346155Sphk	if (cred->cr_uid != 0)
96446155Sphk		return (EPERM);
96546155Sphk	if (proc && proc->p_prison && !(flag & PRISON_ROOT))
96646155Sphk		return (EPERM);
96746155Sphk	return (0);
9681541Srgrimes}
9691541Srgrimes
97065237Srwatsonstatic int
97165237Srwatsonp_cansee(const struct proc *p1, const struct proc *p2, int *privused)
97265237Srwatson{
97353518Sphk
97465237Srwatson	if (privused != NULL)
97565237Srwatson		*privused = 0;
97665237Srwatson
97765237Srwatson	if (!PRISON_CHECK(p1, p2))
97865237Srwatson		return (ESRCH);
97965237Srwatson
98065293Srwatson	if (!ps_showallprocs && p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) {
98165293Srwatson		if (suser_xxx(NULL, p1, PRISON_ROOT) == 0) {
98265293Srwatson			if (privused != NULL)
98365293Srwatson				*privused = 1;
98465293Srwatson			return (0);
98565293Srwatson		}
98665237Srwatson		return (ESRCH);
98765293Srwatson	}
98865237Srwatson
98965237Srwatson	return (0);
99065237Srwatson}
99165237Srwatson
99265237Srwatsonstatic int
99365237Srwatsonp_cankill(const struct proc *p1, const struct proc *p2, int *privused)
99453518Sphk{
99553518Sphk
99665237Srwatson	if (privused != NULL)
99765237Srwatson		*privused = 0;
99865237Srwatson
99953518Sphk	if (p1 == p2)
100053518Sphk		return (0);
100165237Srwatson
100253518Sphk	if (!PRISON_CHECK(p1, p2))
100353518Sphk		return (ESRCH);
100465237Srwatson
100553518Sphk	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
100653518Sphk		return (0);
100753518Sphk	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
100853518Sphk		return (0);
100965237Srwatson	/*
101065237Srwatson	 * XXX should a process be able to affect another process
101165237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
101265237Srwatson	 */
101353518Sphk	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
101453518Sphk		return (0);
101553518Sphk	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
101653518Sphk		return (0);
101765237Srwatson
101865237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
101965237Srwatson		if (privused != NULL)
102065237Srwatson			*privused = 1;
102153518Sphk		return (0);
102265237Srwatson	}
102365237Srwatson
102465237Srwatson#ifdef CAPABILITIES
102565237Srwatson	if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) {
102665237Srwatson		if (privused != NULL)
102765237Srwatson			*privused = 1;
102865237Srwatson		return (0);
102965237Srwatson	}
103065237Srwatson#endif
103165237Srwatson
103253518Sphk	return (EPERM);
103353518Sphk}
103453518Sphk
103565237Srwatsonstatic int
103665237Srwatsonp_cansched(const struct proc *p1, const struct proc *p2, int *privused)
103765237Srwatson{
103865237Srwatson
103965237Srwatson	if (privused != NULL)
104065237Srwatson		*privused = 0;
104165237Srwatson
104265237Srwatson	if (p1 == p2)
104365237Srwatson		return (0);
104465237Srwatson
104565237Srwatson	if (!PRISON_CHECK(p1, p2))
104665237Srwatson		return (ESRCH);
104765237Srwatson
104865237Srwatson	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
104965237Srwatson		return (0);
105065237Srwatson	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
105165237Srwatson		return (0);
105265237Srwatson	/*
105365237Srwatson	 * XXX should a process be able to affect another process
105465237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
105565237Srwatson	 */
105665237Srwatson	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
105765237Srwatson		return (0);
105865237Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
105965237Srwatson		return (0);
106065237Srwatson
106165237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
106265237Srwatson		if (privused != NULL)
106365237Srwatson			*privused = 1;
106465237Srwatson		return (0);
106565237Srwatson	}
106665237Srwatson
106765237Srwatson#ifdef CAPABILITIES
106865237Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) {
106965237Srwatson		if (privused != NULL)
107065237Srwatson			*privused = 1;
107165237Srwatson		return (0);
107265237Srwatson	}
107365237Srwatson#endif
107465237Srwatson
107565237Srwatson	return (EPERM);
107665237Srwatson}
107765237Srwatson
107865237Srwatsonstatic int
107965237Srwatsonp_candebug(const struct proc *p1, const struct proc *p2, int *privused)
108065237Srwatson{
108165237Srwatson	int	error;
108265237Srwatson
108365237Srwatson	if (privused != NULL)
108465237Srwatson		*privused = 0;
108565237Srwatson
108665237Srwatson	/* XXX it is authorized, but semantics don't permit it */
108765237Srwatson	if (p1 == p2)
108865237Srwatson		return (0);
108965237Srwatson
109065237Srwatson	if (!PRISON_CHECK(p1, p2))
109165237Srwatson		return (ESRCH);
109265237Srwatson
109365237Srwatson	/* not owned by you, has done setuid (unless you're root) */
109465237Srwatson	/* add a CAP_SYS_PTRACE here? */
109567999Srwatson	if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid ||
109667999Srwatson	    p1->p_cred->p_ruid != p2->p_cred->p_ruid ||
109768591Srwatson	    p1->p_cred->p_svuid != p2->p_cred->p_ruid ||
109867999Srwatson	    p2->p_flag & P_SUGID) {
109965237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
110065237Srwatson			return (error);
110165237Srwatson		if (privused != NULL)
110265237Srwatson			*privused = 1;
110365237Srwatson	}
110465237Srwatson
110565237Srwatson	/* can't trace init when securelevel > 0 */
110665237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
110765237Srwatson		return (EPERM);
110865237Srwatson
110965237Srwatson	return (0);
111065237Srwatson}
111165237Srwatson
111265237Srwatsonint
111365237Srwatsonp_can(const struct proc *p1, const struct proc *p2, int operation,
111465237Srwatson    int *privused)
111565237Srwatson{
111665237Srwatson
111765237Srwatson	switch(operation) {
111865237Srwatson	case P_CAN_SEE:
111965237Srwatson		return (p_cansee(p1, p2, privused));
112065237Srwatson
112165237Srwatson	case P_CAN_KILL:
112265237Srwatson		return (p_cankill(p1, p2, privused));
112365237Srwatson
112465237Srwatson	case P_CAN_SCHED:
112565237Srwatson		return (p_cansched(p1, p2, privused));
112665237Srwatson
112765237Srwatson	case P_CAN_DEBUG:
112865237Srwatson		return (p_candebug(p1, p2, privused));
112965237Srwatson
113065237Srwatson	default:
113165237Srwatson		panic("p_can: invalid operation");
113265237Srwatson	}
113365237Srwatson}
113465237Srwatson
113565237Srwatson
113653518Sphk/*
11371541Srgrimes * Allocate a zeroed cred structure.
11381541Srgrimes */
11391541Srgrimesstruct ucred *
11401541Srgrimescrget()
11411541Srgrimes{
11421541Srgrimes	register struct ucred *cr;
11431541Srgrimes
114469239Salfred	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
11451541Srgrimes	cr->cr_ref = 1;
114669239Salfred	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
11471541Srgrimes	return (cr);
11481541Srgrimes}
11491541Srgrimes
11501541Srgrimes/*
115169401Salfred * Claim another referernce to a ucred structure
115269401Salfred */
115369401Salfredvoid
115469401Salfredcrhold(cr)
115569401Salfred	struct ucred *cr;
115669401Salfred{
115769401Salfred
115869401Salfred	mtx_enter(&cr->cr_mtx, MTX_DEF);
115969401Salfred	cr->cr_ref++;
116069401Salfred	mtx_exit(&(cr)->cr_mtx, MTX_DEF);
116169401Salfred}
116269401Salfred
116369401Salfred
116469401Salfred/*
11651541Srgrimes * Free a cred structure.
11661541Srgrimes * Throws away space when ref count gets to 0.
11671541Srgrimes */
11681549Srgrimesvoid
11691541Srgrimescrfree(cr)
11701541Srgrimes	struct ucred *cr;
11711541Srgrimes{
117269239Salfred
117369239Salfred	mtx_enter(&cr->cr_mtx, MTX_DEF);
117465495Struckman	if (--cr->cr_ref == 0) {
117569239Salfred		mtx_destroy(&cr->cr_mtx);
117665495Struckman		/*
117765495Struckman		 * Some callers of crget(), such as nfs_statfs(),
117865495Struckman		 * allocate a temporary credential, but don't
117965495Struckman		 * allocate a uidinfo structure.
118065495Struckman		 */
118165495Struckman		if (cr->cr_uidinfo != NULL)
118265495Struckman			uifree(cr->cr_uidinfo);
11831541Srgrimes		FREE((caddr_t)cr, M_CRED);
118469239Salfred	} else {
118569239Salfred		mtx_exit(&cr->cr_mtx, MTX_DEF);
118665495Struckman	}
11871541Srgrimes}
11881541Srgrimes
11891541Srgrimes/*
11901541Srgrimes * Copy cred structure to a new one and free the old one.
11911541Srgrimes */
11921541Srgrimesstruct ucred *
11931541Srgrimescrcopy(cr)
11941541Srgrimes	struct ucred *cr;
11951541Srgrimes{
11961541Srgrimes	struct ucred *newcr;
11971541Srgrimes
119869239Salfred	mtx_enter(&cr->cr_mtx, MTX_DEF);
119969239Salfred	if (cr->cr_ref == 1) {
120069239Salfred		mtx_exit(&cr->cr_mtx, MTX_DEF);
12011541Srgrimes		return (cr);
120269239Salfred	}
120369239Salfred	mtx_exit(&cr->cr_mtx, MTX_DEF);
120469239Salfred	newcr = crdup(cr);
12051541Srgrimes	crfree(cr);
12061541Srgrimes	return (newcr);
12071541Srgrimes}
12081541Srgrimes
12091541Srgrimes/*
12101541Srgrimes * Dup cred struct to a new held one.
12111541Srgrimes */
12121541Srgrimesstruct ucred *
12131541Srgrimescrdup(cr)
12141541Srgrimes	struct ucred *cr;
12151541Srgrimes{
12161541Srgrimes	struct ucred *newcr;
12171541Srgrimes
121869239Salfred	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
12191541Srgrimes	*newcr = *cr;
122069239Salfred	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
122165495Struckman	uihold(newcr->cr_uidinfo);
12221541Srgrimes	newcr->cr_ref = 1;
12231541Srgrimes	return (newcr);
12241541Srgrimes}
12251541Srgrimes
12261541Srgrimes/*
12271541Srgrimes * Get login name, if available.
12281541Srgrimes */
122912221Sbde#ifndef _SYS_SYSPROTO_H_
12301541Srgrimesstruct getlogin_args {
12311541Srgrimes	char	*namebuf;
12321541Srgrimes	u_int	namelen;
12331541Srgrimes};
123412221Sbde#endif
12351541Srgrimes/* ARGSUSED */
12361549Srgrimesint
123730994Sphkgetlogin(p, uap)
12381541Srgrimes	struct proc *p;
12391541Srgrimes	struct getlogin_args *uap;
12401541Srgrimes{
12411541Srgrimes
124223358Sache	if (uap->namelen > MAXLOGNAME)
124323359Sache		uap->namelen = MAXLOGNAME;
12441541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
12451541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
12461541Srgrimes}
12471541Srgrimes
12481541Srgrimes/*
12491541Srgrimes * Set login name.
12501541Srgrimes */
125112221Sbde#ifndef _SYS_SYSPROTO_H_
12521541Srgrimesstruct setlogin_args {
12531541Srgrimes	char	*namebuf;
12541541Srgrimes};
125512221Sbde#endif
12561541Srgrimes/* ARGSUSED */
12571549Srgrimesint
125830994Sphksetlogin(p, uap)
12591541Srgrimes	struct proc *p;
12601541Srgrimes	struct setlogin_args *uap;
12611541Srgrimes{
12621541Srgrimes	int error;
126323330Sache	char logintmp[MAXLOGNAME];
12641541Srgrimes
126546155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
12661541Srgrimes		return (error);
126722522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
126836845Sdfr	    sizeof(logintmp), (size_t *)0);
12691541Srgrimes	if (error == ENAMETOOLONG)
12701541Srgrimes		error = EINVAL;
127122522Sdavidn	else if (!error)
127222522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
127323330Sache		    sizeof(logintmp));
12741541Srgrimes	return (error);
12751541Srgrimes}
127631891Ssef
127731891Ssefvoid
127831891Ssefsetsugid(p)
127955338Sphk	struct proc *p;
128031891Ssef{
128131891Ssef	p->p_flag |= P_SUGID;
128255707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
128331891Ssef		p->p_stops = 0;
128431891Ssef}
128565495Struckman
128665495Struckman/*
128765495Struckman * Helper function to change the effective uid of a process
128865495Struckman */
128965495Struckmanvoid
129065495Struckmanchange_euid(p, euid)
129165495Struckman	struct	proc *p;
129265495Struckman	uid_t	euid;
129365495Struckman{
129465495Struckman	struct	pcred *pc;
129565495Struckman	struct	uidinfo *uip;
129665495Struckman
129765495Struckman	pc = p->p_cred;
129865495Struckman	/*
129965495Struckman	 * crcopy is essentially a NOP if ucred has a reference count
130065495Struckman	 * of 1, which is true if it has already been copied.
130165495Struckman	 */
130265495Struckman	pc->pc_ucred = crcopy(pc->pc_ucred);
130365495Struckman	uip = pc->pc_ucred->cr_uidinfo;
130465495Struckman	pc->pc_ucred->cr_uid = euid;
130565495Struckman	pc->pc_ucred->cr_uidinfo = uifind(euid);
130665495Struckman	uifree(uip);
130765495Struckman}
130865495Struckman
130965495Struckman/*
131065495Struckman * Helper function to change the real uid of a process
131165495Struckman *
131265495Struckman * The per-uid process count for this process is transfered from
131365495Struckman * the old uid to the new uid.
131465495Struckman */
131567629Sgallatinvoid
131665495Struckmanchange_ruid(p, ruid)
131765495Struckman	struct	proc *p;
131865495Struckman	uid_t	ruid;
131965495Struckman{
132065495Struckman	struct	pcred *pc;
132165495Struckman	struct	uidinfo *uip;
132265495Struckman
132365495Struckman	pc = p->p_cred;
132465495Struckman	(void)chgproccnt(pc->p_uidinfo, -1, 0);
132565495Struckman	uip = pc->p_uidinfo;
132665495Struckman	/* It is assumed that pcred is not shared between processes */
132765495Struckman	pc->p_ruid = ruid;
132865495Struckman	pc->p_uidinfo = uifind(ruid);
132965495Struckman	(void)chgproccnt(pc->p_uidinfo, 1, 0);
133065495Struckman	uifree(uip);
133165495Struckman}
1332