kern_prot.c revision 80735
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 80735 2001-07-31 15:48:21Z rwatson $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
4631778Seivind#include "opt_compat.h"
4775426Srwatson#include "opt_global.h"
4831778Seivind
491541Srgrimes#include <sys/param.h>
5076166Smarkm#include <sys/systm.h>
511541Srgrimes#include <sys/acct.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
5476166Smarkm#include <sys/mutex.h>
551541Srgrimes#include <sys/proc.h>
5676166Smarkm#include <sys/sysproto.h>
571541Srgrimes#include <sys/malloc.h>
5831891Ssef#include <sys/pioctl.h>
5965495Struckman#include <sys/resourcevar.h>
6061287Srwatson#include <sys/sysctl.h>
6172786Srwatson#include <sys/jail.h>
621541Srgrimes
6330354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6430354Sphk
6580735SrwatsonSYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0,
6680735Srwatson    "Kernel security policy");
6780735Srwatson
6812221Sbde#ifndef _SYS_SYSPROTO_H_
6911332Sswallacestruct getpid_args {
701541Srgrimes	int	dummy;
711541Srgrimes};
7212221Sbde#endif
731541Srgrimes
7458717Sdillon/*
7570317Sjake * getpid - MP SAFE
7658717Sdillon */
7770317Sjake
781541Srgrimes/* ARGSUSED */
791549Srgrimesint
8030994Sphkgetpid(p, uap)
811541Srgrimes	struct proc *p;
8211332Sswallace	struct getpid_args *uap;
831541Srgrimes{
841541Srgrimes
8530994Sphk	p->p_retval[0] = p->p_pid;
861541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8774728Sjhb	PROC_LOCK(p);
8830994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
8974728Sjhb	PROC_UNLOCK(p);
901541Srgrimes#endif
911541Srgrimes	return (0);
921541Srgrimes}
931541Srgrimes
9470317Sjake/*
9570317Sjake * getppid - MP SAFE
9670317Sjake */
9770317Sjake
9812221Sbde#ifndef _SYS_SYSPROTO_H_
9911332Sswallacestruct getppid_args {
10011332Sswallace        int     dummy;
10111332Sswallace};
10212221Sbde#endif
1031541Srgrimes/* ARGSUSED */
1041549Srgrimesint
10530994Sphkgetppid(p, uap)
1061541Srgrimes	struct proc *p;
10711332Sswallace	struct getppid_args *uap;
1081541Srgrimes{
1091541Srgrimes
11074728Sjhb	PROC_LOCK(p);
11130994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
11274728Sjhb	PROC_UNLOCK(p);
1131541Srgrimes	return (0);
1141541Srgrimes}
1151541Srgrimes
11658717Sdillon/*
11758717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter
11858717Sdillon *
11958717Sdillon * MP SAFE
12058717Sdillon */
12112221Sbde#ifndef _SYS_SYSPROTO_H_
12211332Sswallacestruct getpgrp_args {
12311332Sswallace        int     dummy;
12411332Sswallace};
12512221Sbde#endif
12611332Sswallace
1271549Srgrimesint
12830994Sphkgetpgrp(p, uap)
1291541Srgrimes	struct proc *p;
13011332Sswallace	struct getpgrp_args *uap;
1311541Srgrimes{
1321541Srgrimes
13330994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1341541Srgrimes	return (0);
1351541Srgrimes}
1361541Srgrimes
13728401Speter/* Get an arbitary pid's process group id */
13812221Sbde#ifndef _SYS_SYSPROTO_H_
13928401Speterstruct getpgid_args {
14028401Speter	pid_t	pid;
14128401Speter};
14228401Speter#endif
14328401Speter
14428401Speterint
14530994Sphkgetpgid(p, uap)
14628401Speter	struct proc *p;
14728401Speter	struct getpgid_args *uap;
14828401Speter{
14941726Struckman	struct proc *pt;
15075448Srwatson	int error;
15141726Struckman
15228401Speter	if (uap->pid == 0)
15375893Sjhb		p->p_retval[0] = p->p_pgrp->pg_id;
15475893Sjhb	else {
15575893Sjhb		if ((pt = pfind(uap->pid)) == NULL)
15675893Sjhb			return ESRCH;
15779335Srwatson		if ((error = p_cansee(p, pt))) {
15875893Sjhb			PROC_UNLOCK(pt);
15975893Sjhb			return (error);
16075893Sjhb		}
16175893Sjhb		p->p_retval[0] = pt->p_pgrp->pg_id;
16275893Sjhb		PROC_UNLOCK(pt);
16375893Sjhb	}
16428401Speter	return 0;
16528401Speter}
16628401Speter
16728401Speter/*
16828401Speter * Get an arbitary pid's session id.
16928401Speter */
17028401Speter#ifndef _SYS_SYSPROTO_H_
17128401Speterstruct getsid_args {
17228401Speter	pid_t	pid;
17328401Speter};
17428401Speter#endif
17528401Speter
17628401Speterint
17730994Sphkgetsid(p, uap)
17828401Speter	struct proc *p;
17928401Speter	struct getsid_args *uap;
18028401Speter{
18141726Struckman	struct proc *pt;
18275448Srwatson	int error;
18341726Struckman
18428401Speter	if (uap->pid == 0)
18575893Sjhb		p->p_retval[0] = p->p_session->s_sid;
18675893Sjhb	else {
18775893Sjhb		if ((pt = pfind(uap->pid)) == NULL)
18875893Sjhb			return ESRCH;
18979335Srwatson		if ((error = p_cansee(p, pt))) {
19075893Sjhb			PROC_UNLOCK(pt);
19175893Sjhb			return (error);
19275893Sjhb		}
19375893Sjhb		p->p_retval[0] = pt->p_session->s_sid;
19475893Sjhb		PROC_UNLOCK(pt);
19575893Sjhb	}
19628401Speter	return 0;
19728401Speter}
19828401Speter
19928401Speter
20058941Sdillon/*
20158941Sdillon * getuid() - MP SAFE
20258941Sdillon */
20328401Speter#ifndef _SYS_SYSPROTO_H_
20411332Sswallacestruct getuid_args {
20511332Sswallace        int     dummy;
20611332Sswallace};
20712221Sbde#endif
20811332Sswallace
2091541Srgrimes/* ARGSUSED */
2101549Srgrimesint
21130994Sphkgetuid(p, uap)
2121541Srgrimes	struct proc *p;
21311332Sswallace	struct getuid_args *uap;
2141541Srgrimes{
2151541Srgrimes
21677183Srwatson	p->p_retval[0] = p->p_ucred->cr_ruid;
2171541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
21830994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
2191541Srgrimes#endif
2201541Srgrimes	return (0);
2211541Srgrimes}
2221541Srgrimes
22358941Sdillon/*
22458941Sdillon * geteuid() - MP SAFE
22558941Sdillon */
22612221Sbde#ifndef _SYS_SYSPROTO_H_
22711332Sswallacestruct geteuid_args {
22811332Sswallace        int     dummy;
22911332Sswallace};
23012221Sbde#endif
23111332Sswallace
2321541Srgrimes/* ARGSUSED */
2331549Srgrimesint
23430994Sphkgeteuid(p, uap)
2351541Srgrimes	struct proc *p;
23611332Sswallace	struct geteuid_args *uap;
2371541Srgrimes{
2381541Srgrimes
23930994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2401541Srgrimes	return (0);
2411541Srgrimes}
2421541Srgrimes
24358941Sdillon/*
24458941Sdillon * getgid() - MP SAFE
24558941Sdillon */
24612221Sbde#ifndef _SYS_SYSPROTO_H_
24711332Sswallacestruct getgid_args {
24811332Sswallace        int     dummy;
24911332Sswallace};
25012221Sbde#endif
25111332Sswallace
2521541Srgrimes/* ARGSUSED */
2531549Srgrimesint
25430994Sphkgetgid(p, uap)
2551541Srgrimes	struct proc *p;
25611332Sswallace	struct getgid_args *uap;
2571541Srgrimes{
2581541Srgrimes
25977183Srwatson	p->p_retval[0] = p->p_ucred->cr_rgid;
2601541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
26130994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2621541Srgrimes#endif
2631541Srgrimes	return (0);
2641541Srgrimes}
2651541Srgrimes
2661541Srgrimes/*
2671541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2681541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2691541Srgrimes * correctly in a library function.
2701541Srgrimes */
27112221Sbde#ifndef _SYS_SYSPROTO_H_
27211332Sswallacestruct getegid_args {
27311332Sswallace        int     dummy;
27411332Sswallace};
27512221Sbde#endif
27611332Sswallace
2771541Srgrimes/* ARGSUSED */
2781549Srgrimesint
27930994Sphkgetegid(p, uap)
2801541Srgrimes	struct proc *p;
28111332Sswallace	struct getegid_args *uap;
2821541Srgrimes{
2831541Srgrimes
28430994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2851541Srgrimes	return (0);
2861541Srgrimes}
2871541Srgrimes
28812221Sbde#ifndef _SYS_SYSPROTO_H_
2891541Srgrimesstruct getgroups_args {
2901541Srgrimes	u_int	gidsetsize;
2911541Srgrimes	gid_t	*gidset;
2921541Srgrimes};
29312221Sbde#endif
2941549Srgrimesint
29530994Sphkgetgroups(p, uap)
2961541Srgrimes	struct proc *p;
2971541Srgrimes	register struct	getgroups_args *uap;
2981541Srgrimes{
29977183Srwatson	struct ucred *cred = p->p_ucred;
30077183Srwatson	u_int ngrp;
3011541Srgrimes	int error;
3021541Srgrimes
3031541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
30477183Srwatson		p->p_retval[0] = cred->cr_ngroups;
3051541Srgrimes		return (0);
3061541Srgrimes	}
30777183Srwatson	if (ngrp < cred->cr_ngroups)
3081541Srgrimes		return (EINVAL);
30977183Srwatson	ngrp = cred->cr_ngroups;
31077183Srwatson	if ((error = copyout((caddr_t)cred->cr_groups,
3113098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
3121541Srgrimes		return (error);
31330994Sphk	p->p_retval[0] = ngrp;
3141541Srgrimes	return (0);
3151541Srgrimes}
3161541Srgrimes
31712221Sbde#ifndef _SYS_SYSPROTO_H_
31812207Sbdestruct setsid_args {
31911332Sswallace        int     dummy;
32011332Sswallace};
32112221Sbde#endif
32211332Sswallace
3231541Srgrimes/* ARGSUSED */
3241549Srgrimesint
32530994Sphksetsid(p, uap)
3261541Srgrimes	register struct proc *p;
32712207Sbde	struct setsid_args *uap;
3281541Srgrimes{
3291541Srgrimes
3301541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3311541Srgrimes		return (EPERM);
3321541Srgrimes	} else {
3331541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
33430994Sphk		p->p_retval[0] = p->p_pid;
3351541Srgrimes		return (0);
3361541Srgrimes	}
3371541Srgrimes}
3381541Srgrimes
3391541Srgrimes/*
3401541Srgrimes * set process group (setpgid/old setpgrp)
3411541Srgrimes *
3421541Srgrimes * caller does setpgid(targpid, targpgid)
3431541Srgrimes *
3441541Srgrimes * pid must be caller or child of caller (ESRCH)
3451541Srgrimes * if a child
3461541Srgrimes *	pid must be in same session (EPERM)
3471541Srgrimes *	pid can't have done an exec (EACCES)
3481541Srgrimes * if pgid != pid
3491541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3501541Srgrimes * pid must not be session leader (EPERM)
3511541Srgrimes */
35212221Sbde#ifndef _SYS_SYSPROTO_H_
3531541Srgrimesstruct setpgid_args {
3541541Srgrimes	int	pid;	/* target process id */
3551541Srgrimes	int	pgid;	/* target pgrp id */
3561541Srgrimes};
35712221Sbde#endif
3581541Srgrimes/* ARGSUSED */
3591549Srgrimesint
36030994Sphksetpgid(curp, uap)
3611541Srgrimes	struct proc *curp;
3621541Srgrimes	register struct setpgid_args *uap;
3631541Srgrimes{
3641541Srgrimes	register struct proc *targp;		/* target process */
3651541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
36675448Srwatson	int error;
3671541Srgrimes
36820677Sbde	if (uap->pgid < 0)
36920677Sbde		return (EINVAL);
3701541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
37175893Sjhb		if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
37275893Sjhb			if (targp)
37375893Sjhb				PROC_UNLOCK(targp);
3741541Srgrimes			return (ESRCH);
37575893Sjhb		}
37679335Srwatson		if ((error = p_cansee(curproc, targp))) {
37775893Sjhb			PROC_UNLOCK(targp);
37875448Srwatson			return (error);
37975893Sjhb		}
38075893Sjhb		if (targp->p_pgrp == NULL ||
38175893Sjhb		    targp->p_session != curp->p_session) {
38275893Sjhb			PROC_UNLOCK(targp);
3831541Srgrimes			return (EPERM);
38475893Sjhb		}
38575893Sjhb		if (targp->p_flag & P_EXEC) {
38675893Sjhb			PROC_UNLOCK(targp);
3871541Srgrimes			return (EACCES);
38875893Sjhb		}
38975893Sjhb	} else {
3901541Srgrimes		targp = curp;
39175893Sjhb		PROC_LOCK(curp);	/* XXX: not needed */
39275893Sjhb	}
39375893Sjhb	if (SESS_LEADER(targp)) {
39475893Sjhb		PROC_UNLOCK(targp);
3951541Srgrimes		return (EPERM);
39675893Sjhb	}
3971541Srgrimes	if (uap->pgid == 0)
3981541Srgrimes		uap->pgid = targp->p_pid;
3991541Srgrimes	else if (uap->pgid != targp->p_pid)
4001541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
40175893Sjhb	            pgrp->pg_session != curp->p_session) {
40275893Sjhb			PROC_UNLOCK(targp);
4031541Srgrimes			return (EPERM);
40475893Sjhb		}
40575893Sjhb	/* XXX: We should probably hold the lock across enterpgrp. */
40675893Sjhb	PROC_UNLOCK(targp);
4071541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
4081541Srgrimes}
4091541Srgrimes
41024448Speter/*
41124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
41272093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
41324448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
41424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
41524448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
41624448Speter * does not set the saved id - this is dangerous for traditional BSD
41724448Speter * programs.  For this reason, we *really* do not want to set
41824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
41924448Speter */
42024448Speter#define POSIX_APPENDIX_B_4_2_2
42124448Speter
42212221Sbde#ifndef _SYS_SYSPROTO_H_
4231541Srgrimesstruct setuid_args {
4241541Srgrimes	uid_t	uid;
4251541Srgrimes};
42612221Sbde#endif
4271541Srgrimes/* ARGSUSED */
4281549Srgrimesint
42930994Sphksetuid(p, uap)
4301541Srgrimes	struct proc *p;
4311541Srgrimes	struct setuid_args *uap;
4321541Srgrimes{
43377183Srwatson	struct ucred *newcred, *oldcred;
43477183Srwatson	uid_t uid;
4351541Srgrimes	int error;
4361541Srgrimes
43777183Srwatson	uid = uap->uid;
43877183Srwatson	oldcred = p->p_ucred;
43924448Speter	/*
44024448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
44124448Speter	 *
44224448Speter	 * Note that setuid(geteuid()) is a special case of
44324448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
44472093Sasmodai	 * to use this clause to be compatible with traditional BSD
44524448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
44624448Speter	 * three id's (assuming you have privs).
44724448Speter	 *
44824448Speter	 * Notes on the logic.  We do things in three steps.
44924448Speter	 * 1: We determine if the euid is going to change, and do EPERM
45024448Speter	 *    right away.  We unconditionally change the euid later if this
45124448Speter	 *    test is satisfied, simplifying that part of the logic.
45224448Speter	 * 2: We determine if the real and/or saved uid's are going to
45324448Speter	 *    change.  Determined by compile options.
45424448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
45524448Speter	 */
45677183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
45717994Sache#ifdef _POSIX_SAVED_IDS
45877183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
45917994Sache#endif
46024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
46177183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
46224448Speter#endif
46377183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
4641541Srgrimes		return (error);
46524448Speter
46677183Srwatson	newcred = crdup(oldcred);
46724448Speter#ifdef _POSIX_SAVED_IDS
4681541Srgrimes	/*
46924448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
47024448Speter	 * If so, we are changing the real uid and/or saved uid.
4711541Srgrimes	 */
47217994Sache	if (
47324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
47477183Srwatson	    uid == oldcred->cr_uid ||
47517994Sache#endif
47677183Srwatson	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
47717994Sache#endif
47824448Speter	{
47924448Speter		/*
48065495Struckman		 * Set the real uid and transfer proc count to new user.
48124448Speter		 */
48277183Srwatson		if (uid != oldcred->cr_ruid) {
48377183Srwatson			change_ruid(newcred, uid);
48465495Struckman			setsugid(p);
48524448Speter		}
48624448Speter		/*
48724448Speter		 * Set saved uid
48824448Speter		 *
48924448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
49024448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
49124448Speter		 * is important that we should do this.
49224448Speter		 */
49377183Srwatson		if (uid != oldcred->cr_svuid) {
49477183Srwatson			change_svuid(newcred, uid);
49531891Ssef			setsugid(p);
49624448Speter		}
4978141Sache	}
49824448Speter
49924448Speter	/*
50024448Speter	 * In all permitted cases, we are changing the euid.
50124448Speter	 * Copy credentials so other references do not see our changes.
50224448Speter	 */
50377183Srwatson	if (uid != oldcred->cr_uid) {
50477183Srwatson		change_euid(newcred, uid);
50531891Ssef		setsugid(p);
50624448Speter	}
50777183Srwatson	p->p_ucred = newcred;
50877183Srwatson	crfree(oldcred);
5091541Srgrimes	return (0);
5101541Srgrimes}
5111541Srgrimes
51212221Sbde#ifndef _SYS_SYSPROTO_H_
5131541Srgrimesstruct seteuid_args {
5141541Srgrimes	uid_t	euid;
5151541Srgrimes};
51612221Sbde#endif
5171541Srgrimes/* ARGSUSED */
5181549Srgrimesint
51930994Sphkseteuid(p, uap)
5201541Srgrimes	struct proc *p;
5211541Srgrimes	struct seteuid_args *uap;
5221541Srgrimes{
52377183Srwatson	struct ucred *newcred, *oldcred;
52477183Srwatson	uid_t euid;
5251541Srgrimes	int error;
5261541Srgrimes
5271541Srgrimes	euid = uap->euid;
52877183Srwatson	oldcred = p->p_ucred;
52977183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
53077183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
53177183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
5321541Srgrimes		return (error);
5331541Srgrimes	/*
5341541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
5351541Srgrimes	 * not see our changes.
5361541Srgrimes	 */
53777183Srwatson	newcred = crdup(oldcred);
53877183Srwatson	if (oldcred->cr_uid != euid) {
53977183Srwatson		change_euid(newcred, euid);
54031891Ssef		setsugid(p);
54124449Speter	}
54277183Srwatson	p->p_ucred = newcred;
54377183Srwatson	crfree(oldcred);
5441541Srgrimes	return (0);
5451541Srgrimes}
5461541Srgrimes
54712221Sbde#ifndef _SYS_SYSPROTO_H_
5481541Srgrimesstruct setgid_args {
5491541Srgrimes	gid_t	gid;
5501541Srgrimes};
55112221Sbde#endif
5521541Srgrimes/* ARGSUSED */
5531549Srgrimesint
55430994Sphksetgid(p, uap)
5551541Srgrimes	struct proc *p;
5561541Srgrimes	struct setgid_args *uap;
5571541Srgrimes{
55877183Srwatson	struct ucred *newcred, *oldcred;
55977183Srwatson	gid_t gid;
5601541Srgrimes	int error;
5611541Srgrimes
56277183Srwatson	gid = uap->gid;
56377183Srwatson	oldcred = p->p_ucred;
56424448Speter	/*
56524448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
56624448Speter	 *
56724448Speter	 * Note that setgid(getegid()) is a special case of
56824448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
56972093Sasmodai	 * to use this clause to be compatible with traditional BSD
57024448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
57124448Speter	 * three id's (assuming you have privs).
57224448Speter	 *
57324448Speter	 * For notes on the logic here, see setuid() above.
57424448Speter	 */
57577183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
57617994Sache#ifdef _POSIX_SAVED_IDS
57777183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
57817994Sache#endif
57924448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
58077183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
58124448Speter#endif
58277183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
5831541Srgrimes		return (error);
58424448Speter
58577183Srwatson	newcred = crdup(oldcred);
58617994Sache#ifdef _POSIX_SAVED_IDS
58724448Speter	/*
58824448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
58924448Speter	 * If so, we are changing the real uid and saved gid.
59024448Speter	 */
59124448Speter	if (
59224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
59377183Srwatson	    gid == oldcred->cr_groups[0] ||
59417994Sache#endif
59577183Srwatson	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
59624448Speter#endif
59724448Speter	{
59824448Speter		/*
59924448Speter		 * Set real gid
60024448Speter		 */
60177183Srwatson		if (oldcred->cr_rgid != gid) {
60277183Srwatson			change_rgid(newcred, gid);
60331891Ssef			setsugid(p);
60424448Speter		}
60524448Speter		/*
60624448Speter		 * Set saved gid
60724448Speter		 *
60824448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
60924448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
61024448Speter		 * is important that we should do this.
61124448Speter		 */
61277183Srwatson		if (oldcred->cr_svgid != gid) {
61377183Srwatson			change_svgid(newcred, gid);
61431891Ssef			setsugid(p);
61524448Speter		}
6168141Sache	}
61724448Speter	/*
61824448Speter	 * In all cases permitted cases, we are changing the egid.
61924448Speter	 * Copy credentials so other references do not see our changes.
62024448Speter	 */
62177183Srwatson	if (oldcred->cr_groups[0] != gid) {
62277183Srwatson		change_egid(newcred, gid);
62331891Ssef		setsugid(p);
62424448Speter	}
62577183Srwatson	p->p_ucred = newcred;
62677183Srwatson	crfree(oldcred);
6271541Srgrimes	return (0);
6281541Srgrimes}
6291541Srgrimes
63012221Sbde#ifndef _SYS_SYSPROTO_H_
6311541Srgrimesstruct setegid_args {
6321541Srgrimes	gid_t	egid;
6331541Srgrimes};
63412221Sbde#endif
6351541Srgrimes/* ARGSUSED */
6361549Srgrimesint
63730994Sphksetegid(p, uap)
6381541Srgrimes	struct proc *p;
6391541Srgrimes	struct setegid_args *uap;
6401541Srgrimes{
64177183Srwatson	struct ucred *newcred, *oldcred;
64277183Srwatson	gid_t egid;
6431541Srgrimes	int error;
6441541Srgrimes
6451541Srgrimes	egid = uap->egid;
64677183Srwatson	oldcred = p->p_ucred;
64777183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
64877183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
64977183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
6501541Srgrimes		return (error);
65177183Srwatson	newcred = crdup(oldcred);
65277183Srwatson	if (oldcred->cr_groups[0] != egid) {
65377183Srwatson		change_egid(newcred, egid);
65431891Ssef		setsugid(p);
65524449Speter	}
65677183Srwatson	p->p_ucred = newcred;
65777183Srwatson	crfree(oldcred);
6581541Srgrimes	return (0);
6591541Srgrimes}
6601541Srgrimes
66112221Sbde#ifndef _SYS_SYSPROTO_H_
6621541Srgrimesstruct setgroups_args {
6631541Srgrimes	u_int	gidsetsize;
6641541Srgrimes	gid_t	*gidset;
6651541Srgrimes};
66612221Sbde#endif
6671541Srgrimes/* ARGSUSED */
6681549Srgrimesint
66930994Sphksetgroups(p, uap)
6701541Srgrimes	struct proc *p;
6711541Srgrimes	struct setgroups_args *uap;
6721541Srgrimes{
67377183Srwatson	struct ucred *newcred, *oldcred;
67477183Srwatson	u_int ngrp;
6751541Srgrimes	int error;
6761541Srgrimes
67777183Srwatson	ngrp = uap->gidsetsize;
67877183Srwatson	oldcred = p->p_ucred;
67977183Srwatson	if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
6801541Srgrimes		return (error);
68124447Speter	if (ngrp > NGROUPS)
6821541Srgrimes		return (EINVAL);
68324447Speter	/*
68424447Speter	 * XXX A little bit lazy here.  We could test if anything has
68524447Speter	 * changed before crcopy() and setting P_SUGID.
68624447Speter	 */
68777183Srwatson	newcred = crdup(oldcred);
68824447Speter	if (ngrp < 1) {
68924447Speter		/*
69024447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
69124447Speter		 * groups vector on non-BSD systems (which generally do not
69224447Speter		 * have the egid in the groups[0]).  We risk security holes
69324447Speter		 * when running non-BSD software if we do not do the same.
69424447Speter		 */
69577183Srwatson		newcred->cr_ngroups = 1;
69624447Speter	} else {
69724447Speter		if ((error = copyin((caddr_t)uap->gidset,
69877183Srwatson		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
69977183Srwatson			crfree(newcred);
70024447Speter			return (error);
70177183Srwatson		}
70277183Srwatson		newcred->cr_ngroups = ngrp;
70324447Speter	}
70431891Ssef	setsugid(p);
70577183Srwatson	p->p_ucred = newcred;
70677183Srwatson	crfree(oldcred);
7071541Srgrimes	return (0);
7081541Srgrimes}
7091541Srgrimes
71012221Sbde#ifndef _SYS_SYSPROTO_H_
7111541Srgrimesstruct setreuid_args {
7129238Sache	uid_t	ruid;
7139238Sache	uid_t	euid;
7141541Srgrimes};
71512221Sbde#endif
7161541Srgrimes/* ARGSUSED */
7171549Srgrimesint
71830994Sphksetreuid(p, uap)
7191541Srgrimes	register struct proc *p;
7201541Srgrimes	struct setreuid_args *uap;
7211541Srgrimes{
72277183Srwatson	struct ucred *newcred, *oldcred;
72377183Srwatson	uid_t ruid, euid;
7248135Sache	int error;
7251541Srgrimes
7269238Sache	ruid = uap->ruid;
7279238Sache	euid = uap->euid;
72877183Srwatson	oldcred = p->p_ucred;
72977183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
73077183Srwatson	      ruid != oldcred->cr_svuid) ||
73177183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
73277183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
73377183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
7348135Sache		return (error);
73577183Srwatson	newcred = crdup(oldcred);
73677183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
73777183Srwatson		change_euid(newcred, euid);
73831891Ssef		setsugid(p);
73924450Speter	}
74077183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
74177183Srwatson		change_ruid(newcred, ruid);
74231891Ssef		setsugid(p);
7438135Sache	}
74477183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
74577183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
74677183Srwatson		change_svuid(newcred, newcred->cr_uid);
74731891Ssef		setsugid(p);
74824450Speter	}
74977183Srwatson	p->p_ucred = newcred;
75077183Srwatson	crfree(oldcred);
7518135Sache	return (0);
7521541Srgrimes}
7531541Srgrimes
75412221Sbde#ifndef _SYS_SYSPROTO_H_
7551541Srgrimesstruct setregid_args {
7569238Sache	gid_t	rgid;
7579238Sache	gid_t	egid;
7581541Srgrimes};
75912221Sbde#endif
7601541Srgrimes/* ARGSUSED */
7611549Srgrimesint
76230994Sphksetregid(p, uap)
7631541Srgrimes	register struct proc *p;
7641541Srgrimes	struct setregid_args *uap;
7651541Srgrimes{
76677183Srwatson	struct ucred *newcred, *oldcred;
76777183Srwatson	gid_t rgid, egid;
7688135Sache	int error;
7691541Srgrimes
7709238Sache	rgid = uap->rgid;
7719238Sache	egid = uap->egid;
77277183Srwatson	oldcred = p->p_ucred;
77377183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
77477183Srwatson	    rgid != oldcred->cr_svgid) ||
77577183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
77677183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
77777183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
7788135Sache		return (error);
7799238Sache
78077183Srwatson	newcred = crdup(oldcred);
78177183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
78277183Srwatson		change_egid(newcred, egid);
78331891Ssef		setsugid(p);
78424450Speter	}
78577183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
78677183Srwatson		change_rgid(newcred, rgid);
78731891Ssef		setsugid(p);
78824450Speter	}
78977183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
79077183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
79177183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
79231891Ssef		setsugid(p);
79324450Speter	}
79477812Sru	p->p_ucred = newcred;
79577812Sru	crfree(oldcred);
7968135Sache	return (0);
7971541Srgrimes}
7981541Srgrimes
79956115Speter/*
80056115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
80156115Speter * saved uid is explicit.
80256115Speter */
80356115Speter
80424453Speter#ifndef _SYS_SYSPROTO_H_
80556115Speterstruct setresuid_args {
80656115Speter	uid_t	ruid;
80756115Speter	uid_t	euid;
80856115Speter	uid_t	suid;
80956115Speter};
81056115Speter#endif
81156115Speter/* ARGSUSED */
81256115Speterint
81356115Spetersetresuid(p, uap)
81456115Speter	register struct proc *p;
81556115Speter	struct setresuid_args *uap;
81656115Speter{
81777183Srwatson	struct ucred *newcred, *oldcred;
81877183Srwatson	uid_t ruid, euid, suid;
81956115Speter	int error;
82056115Speter
82156115Speter	ruid = uap->ruid;
82256115Speter	euid = uap->euid;
82356115Speter	suid = uap->suid;
82477183Srwatson	oldcred = p->p_ucred;
82577183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
82677183Srwatson	     ruid != oldcred->cr_svuid &&
82777183Srwatson	      ruid != oldcred->cr_uid) ||
82877183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
82977183Srwatson	    euid != oldcred->cr_svuid &&
83077183Srwatson	      euid != oldcred->cr_uid) ||
83177183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
83277183Srwatson	    suid != oldcred->cr_svuid &&
83377183Srwatson	      suid != oldcred->cr_uid)) &&
83477183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
83556115Speter		return (error);
83677183Srwatson
83777183Srwatson	newcred = crdup(oldcred);
83877183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
83977183Srwatson		change_euid(newcred, euid);
84056115Speter		setsugid(p);
84156115Speter	}
84277183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
84377183Srwatson		change_ruid(newcred, ruid);
84456115Speter		setsugid(p);
84556115Speter	}
84677183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
84777183Srwatson		change_svuid(newcred, suid);
84856115Speter		setsugid(p);
84956115Speter	}
85077183Srwatson	p->p_ucred = newcred;
85177183Srwatson	crfree(oldcred);
85256115Speter	return (0);
85356115Speter}
85456115Speter
85556115Speter/*
85656115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
85756115Speter * saved gid is explicit.
85856115Speter */
85956115Speter
86056115Speter#ifndef _SYS_SYSPROTO_H_
86156115Speterstruct setresgid_args {
86256115Speter	gid_t	rgid;
86356115Speter	gid_t	egid;
86456115Speter	gid_t	sgid;
86556115Speter};
86656115Speter#endif
86756115Speter/* ARGSUSED */
86856115Speterint
86956115Spetersetresgid(p, uap)
87056115Speter	register struct proc *p;
87156115Speter	struct setresgid_args *uap;
87256115Speter{
87377183Srwatson	struct ucred *newcred, *oldcred;
87477183Srwatson	gid_t rgid, egid, sgid;
87556115Speter	int error;
87656115Speter
87756115Speter	rgid = uap->rgid;
87856115Speter	egid = uap->egid;
87956115Speter	sgid = uap->sgid;
88077183Srwatson	oldcred = p->p_ucred;
88177183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
88277183Srwatson	      rgid != oldcred->cr_svgid &&
88377183Srwatson	      rgid != oldcred->cr_groups[0]) ||
88477183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
88577183Srwatson	      egid != oldcred->cr_svgid &&
88677183Srwatson	      egid != oldcred->cr_groups[0]) ||
88777183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
88877183Srwatson	      sgid != oldcred->cr_svgid &&
88977183Srwatson	      sgid != oldcred->cr_groups[0])) &&
89077183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
89156115Speter		return (error);
89256115Speter
89377183Srwatson	newcred = crdup(oldcred);
89477183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
89577183Srwatson		change_egid(newcred, egid);
89656115Speter		setsugid(p);
89756115Speter	}
89877183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
89977183Srwatson		change_rgid(newcred, rgid);
90056115Speter		setsugid(p);
90156115Speter	}
90277183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
90377183Srwatson		change_svgid(newcred, sgid);
90456115Speter		setsugid(p);
90556115Speter	}
90677183Srwatson	p->p_ucred = newcred;
90777183Srwatson	crfree(oldcred);
90856115Speter	return (0);
90956115Speter}
91056115Speter
91156115Speter#ifndef _SYS_SYSPROTO_H_
91256115Speterstruct getresuid_args {
91356115Speter	uid_t	*ruid;
91456115Speter	uid_t	*euid;
91556115Speter	uid_t	*suid;
91656115Speter};
91756115Speter#endif
91856115Speter/* ARGSUSED */
91956115Speterint
92056115Spetergetresuid(p, uap)
92156115Speter	register struct proc *p;
92256115Speter	struct getresuid_args *uap;
92356115Speter{
92477183Srwatson	struct ucred *cred = p->p_ucred;
92556115Speter	int error1 = 0, error2 = 0, error3 = 0;
92656115Speter
92756115Speter	if (uap->ruid)
92877183Srwatson		error1 = copyout((caddr_t)&cred->cr_ruid,
92977183Srwatson		    (caddr_t)uap->ruid, sizeof(cred->cr_ruid));
93056115Speter	if (uap->euid)
93177183Srwatson		error2 = copyout((caddr_t)&cred->cr_uid,
93277183Srwatson		    (caddr_t)uap->euid, sizeof(cred->cr_uid));
93356115Speter	if (uap->suid)
93477183Srwatson		error3 = copyout((caddr_t)&cred->cr_svuid,
93577183Srwatson		    (caddr_t)uap->suid, sizeof(cred->cr_svuid));
93656115Speter	return error1 ? error1 : (error2 ? error2 : error3);
93756115Speter}
93856115Speter
93956115Speter#ifndef _SYS_SYSPROTO_H_
94056115Speterstruct getresgid_args {
94156115Speter	gid_t	*rgid;
94256115Speter	gid_t	*egid;
94356115Speter	gid_t	*sgid;
94456115Speter};
94556115Speter#endif
94656115Speter/* ARGSUSED */
94756115Speterint
94856115Spetergetresgid(p, uap)
94956115Speter	register struct proc *p;
95056115Speter	struct getresgid_args *uap;
95156115Speter{
95277183Srwatson	struct ucred *cred = p->p_ucred;
95356115Speter	int error1 = 0, error2 = 0, error3 = 0;
95456115Speter
95556115Speter	if (uap->rgid)
95677183Srwatson		error1 = copyout((caddr_t)&cred->cr_rgid,
95777183Srwatson		    (caddr_t)uap->rgid, sizeof(cred->cr_rgid));
95856115Speter	if (uap->egid)
95977183Srwatson		error2 = copyout((caddr_t)&cred->cr_groups[0],
96077183Srwatson		    (caddr_t)uap->egid, sizeof(cred->cr_groups[0]));
96156115Speter	if (uap->sgid)
96277183Srwatson		error3 = copyout((caddr_t)&cred->cr_svgid,
96377183Srwatson		    (caddr_t)uap->sgid, sizeof(cred->cr_svgid));
96456115Speter	return error1 ? error1 : (error2 ? error2 : error3);
96556115Speter}
96656115Speter
96756115Speter
96856115Speter#ifndef _SYS_SYSPROTO_H_
96924453Speterstruct issetugid_args {
97024453Speter	int dummy;
97124453Speter};
97224453Speter#endif
97324453Speter/* ARGSUSED */
97424453Speterint
97530994Sphkissetugid(p, uap)
97624453Speter	register struct proc *p;
97724453Speter	struct issetugid_args *uap;
97824453Speter{
97924453Speter	/*
98024453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
98124453Speter	 * we use P_SUGID because we consider changing the owners as
98224453Speter	 * "tainting" as well.
98324453Speter	 * This is significant for procs that start as root and "become"
98424453Speter	 * a user without an exec - programs cannot know *everything*
98524453Speter	 * that libc *might* have put in their data segment.
98624453Speter	 */
98760216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
98824453Speter	return (0);
98924453Speter}
99024453Speter
99175426Srwatsonint
99275426Srwatson__setugid(p, uap)
99375426Srwatson	struct proc *p;
99475426Srwatson	struct __setugid_args *uap;
99575426Srwatson{
99675426Srwatson
99775426Srwatson#ifdef REGRESSION
99875426Srwatson	switch (uap->flag) {
99975426Srwatson	case 0:
100075426Srwatson		p->p_flag &= ~P_SUGID;
100175426Srwatson		return (0);
100275426Srwatson	case 1:
100375426Srwatson		p->p_flag |= P_SUGID;
100475426Srwatson		return (0);
100575426Srwatson	default:
100675426Srwatson		return (EINVAL);
100775426Srwatson	}
100875426Srwatson#else /* !REGRESSION */
100975426Srwatson	return (ENOSYS);
101075426Srwatson#endif /* !REGRESSION */
101175426Srwatson}
101275426Srwatson
10131541Srgrimes/*
10141541Srgrimes * Check if gid is a member of the group set.
10151541Srgrimes */
10161549Srgrimesint
10171541Srgrimesgroupmember(gid, cred)
10181541Srgrimes	gid_t gid;
101977183Srwatson	struct ucred *cred;
10201541Srgrimes{
10211541Srgrimes	register gid_t *gp;
10221541Srgrimes	gid_t *egp;
10231541Srgrimes
10241541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
10251541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
10261541Srgrimes		if (*gp == gid)
10271541Srgrimes			return (1);
10281541Srgrimes	return (0);
10291541Srgrimes}
10301541Srgrimes
103161287Srwatsonstatic int suser_permitted = 1;
103261287Srwatson
103380735SrwatsonSYSCTL_INT(_kern_security, OID_AUTO, suser_permitted, CTLFLAG_RW,
103480735Srwatson    &suser_permitted, 0, "processes with uid 0 have privilege");
103561287Srwatson
10361541Srgrimes/*
10371541Srgrimes * Test whether the specified credentials imply "super-user"
10381541Srgrimes * privilege; if so, and we have accounting info, set the flag
10391541Srgrimes * indicating use of super-powers.
10401541Srgrimes * Returns 0 or error.
10411541Srgrimes */
10421549Srgrimesint
104346112Sphksuser(p)
104472786Srwatson	struct proc *p;
104546112Sphk{
104646155Sphk	return suser_xxx(0, p, 0);
104746112Sphk}
104846112Sphk
104946112Sphkint
105046155Sphksuser_xxx(cred, proc, flag)
105172786Srwatson	struct ucred *cred;
105272786Srwatson	struct proc *proc;
105346155Sphk	int flag;
10541541Srgrimes{
105561282Srwatson	if (!suser_permitted)
105661282Srwatson		return (EPERM);
105746155Sphk	if (!cred && !proc) {
105846155Sphk		printf("suser_xxx(): THINK!\n");
105946155Sphk		return (EPERM);
10601541Srgrimes	}
106146155Sphk	if (!cred)
106246155Sphk		cred = proc->p_ucred;
106346155Sphk	if (cred->cr_uid != 0)
106446155Sphk		return (EPERM);
106572786Srwatson	if (jailed(cred) && !(flag & PRISON_ROOT))
106646155Sphk		return (EPERM);
106746155Sphk	return (0);
10681541Srgrimes}
10691541Srgrimes
107074956Srwatson/*
107174956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2
107274956Srwatson * Arguments: imutable credentials u1, u2
107374956Srwatson * Returns: 0 for permitted, an errno value otherwise
107474956Srwatson * Locks: none
107574956Srwatson * References: u1 and u2 must be valid for the lifetime of the call
107674956Srwatson *             u1 may equal u2, in which case only one reference is required
107774956Srwatson */
107874956Srwatsonint
107974956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2)
108065237Srwatson{
108172786Srwatson	int error;
108253518Sphk
108374956Srwatson	if ((error = prison_check(u1, u2)))
108472786Srwatson		return (error);
108577183Srwatson	if (!ps_showallprocs && u1->cr_ruid != u2->cr_ruid) {
108675005Srwatson		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
108774956Srwatson			return (ESRCH);
108865293Srwatson	}
108965237Srwatson	return (0);
109065237Srwatson}
109165237Srwatson
109279335Srwatsonint
109379335Srwatsonp_cansee(struct proc *p1, struct proc *p2)
109474956Srwatson{
109574956Srwatson
109674956Srwatson	/* Wrap u_cansee() for all functionality. */
109774956Srwatson	return (u_cansee(p1->p_ucred, p2->p_ucred));
109874956Srwatson}
109974956Srwatson
110075437Srwatson/*
110175437Srwatson * Can process p1 send the signal signum to process p2?
110275437Srwatson */
110375437Srwatsonint
110475437Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum)
110553518Sphk{
110675437Srwatson	int	error;
110775437Srwatson
110853518Sphk	if (p1 == p2)
110953518Sphk		return (0);
111065237Srwatson
111175437Srwatson	/*
111275437Srwatson	 * Jail semantics limit the scope of signalling to p2 in the same
111375437Srwatson	 * jail as p1, if p1 is in jail.
111475437Srwatson	 */
111572786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
111672786Srwatson		return (error);
111765237Srwatson
111865237Srwatson	/*
111975437Srwatson	 * UNIX signalling semantics require that processes in the same
112075437Srwatson	 * session always be able to deliver SIGCONT to one another,
112175437Srwatson	 * overriding the remaining protections.
112265237Srwatson	 */
112375437Srwatson	if (signum == SIGCONT && p1->p_session == p2->p_session)
112453518Sphk		return (0);
112565237Srwatson
112675437Srwatson	/*
112775437Srwatson	 * UNIX uid semantics depend on the status of the P_SUGID
112875437Srwatson	 * bit on the target process.  If the bit is set, then more
112975437Srwatson	 * restricted signal sets are permitted.
113075437Srwatson	 */
113175437Srwatson	if (p2->p_flag & P_SUGID) {
113275437Srwatson		switch (signum) {
113375437Srwatson		case 0:
113475437Srwatson		case SIGKILL:
113575437Srwatson		case SIGINT:
113675437Srwatson		case SIGTERM:
113775437Srwatson		case SIGSTOP:
113875437Srwatson		case SIGTTIN:
113975437Srwatson		case SIGTTOU:
114075437Srwatson		case SIGTSTP:
114175437Srwatson		case SIGHUP:
114275437Srwatson		case SIGUSR1:
114375437Srwatson		case SIGUSR2:
114475437Srwatson			break;
114575437Srwatson		default:
114675437Srwatson			/* Not permitted, try privilege. */
114775437Srwatson			error = suser_xxx(NULL, p1, PRISON_ROOT);
114875437Srwatson			if (error)
114975437Srwatson				return (error);
115075437Srwatson		}
115165237Srwatson	}
115265237Srwatson
115375480Srwatson	/*
115475480Srwatson	 * Generally, the object credential's ruid or svuid must match the
115575480Srwatson	 * subject credential's ruid or euid.
115675480Srwatson	 */
115777183Srwatson	if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid &&
115877183Srwatson	    p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid &&
115977183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid &&
116077183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) {
116175480Srwatson		/* Not permitted, try privilege. */
116275480Srwatson		error = suser_xxx(NULL, p1, PRISON_ROOT);
116375480Srwatson		if (error)
116475480Srwatson			return (error);
116575480Srwatson	}
116675480Srwatson
116775437Srwatson        return (0);
116853518Sphk}
116953518Sphk
117079335Srwatsonint
117179335Srwatsonp_cansched(struct proc *p1, struct proc *p2)
117265237Srwatson{
117372786Srwatson	int error;
117465237Srwatson
117565237Srwatson	if (p1 == p2)
117665237Srwatson		return (0);
117765237Srwatson
117872786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
117972786Srwatson		return (error);
118065237Srwatson
118177183Srwatson	if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid)
118265237Srwatson		return (0);
118377183Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid)
118465237Srwatson		return (0);
118565237Srwatson
118679335Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT))
118765237Srwatson		return (0);
118865237Srwatson
118965237Srwatson#ifdef CAPABILITIES
119079335Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT))
119165237Srwatson		return (0);
119265237Srwatson#endif
119365237Srwatson
119465237Srwatson	return (EPERM);
119565237Srwatson}
119665237Srwatson
119780735Srwatsonstatic int	kern_unprivileged_procdebug_permitted = 1;
119880735SrwatsonSYSCTL_INT(_kern_security, OID_AUTO, unprivileged_procdebug_permitted,
119980735Srwatson    CTLFLAG_RW, &kern_unprivileged_procdebug_permitted, 0,
120080735Srwatson    "Unprivileged processes may use process debugging facilities");
120180735Srwatson
120279335Srwatsonint
120379335Srwatsonp_candebug(struct proc *p1, struct proc *p2)
120465237Srwatson{
120572786Srwatson	int error;
120665237Srwatson
120765237Srwatson	if (p1 == p2)
120865237Srwatson		return (0);
120965237Srwatson
121072786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
121172786Srwatson		return (error);
121265237Srwatson
121365237Srwatson	/* not owned by you, has done setuid (unless you're root) */
121465237Srwatson	/* add a CAP_SYS_PTRACE here? */
121577183Srwatson	if (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid ||
121677183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid ||
121777183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid ||
121880735Srwatson	    p2->p_flag & P_SUGID || !kern_unprivileged_procdebug_permitted)
121965237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
122065237Srwatson			return (error);
122165237Srwatson
122265237Srwatson	/* can't trace init when securelevel > 0 */
122365237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
122465237Srwatson		return (EPERM);
122565237Srwatson
122665237Srwatson	return (0);
122765237Srwatson}
122865237Srwatson
122953518Sphk/*
12301541Srgrimes * Allocate a zeroed cred structure.
12311541Srgrimes */
12321541Srgrimesstruct ucred *
12331541Srgrimescrget()
12341541Srgrimes{
12351541Srgrimes	register struct ucred *cr;
12361541Srgrimes
123769239Salfred	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
12381541Srgrimes	cr->cr_ref = 1;
123969239Salfred	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
12401541Srgrimes	return (cr);
12411541Srgrimes}
12421541Srgrimes
12431541Srgrimes/*
124472474Srwatson * Claim another reference to a ucred structure
124569401Salfred */
124669401Salfredvoid
124769401Salfredcrhold(cr)
124869401Salfred	struct ucred *cr;
124969401Salfred{
125069401Salfred
125172200Sbmilekic	mtx_lock(&cr->cr_mtx);
125269401Salfred	cr->cr_ref++;
125372200Sbmilekic	mtx_unlock(&(cr)->cr_mtx);
125469401Salfred}
125569401Salfred
125669401Salfred
125769401Salfred/*
12581541Srgrimes * Free a cred structure.
12591541Srgrimes * Throws away space when ref count gets to 0.
12601541Srgrimes */
12611549Srgrimesvoid
12621541Srgrimescrfree(cr)
12631541Srgrimes	struct ucred *cr;
12641541Srgrimes{
126569239Salfred
126672200Sbmilekic	mtx_lock(&cr->cr_mtx);
126775632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
126865495Struckman	if (--cr->cr_ref == 0) {
126969239Salfred		mtx_destroy(&cr->cr_mtx);
127065495Struckman		/*
127165495Struckman		 * Some callers of crget(), such as nfs_statfs(),
127265495Struckman		 * allocate a temporary credential, but don't
127365495Struckman		 * allocate a uidinfo structure.
127465495Struckman		 */
127565495Struckman		if (cr->cr_uidinfo != NULL)
127665495Struckman			uifree(cr->cr_uidinfo);
127777277Srwatson		if (cr->cr_ruidinfo != NULL)
127877277Srwatson			uifree(cr->cr_ruidinfo);
127972786Srwatson		/*
128072786Srwatson		 * Free a prison, if any.
128172786Srwatson		 */
128272786Srwatson		if (jailed(cr))
128372786Srwatson			prison_free(cr->cr_prison);
12841541Srgrimes		FREE((caddr_t)cr, M_CRED);
128569239Salfred	} else {
128672200Sbmilekic		mtx_unlock(&cr->cr_mtx);
128765495Struckman	}
12881541Srgrimes}
12891541Srgrimes
12901541Srgrimes/*
12911541Srgrimes * Copy cred structure to a new one and free the old one.
12921541Srgrimes */
12931541Srgrimesstruct ucred *
12941541Srgrimescrcopy(cr)
12951541Srgrimes	struct ucred *cr;
12961541Srgrimes{
12971541Srgrimes	struct ucred *newcr;
12981541Srgrimes
129972200Sbmilekic	mtx_lock(&cr->cr_mtx);
130069239Salfred	if (cr->cr_ref == 1) {
130172200Sbmilekic		mtx_unlock(&cr->cr_mtx);
13021541Srgrimes		return (cr);
130369239Salfred	}
130472200Sbmilekic	mtx_unlock(&cr->cr_mtx);
130569239Salfred	newcr = crdup(cr);
13061541Srgrimes	crfree(cr);
13071541Srgrimes	return (newcr);
13081541Srgrimes}
13091541Srgrimes
13101541Srgrimes/*
13111541Srgrimes * Dup cred struct to a new held one.
13121541Srgrimes */
13131541Srgrimesstruct ucred *
13141541Srgrimescrdup(cr)
13151541Srgrimes	struct ucred *cr;
13161541Srgrimes{
13171541Srgrimes	struct ucred *newcr;
13181541Srgrimes
131969239Salfred	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
13201541Srgrimes	*newcr = *cr;
132169239Salfred	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
132265495Struckman	uihold(newcr->cr_uidinfo);
132377183Srwatson	uihold(newcr->cr_ruidinfo);
132472786Srwatson	if (jailed(newcr))
132572786Srwatson		prison_hold(newcr->cr_prison);
13261541Srgrimes	newcr->cr_ref = 1;
13271541Srgrimes	return (newcr);
13281541Srgrimes}
13291541Srgrimes
13301541Srgrimes/*
13311541Srgrimes * Get login name, if available.
13321541Srgrimes */
133312221Sbde#ifndef _SYS_SYSPROTO_H_
13341541Srgrimesstruct getlogin_args {
13351541Srgrimes	char	*namebuf;
13361541Srgrimes	u_int	namelen;
13371541Srgrimes};
133812221Sbde#endif
13391541Srgrimes/* ARGSUSED */
13401549Srgrimesint
134130994Sphkgetlogin(p, uap)
13421541Srgrimes	struct proc *p;
13431541Srgrimes	struct getlogin_args *uap;
13441541Srgrimes{
13451541Srgrimes
134623358Sache	if (uap->namelen > MAXLOGNAME)
134723359Sache		uap->namelen = MAXLOGNAME;
13481541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
13491541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
13501541Srgrimes}
13511541Srgrimes
13521541Srgrimes/*
13531541Srgrimes * Set login name.
13541541Srgrimes */
135512221Sbde#ifndef _SYS_SYSPROTO_H_
13561541Srgrimesstruct setlogin_args {
13571541Srgrimes	char	*namebuf;
13581541Srgrimes};
135912221Sbde#endif
13601541Srgrimes/* ARGSUSED */
13611549Srgrimesint
136230994Sphksetlogin(p, uap)
13631541Srgrimes	struct proc *p;
13641541Srgrimes	struct setlogin_args *uap;
13651541Srgrimes{
13661541Srgrimes	int error;
136723330Sache	char logintmp[MAXLOGNAME];
13681541Srgrimes
136946155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
13701541Srgrimes		return (error);
137122522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
137236845Sdfr	    sizeof(logintmp), (size_t *)0);
13731541Srgrimes	if (error == ENAMETOOLONG)
13741541Srgrimes		error = EINVAL;
137522522Sdavidn	else if (!error)
137622522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
137723330Sache		    sizeof(logintmp));
13781541Srgrimes	return (error);
13791541Srgrimes}
138031891Ssef
138131891Ssefvoid
138231891Ssefsetsugid(p)
138355338Sphk	struct proc *p;
138431891Ssef{
138531891Ssef	p->p_flag |= P_SUGID;
138655707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
138731891Ssef		p->p_stops = 0;
138831891Ssef}
138965495Struckman
139065495Struckman/*
139177183Srwatson * change_euid(): Change a process's effective uid.
139277183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
139377183Srwatson * References: newcred must be an exclusive credential reference for the
139477183Srwatson *             duration of the call.
139565495Struckman */
139665495Struckmanvoid
139777183Srwatsonchange_euid(newcred, euid)
139877183Srwatson	struct ucred *newcred;
139977183Srwatson	uid_t euid;
140065495Struckman{
140165495Struckman
140277183Srwatson	newcred->cr_uid = euid;
140377183Srwatson	uifree(newcred->cr_uidinfo);
140477183Srwatson	newcred->cr_uidinfo = uifind(euid);
140565495Struckman}
140665495Struckman
140765495Struckman/*
140877183Srwatson * change_egid(): Change a process's effective gid.
140977183Srwatson * Side effects: newcred->cr_gid will be modified.
141077183Srwatson * References: newcred must be an exclusive credential reference for the
141177183Srwatson *             duration of the call.
141265495Struckman */
141367629Sgallatinvoid
141477183Srwatsonchange_egid(newcred, egid)
141577183Srwatson	struct ucred *newcred;
141677183Srwatson	gid_t egid;
141765495Struckman{
141865495Struckman
141977183Srwatson	newcred->cr_groups[0] = egid;
142065495Struckman}
142177183Srwatson
142277183Srwatson/*
142377183Srwatson * change_ruid(): Change a process's real uid.
142477183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
142577183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
142677183Srwatson *               counts will be updated.
142777183Srwatson * References: newcred must be an exclusive credential reference for the
142877183Srwatson *             duration of the call.
142977183Srwatson */
143077183Srwatsonvoid
143177183Srwatsonchange_ruid(newcred, ruid)
143277183Srwatson	struct ucred *newcred;
143377183Srwatson	uid_t ruid;
143477183Srwatson{
143577183Srwatson
143677183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
143777183Srwatson	newcred->cr_ruid = ruid;
143877183Srwatson	uifree(newcred->cr_ruidinfo);
143977183Srwatson	newcred->cr_ruidinfo = uifind(ruid);
144077183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
144177183Srwatson}
144277183Srwatson
144377183Srwatson/*
144477183Srwatson * change_rgid(): Change a process's real gid.
144577183Srwatson * Side effects: newcred->cr_rgid will be updated.
144677183Srwatson * References: newcred must be an exclusive credential reference for the
144777183Srwatson *             duration of the call.
144877183Srwatson */
144977183Srwatsonvoid
145077183Srwatsonchange_rgid(newcred, rgid)
145177183Srwatson	struct ucred *newcred;
145277183Srwatson	gid_t rgid;
145377183Srwatson{
145477183Srwatson
145577183Srwatson	newcred->cr_rgid = rgid;
145677183Srwatson}
145777183Srwatson
145877183Srwatson/*
145977183Srwatson * change_svuid(): Change a process's saved uid.
146077183Srwatson * Side effects: newcred->cr_svuid will be updated.
146177183Srwatson * References: newcred must be an exclusive credential reference for the
146277183Srwatson *             duration of the call.
146377183Srwatson */
146477183Srwatsonvoid
146577183Srwatsonchange_svuid(newcred, svuid)
146677183Srwatson	struct ucred *newcred;
146777183Srwatson	uid_t svuid;
146877183Srwatson{
146977183Srwatson
147077183Srwatson	newcred->cr_svuid = svuid;
147177183Srwatson}
147277183Srwatson
147377183Srwatson/*
147477183Srwatson * change_svgid(): Change a process's saved gid.
147577183Srwatson * Side effects: newcred->cr_svgid will be updated.
147677183Srwatson * References: newcred must be an exclusive credential reference for the
147777183Srwatson *             duration of the call.
147877183Srwatson */
147977183Srwatsonvoid
148077183Srwatsonchange_svgid(newcred, svgid)
148177183Srwatson	struct ucred *newcred;
148277183Srwatson	gid_t svgid;
148377183Srwatson{
148477183Srwatson
148577183Srwatson	newcred->cr_svgid = svgid;
148677183Srwatson}
1487