kern_prot.c revision 150634
1139804Simp/*-
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.
987218Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson.  All rights reserved.
101541Srgrimes *
111541Srgrimes * Redistribution and use in source and binary forms, with or without
121541Srgrimes * modification, are permitted provided that the following conditions
131541Srgrimes * are met:
141541Srgrimes * 1. Redistributions of source code must retain the above copyright
151541Srgrimes *    notice, this list of conditions and the following disclaimer.
161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer in the
181541Srgrimes *    documentation and/or other materials provided with the distribution.
191541Srgrimes * 4. Neither the name of the University nor the names of its contributors
201541Srgrimes *    may be used to endorse or promote products derived from this software
211541Srgrimes *    without specific prior written permission.
221541Srgrimes *
231541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
241541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
251541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
261541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
271541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
281541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
301541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
311541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
321541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
331541Srgrimes * SUCH DAMAGE.
341541Srgrimes *
351541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
361541Srgrimes */
371541Srgrimes
381541Srgrimes/*
391541Srgrimes * System calls related to processes and protection
401541Srgrimes */
411541Srgrimes
42116182Sobrien#include <sys/cdefs.h>
43116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_prot.c 150634 2005-09-27 18:09:42Z jhb $");
44116182Sobrien
4531778Seivind#include "opt_compat.h"
46101001Srwatson#include "opt_mac.h"
4731778Seivind
481541Srgrimes#include <sys/param.h>
4976166Smarkm#include <sys/systm.h>
501541Srgrimes#include <sys/acct.h>
51132548Srwatson#include <sys/kdb.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
54101173Srwatson#include <sys/mac.h>
5591140Stanimura#include <sys/malloc.h>
5676166Smarkm#include <sys/mutex.h>
57150634Sjhb#include <sys/refcount.h>
5891140Stanimura#include <sys/sx.h>
591541Srgrimes#include <sys/proc.h>
6076166Smarkm#include <sys/sysproto.h>
6187218Srwatson#include <sys/jail.h>
6231891Ssef#include <sys/pioctl.h>
6365495Struckman#include <sys/resourcevar.h>
6492976Srwatson#include <sys/socket.h>
6592976Srwatson#include <sys/socketvar.h>
6661287Srwatson#include <sys/sysctl.h>
671541Srgrimes
6830354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6930354Sphk
7089414SarrSYSCTL_DECL(_security);
7189414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0,
7287138Srwatson    "BSD security policy");
7387138Srwatson
7412221Sbde#ifndef _SYS_SYSPROTO_H_
7511332Sswallacestruct getpid_args {
761541Srgrimes	int	dummy;
771541Srgrimes};
7812221Sbde#endif
7958717Sdillon/*
8082749Sdillon * MPSAFE
8182749Sdillon */
821541Srgrimes/* ARGSUSED */
831549Srgrimesint
8493580Sjhbgetpid(struct thread *td, struct getpid_args *uap)
851541Srgrimes{
8683366Sjulian	struct proc *p = td->td_proc;
871541Srgrimes
8883366Sjulian	td->td_retval[0] = p->p_pid;
89130344Sphk#if defined(COMPAT_43)
9074728Sjhb	PROC_LOCK(p);
9183366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
9274728Sjhb	PROC_UNLOCK(p);
931541Srgrimes#endif
941541Srgrimes	return (0);
951541Srgrimes}
961541Srgrimes
9712221Sbde#ifndef _SYS_SYSPROTO_H_
9811332Sswallacestruct getppid_args {
9911332Sswallace        int     dummy;
10011332Sswallace};
10112221Sbde#endif
10282749Sdillon/*
10382749Sdillon * MPSAFE
10482749Sdillon */
1051541Srgrimes/* ARGSUSED */
1061549Srgrimesint
10793580Sjhbgetppid(struct thread *td, struct getppid_args *uap)
1081541Srgrimes{
10983366Sjulian	struct proc *p = td->td_proc;
1101541Srgrimes
11174728Sjhb	PROC_LOCK(p);
11283366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
11374728Sjhb	PROC_UNLOCK(p);
1141541Srgrimes	return (0);
1151541Srgrimes}
1161541Srgrimes
11787466Srwatson/*
11887218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
11958717Sdillon */
12012221Sbde#ifndef _SYS_SYSPROTO_H_
12111332Sswallacestruct getpgrp_args {
12211332Sswallace        int     dummy;
12311332Sswallace};
12412221Sbde#endif
12582749Sdillon/*
12682749Sdillon * MPSAFE
12782749Sdillon */
1281549Srgrimesint
12993580Sjhbgetpgrp(struct thread *td, struct getpgrp_args *uap)
1301541Srgrimes{
13183366Sjulian	struct proc *p = td->td_proc;
1321541Srgrimes
13391140Stanimura	PROC_LOCK(p);
13483366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
13591140Stanimura	PROC_UNLOCK(p);
1361541Srgrimes	return (0);
1371541Srgrimes}
1381541Srgrimes
13928401Speter/* Get an arbitary pid's process group id */
14012221Sbde#ifndef _SYS_SYSPROTO_H_
14128401Speterstruct getpgid_args {
14228401Speter	pid_t	pid;
14328401Speter};
14428401Speter#endif
14582749Sdillon/*
14682749Sdillon * MPSAFE
14782749Sdillon */
14828401Speterint
14993580Sjhbgetpgid(struct thread *td, struct getpgid_args *uap)
15028401Speter{
151114031Sjhb	struct proc *p;
15292985Sjhb	int error;
15341726Struckman
15491140Stanimura	if (uap->pid == 0) {
155114031Sjhb		p = td->td_proc;
15691140Stanimura		PROC_LOCK(p);
157114031Sjhb	} else {
158114031Sjhb		p = pfind(uap->pid);
159114031Sjhb		if (p == NULL)
160114031Sjhb			return (ESRCH);
161114031Sjhb		error = p_cansee(td, p);
162114031Sjhb		if (error) {
163114031Sjhb			PROC_UNLOCK(p);
164114031Sjhb			return (error);
165114031Sjhb		}
16675893Sjhb	}
167114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
168114031Sjhb	PROC_UNLOCK(p);
169114031Sjhb	return (0);
17028401Speter}
17128401Speter
17228401Speter/*
17328401Speter * Get an arbitary pid's session id.
17428401Speter */
17528401Speter#ifndef _SYS_SYSPROTO_H_
17628401Speterstruct getsid_args {
17728401Speter	pid_t	pid;
17828401Speter};
17928401Speter#endif
18082749Sdillon/*
18182749Sdillon * MPSAFE
18282749Sdillon */
18328401Speterint
18493580Sjhbgetsid(struct thread *td, struct getsid_args *uap)
18528401Speter{
186114031Sjhb	struct proc *p;
18787218Srwatson	int error;
18841726Struckman
18991140Stanimura	if (uap->pid == 0) {
190114031Sjhb		p = td->td_proc;
19191140Stanimura		PROC_LOCK(p);
192114031Sjhb	} else {
193114031Sjhb		p = pfind(uap->pid);
194114031Sjhb		if (p == NULL)
195114031Sjhb			return (ESRCH);
196114031Sjhb		error = p_cansee(td, p);
197114031Sjhb		if (error) {
198114031Sjhb			PROC_UNLOCK(p);
199114031Sjhb			return (error);
200114031Sjhb		}
20175893Sjhb	}
202114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
203114031Sjhb	PROC_UNLOCK(p);
204114031Sjhb	return (0);
20528401Speter}
20628401Speter
20728401Speter#ifndef _SYS_SYSPROTO_H_
20811332Sswallacestruct getuid_args {
20911332Sswallace        int     dummy;
21011332Sswallace};
21112221Sbde#endif
21282749Sdillon/*
21382749Sdillon * MPSAFE
21482749Sdillon */
2151541Srgrimes/* ARGSUSED */
2161549Srgrimesint
21793580Sjhbgetuid(struct thread *td, struct getuid_args *uap)
2181541Srgrimes{
2191541Srgrimes
22092987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
221130344Sphk#if defined(COMPAT_43)
22292987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2231541Srgrimes#endif
2241541Srgrimes	return (0);
2251541Srgrimes}
2261541Srgrimes
22712221Sbde#ifndef _SYS_SYSPROTO_H_
22811332Sswallacestruct geteuid_args {
22911332Sswallace        int     dummy;
23011332Sswallace};
23112221Sbde#endif
23287218Srwatson/*
23387218Srwatson * MPSAFE
23487218Srwatson */
2351541Srgrimes/* ARGSUSED */
2361549Srgrimesint
23793580Sjhbgeteuid(struct thread *td, struct geteuid_args *uap)
2381541Srgrimes{
23992987Sjhb
24092987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2411541Srgrimes	return (0);
2421541Srgrimes}
2431541Srgrimes
24412221Sbde#ifndef _SYS_SYSPROTO_H_
24511332Sswallacestruct getgid_args {
24611332Sswallace        int     dummy;
24711332Sswallace};
24812221Sbde#endif
24982749Sdillon/*
25082749Sdillon * MPSAFE
25182749Sdillon */
2521541Srgrimes/* ARGSUSED */
2531549Srgrimesint
25493580Sjhbgetgid(struct thread *td, struct getgid_args *uap)
2551541Srgrimes{
2561541Srgrimes
25792987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
258130344Sphk#if defined(COMPAT_43)
25992987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2601541Srgrimes#endif
2611541Srgrimes	return (0);
2621541Srgrimes}
2631541Srgrimes
2641541Srgrimes/*
2651541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2661541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2671541Srgrimes * correctly in a library function.
2681541Srgrimes */
26912221Sbde#ifndef _SYS_SYSPROTO_H_
27011332Sswallacestruct getegid_args {
27111332Sswallace        int     dummy;
27211332Sswallace};
27312221Sbde#endif
27482749Sdillon/*
27582749Sdillon * MPSAFE
27682749Sdillon */
2771541Srgrimes/* ARGSUSED */
2781549Srgrimesint
27993580Sjhbgetegid(struct thread *td, struct getegid_args *uap)
2801541Srgrimes{
2811541Srgrimes
28292987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2831541Srgrimes	return (0);
2841541Srgrimes}
2851541Srgrimes
28612221Sbde#ifndef _SYS_SYSPROTO_H_
2871541Srgrimesstruct getgroups_args {
2881541Srgrimes	u_int	gidsetsize;
2891541Srgrimes	gid_t	*gidset;
2901541Srgrimes};
29112221Sbde#endif
29282749Sdillon/*
29382749Sdillon * MPSAFE
29482749Sdillon */
2951549Srgrimesint
29693580Sjhbgetgroups(struct thread *td, register struct getgroups_args *uap)
2971541Srgrimes{
29882749Sdillon	struct ucred *cred;
29977183Srwatson	u_int ngrp;
30087218Srwatson	int error;
3011541Srgrimes
30292987Sjhb	cred = td->td_ucred;
3031541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
30483366Sjulian		td->td_retval[0] = cred->cr_ngroups;
30592987Sjhb		return (0);
3061541Srgrimes	}
30792987Sjhb	if (ngrp < cred->cr_ngroups)
30892987Sjhb		return (EINVAL);
30977183Srwatson	ngrp = cred->cr_ngroups;
31099009Salfred	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
31193264Sdillon	if (error == 0)
31293557Sjhb		td->td_retval[0] = ngrp;
31393264Sdillon	return (error);
3141541Srgrimes}
3151541Srgrimes
31612221Sbde#ifndef _SYS_SYSPROTO_H_
31712207Sbdestruct setsid_args {
31811332Sswallace        int     dummy;
31911332Sswallace};
32012221Sbde#endif
32182749Sdillon/*
32282749Sdillon * MPSAFE
32382749Sdillon */
3241541Srgrimes/* ARGSUSED */
3251549Srgrimesint
32693580Sjhbsetsid(register struct thread *td, struct setsid_args *uap)
3271541Srgrimes{
32891140Stanimura	struct pgrp *pgrp;
32982749Sdillon	int error;
33083366Sjulian	struct proc *p = td->td_proc;
33191140Stanimura	struct pgrp *newpgrp;
33291140Stanimura	struct session *newsess;
3331541Srgrimes
33491140Stanimura	error = 0;
33591140Stanimura	pgrp = NULL;
33691140Stanimura
337111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
338111119Simp	MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
33991140Stanimura
34094859Sjhb	sx_xlock(&proctree_lock);
34191140Stanimura
34291140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
34391140Stanimura		if (pgrp != NULL)
34491140Stanimura			PGRP_UNLOCK(pgrp);
34582749Sdillon		error = EPERM;
34691140Stanimura	} else {
34791140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
34883366Sjulian		td->td_retval[0] = p->p_pid;
34994859Sjhb		newpgrp = NULL;
35094859Sjhb		newsess = NULL;
3511541Srgrimes	}
35291140Stanimura
35394859Sjhb	sx_xunlock(&proctree_lock);
35491140Stanimura
35595973Stanimura	if (newpgrp != NULL)
35695973Stanimura		FREE(newpgrp, M_PGRP);
35795973Stanimura	if (newsess != NULL)
35895973Stanimura		FREE(newsess, M_SESSION);
35991140Stanimura
36094859Sjhb	return (error);
3611541Srgrimes}
3621541Srgrimes
3631541Srgrimes/*
3641541Srgrimes * set process group (setpgid/old setpgrp)
3651541Srgrimes *
3661541Srgrimes * caller does setpgid(targpid, targpgid)
3671541Srgrimes *
3681541Srgrimes * pid must be caller or child of caller (ESRCH)
3691541Srgrimes * if a child
3701541Srgrimes *	pid must be in same session (EPERM)
3711541Srgrimes *	pid can't have done an exec (EACCES)
3721541Srgrimes * if pgid != pid
3731541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3741541Srgrimes * pid must not be session leader (EPERM)
3751541Srgrimes */
37612221Sbde#ifndef _SYS_SYSPROTO_H_
3771541Srgrimesstruct setpgid_args {
37887218Srwatson	int	pid;		/* target process id */
37987218Srwatson	int	pgid;		/* target pgrp id */
3801541Srgrimes};
38112221Sbde#endif
38282749Sdillon/*
38382749Sdillon * MPSAFE
38482749Sdillon */
3851541Srgrimes/* ARGSUSED */
3861549Srgrimesint
38793580Sjhbsetpgid(struct thread *td, register struct setpgid_args *uap)
3881541Srgrimes{
38983366Sjulian	struct proc *curp = td->td_proc;
39087218Srwatson	register struct proc *targp;	/* target process */
39187218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
39275448Srwatson	int error;
39391140Stanimura	struct pgrp *newpgrp;
3941541Srgrimes
39520677Sbde	if (uap->pgid < 0)
39620677Sbde		return (EINVAL);
39791140Stanimura
39891140Stanimura	error = 0;
39991140Stanimura
400111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
40191140Stanimura
40294859Sjhb	sx_xlock(&proctree_lock);
4031541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
40491140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
40582749Sdillon			error = ESRCH;
40694859Sjhb			goto done;
40775893Sjhb		}
40891140Stanimura		if (!inferior(targp)) {
40991140Stanimura			PROC_UNLOCK(targp);
41091371Stanimura			error = ESRCH;
41194859Sjhb			goto done;
41291140Stanimura		}
413132568Srwatson		if ((error = p_cansee(td, targp))) {
41475893Sjhb			PROC_UNLOCK(targp);
41594859Sjhb			goto done;
41675893Sjhb		}
41775893Sjhb		if (targp->p_pgrp == NULL ||
41875893Sjhb		    targp->p_session != curp->p_session) {
41975893Sjhb			PROC_UNLOCK(targp);
42082749Sdillon			error = EPERM;
42194859Sjhb			goto done;
42275893Sjhb		}
42375893Sjhb		if (targp->p_flag & P_EXEC) {
42475893Sjhb			PROC_UNLOCK(targp);
42582749Sdillon			error = EACCES;
42694859Sjhb			goto done;
42775893Sjhb		}
42891140Stanimura		PROC_UNLOCK(targp);
42991140Stanimura	} else
4301541Srgrimes		targp = curp;
43175893Sjhb	if (SESS_LEADER(targp)) {
43282749Sdillon		error = EPERM;
43394859Sjhb		goto done;
43475893Sjhb	}
43587218Srwatson	if (uap->pgid == 0)
4361541Srgrimes		uap->pgid = targp->p_pid;
437117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
438117214Scognet		if (uap->pgid == targp->p_pid) {
439117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
440117214Scognet			    NULL);
441117214Scognet			if (error == 0)
442117214Scognet				newpgrp = NULL;
443117214Scognet		} else
444117214Scognet			error = EPERM;
44591140Stanimura	} else {
446117214Scognet		if (pgrp == targp->p_pgrp) {
447117214Scognet			PGRP_UNLOCK(pgrp);
44894859Sjhb			goto done;
44975893Sjhb		}
450117214Scognet		if (pgrp->pg_id != targp->p_pid &&
451117214Scognet		    pgrp->pg_session != curp->p_session) {
45291140Stanimura			PGRP_UNLOCK(pgrp);
453117214Scognet			error = EPERM;
45491140Stanimura			goto done;
45591140Stanimura		}
45691140Stanimura		PGRP_UNLOCK(pgrp);
45791140Stanimura		error = enterthispgrp(targp, pgrp);
45882749Sdillon	}
45991140Stanimuradone:
46094859Sjhb	sx_xunlock(&proctree_lock);
46194859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
46294859Sjhb	    ("setpgid failed and newpgrp is NULL"));
46395973Stanimura	if (newpgrp != NULL)
46491140Stanimura		FREE(newpgrp, M_PGRP);
46582749Sdillon	return (error);
4661541Srgrimes}
4671541Srgrimes
46824448Speter/*
46924448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
47072093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47124448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
47224448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
47324448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
47424448Speter * does not set the saved id - this is dangerous for traditional BSD
47524448Speter * programs.  For this reason, we *really* do not want to set
47624448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
47724448Speter */
47824448Speter#define POSIX_APPENDIX_B_4_2_2
47924448Speter
48012221Sbde#ifndef _SYS_SYSPROTO_H_
4811541Srgrimesstruct setuid_args {
4821541Srgrimes	uid_t	uid;
4831541Srgrimes};
48412221Sbde#endif
48582749Sdillon/*
48682749Sdillon * MPSAFE
48782749Sdillon */
4881541Srgrimes/* ARGSUSED */
4891549Srgrimesint
49093580Sjhbsetuid(struct thread *td, struct setuid_args *uap)
4911541Srgrimes{
49283366Sjulian	struct proc *p = td->td_proc;
49377183Srwatson	struct ucred *newcred, *oldcred;
49477183Srwatson	uid_t uid;
49598417Salfred	struct uidinfo *uip;
49687218Srwatson	int error;
4971541Srgrimes
49877183Srwatson	uid = uap->uid;
49994619Sjhb	newcred = crget();
50098417Salfred	uip = uifind(uid);
50194619Sjhb	PROC_LOCK(p);
50287219Srwatson	oldcred = p->p_ucred;
50387466Srwatson
504145147Srwatson#ifdef MAC
505145147Srwatson	error = mac_check_proc_setuid(p, oldcred, uid);
506145147Srwatson	if (error)
507145147Srwatson		goto fail;
508145147Srwatson#endif
509145147Srwatson
51024448Speter	/*
51124448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
51224448Speter	 *
51387218Srwatson	 * Note that setuid(geteuid()) is a special case of
51424448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
51572093Sasmodai	 * to use this clause to be compatible with traditional BSD
51624448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
51724448Speter	 * three id's (assuming you have privs).
51824448Speter	 *
51924448Speter	 * Notes on the logic.  We do things in three steps.
52024448Speter	 * 1: We determine if the euid is going to change, and do EPERM
52124448Speter	 *    right away.  We unconditionally change the euid later if this
52224448Speter	 *    test is satisfied, simplifying that part of the logic.
52387218Srwatson	 * 2: We determine if the real and/or saved uids are going to
52424448Speter	 *    change.  Determined by compile options.
52524448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
52624448Speter	 */
52777183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
52817994Sache#ifdef _POSIX_SAVED_IDS
52977183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
53017994Sache#endif
53124448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53277183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
53324448Speter#endif
534145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
535145147Srwatson		goto fail;
53624448Speter
53798417Salfred	/*
53898417Salfred	 * Copy credentials so other references do not see our changes.
53998417Salfred	 */
54094619Sjhb	crcopy(newcred, oldcred);
54124448Speter#ifdef _POSIX_SAVED_IDS
5421541Srgrimes	/*
54324448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
54424448Speter	 * If so, we are changing the real uid and/or saved uid.
5451541Srgrimes	 */
54617994Sache	if (
54724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
54877183Srwatson	    uid == oldcred->cr_uid ||
54917994Sache#endif
550132653Scperciva	    suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */
55117994Sache#endif
55224448Speter	{
55324448Speter		/*
55465495Struckman		 * Set the real uid and transfer proc count to new user.
55524448Speter		 */
55677183Srwatson		if (uid != oldcred->cr_ruid) {
55798417Salfred			change_ruid(newcred, uip);
55865495Struckman			setsugid(p);
55924448Speter		}
56024448Speter		/*
56124448Speter		 * Set saved uid
56224448Speter		 *
56324448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
56424448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
56524448Speter		 * is important that we should do this.
56624448Speter		 */
56777183Srwatson		if (uid != oldcred->cr_svuid) {
56877183Srwatson			change_svuid(newcred, uid);
56931891Ssef			setsugid(p);
57024448Speter		}
5718141Sache	}
57224448Speter
57324448Speter	/*
57424448Speter	 * In all permitted cases, we are changing the euid.
57524448Speter	 */
57677183Srwatson	if (uid != oldcred->cr_uid) {
57798417Salfred		change_euid(newcred, uip);
57831891Ssef		setsugid(p);
57924448Speter	}
58077183Srwatson	p->p_ucred = newcred;
58194619Sjhb	PROC_UNLOCK(p);
58298417Salfred	uifree(uip);
58377183Srwatson	crfree(oldcred);
58494619Sjhb	return (0);
585145147Srwatson
586145147Srwatsonfail:
587145147Srwatson	PROC_UNLOCK(p);
588145147Srwatson	uifree(uip);
589145147Srwatson	crfree(newcred);
590145147Srwatson	return (error);
5911541Srgrimes}
5921541Srgrimes
59312221Sbde#ifndef _SYS_SYSPROTO_H_
5941541Srgrimesstruct seteuid_args {
5951541Srgrimes	uid_t	euid;
5961541Srgrimes};
59712221Sbde#endif
59882749Sdillon/*
59982749Sdillon * MPSAFE
60082749Sdillon */
6011541Srgrimes/* ARGSUSED */
6021549Srgrimesint
60393580Sjhbseteuid(struct thread *td, struct seteuid_args *uap)
6041541Srgrimes{
60583366Sjulian	struct proc *p = td->td_proc;
60677183Srwatson	struct ucred *newcred, *oldcred;
60777183Srwatson	uid_t euid;
60898417Salfred	struct uidinfo *euip;
60987218Srwatson	int error;
6101541Srgrimes
6111541Srgrimes	euid = uap->euid;
61294619Sjhb	newcred = crget();
61398417Salfred	euip = uifind(euid);
61494619Sjhb	PROC_LOCK(p);
61577183Srwatson	oldcred = p->p_ucred;
616145147Srwatson
617145147Srwatson#ifdef MAC
618145147Srwatson	error = mac_check_proc_seteuid(p, oldcred, euid);
619145147Srwatson	if (error)
620145147Srwatson		goto fail;
621145147Srwatson#endif
622145147Srwatson
62377183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
62477183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
625145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
626145147Srwatson		goto fail;
627145147Srwatson
6281541Srgrimes	/*
6291541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
6301541Srgrimes	 * not see our changes.
6311541Srgrimes	 */
63294619Sjhb	crcopy(newcred, oldcred);
63377183Srwatson	if (oldcred->cr_uid != euid) {
63498417Salfred		change_euid(newcred, euip);
63531891Ssef		setsugid(p);
63624449Speter	}
63777183Srwatson	p->p_ucred = newcred;
63894619Sjhb	PROC_UNLOCK(p);
63998417Salfred	uifree(euip);
64077183Srwatson	crfree(oldcred);
64194619Sjhb	return (0);
642145147Srwatson
643145147Srwatsonfail:
644145147Srwatson	PROC_UNLOCK(p);
645145147Srwatson	uifree(euip);
646145147Srwatson	crfree(newcred);
647145147Srwatson	return (error);
6481541Srgrimes}
6491541Srgrimes
65012221Sbde#ifndef _SYS_SYSPROTO_H_
6511541Srgrimesstruct setgid_args {
6521541Srgrimes	gid_t	gid;
6531541Srgrimes};
65412221Sbde#endif
65582749Sdillon/*
65682749Sdillon * MPSAFE
65782749Sdillon */
6581541Srgrimes/* ARGSUSED */
6591549Srgrimesint
66093580Sjhbsetgid(struct thread *td, struct setgid_args *uap)
6611541Srgrimes{
66283366Sjulian	struct proc *p = td->td_proc;
66377183Srwatson	struct ucred *newcred, *oldcred;
66477183Srwatson	gid_t gid;
66587218Srwatson	int error;
6661541Srgrimes
66777183Srwatson	gid = uap->gid;
66894619Sjhb	newcred = crget();
66994619Sjhb	PROC_LOCK(p);
67077183Srwatson	oldcred = p->p_ucred;
67187466Srwatson
672145147Srwatson#ifdef MAC
673145147Srwatson	error = mac_check_proc_setgid(p, oldcred, gid);
674145147Srwatson	if (error)
675145147Srwatson		goto fail;
676145147Srwatson#endif
677145147Srwatson
67824448Speter	/*
67924448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
68024448Speter	 *
68124448Speter	 * Note that setgid(getegid()) is a special case of
68224448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
68372093Sasmodai	 * to use this clause to be compatible with traditional BSD
68424448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
68524448Speter	 * three id's (assuming you have privs).
68624448Speter	 *
68724448Speter	 * For notes on the logic here, see setuid() above.
68824448Speter	 */
68977183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
69017994Sache#ifdef _POSIX_SAVED_IDS
69177183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
69217994Sache#endif
69324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
69477183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
69524448Speter#endif
696145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
697145147Srwatson		goto fail;
69824448Speter
69994619Sjhb	crcopy(newcred, oldcred);
70017994Sache#ifdef _POSIX_SAVED_IDS
70124448Speter	/*
70224448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
70324448Speter	 * If so, we are changing the real uid and saved gid.
70424448Speter	 */
70524448Speter	if (
70624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
70777183Srwatson	    gid == oldcred->cr_groups[0] ||
70817994Sache#endif
709132653Scperciva	    suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */
71024448Speter#endif
71124448Speter	{
71224448Speter		/*
71324448Speter		 * Set real gid
71424448Speter		 */
71577183Srwatson		if (oldcred->cr_rgid != gid) {
71677183Srwatson			change_rgid(newcred, gid);
71731891Ssef			setsugid(p);
71824448Speter		}
71924448Speter		/*
72024448Speter		 * Set saved gid
72124448Speter		 *
72224448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
72324448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
72424448Speter		 * is important that we should do this.
72524448Speter		 */
72677183Srwatson		if (oldcred->cr_svgid != gid) {
72777183Srwatson			change_svgid(newcred, gid);
72831891Ssef			setsugid(p);
72924448Speter		}
7308141Sache	}
73124448Speter	/*
73224448Speter	 * In all cases permitted cases, we are changing the egid.
73324448Speter	 * Copy credentials so other references do not see our changes.
73424448Speter	 */
73577183Srwatson	if (oldcred->cr_groups[0] != gid) {
73677183Srwatson		change_egid(newcred, gid);
73731891Ssef		setsugid(p);
73824448Speter	}
73977183Srwatson	p->p_ucred = newcred;
74094619Sjhb	PROC_UNLOCK(p);
74177183Srwatson	crfree(oldcred);
74294619Sjhb	return (0);
743145147Srwatson
744145147Srwatsonfail:
745145147Srwatson	PROC_UNLOCK(p);
746145147Srwatson	crfree(newcred);
747145147Srwatson	return (error);
7481541Srgrimes}
7491541Srgrimes
75012221Sbde#ifndef _SYS_SYSPROTO_H_
7511541Srgrimesstruct setegid_args {
7521541Srgrimes	gid_t	egid;
7531541Srgrimes};
75412221Sbde#endif
75582749Sdillon/*
75682749Sdillon * MPSAFE
75782749Sdillon */
7581541Srgrimes/* ARGSUSED */
7591549Srgrimesint
76093580Sjhbsetegid(struct thread *td, struct setegid_args *uap)
7611541Srgrimes{
76283366Sjulian	struct proc *p = td->td_proc;
76377183Srwatson	struct ucred *newcred, *oldcred;
76477183Srwatson	gid_t egid;
76587218Srwatson	int error;
7661541Srgrimes
7671541Srgrimes	egid = uap->egid;
76894619Sjhb	newcred = crget();
76994619Sjhb	PROC_LOCK(p);
77077183Srwatson	oldcred = p->p_ucred;
771145147Srwatson
772145147Srwatson#ifdef MAC
773145147Srwatson	error = mac_check_proc_setegid(p, oldcred, egid);
774145147Srwatson	if (error)
775145147Srwatson		goto fail;
776145147Srwatson#endif
777145147Srwatson
77877183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
77977183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
780145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
781145147Srwatson		goto fail;
782145147Srwatson
78394619Sjhb	crcopy(newcred, oldcred);
78477183Srwatson	if (oldcred->cr_groups[0] != egid) {
78577183Srwatson		change_egid(newcred, egid);
78631891Ssef		setsugid(p);
78724449Speter	}
78877183Srwatson	p->p_ucred = newcred;
78994619Sjhb	PROC_UNLOCK(p);
79077183Srwatson	crfree(oldcred);
79194619Sjhb	return (0);
792145147Srwatson
793145147Srwatsonfail:
794145147Srwatson	PROC_UNLOCK(p);
795145147Srwatson	crfree(newcred);
796145147Srwatson	return (error);
7971541Srgrimes}
7981541Srgrimes
79912221Sbde#ifndef _SYS_SYSPROTO_H_
8001541Srgrimesstruct setgroups_args {
8011541Srgrimes	u_int	gidsetsize;
8021541Srgrimes	gid_t	*gidset;
8031541Srgrimes};
80412221Sbde#endif
80582749Sdillon/*
80682749Sdillon * MPSAFE
80782749Sdillon */
8081541Srgrimes/* ARGSUSED */
8091549Srgrimesint
81093580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap)
8111541Srgrimes{
81283366Sjulian	struct proc *p = td->td_proc;
81394619Sjhb	struct ucred *newcred, *tempcred, *oldcred;
81477183Srwatson	u_int ngrp;
8151541Srgrimes	int error;
8161541Srgrimes
81787220Srwatson	ngrp = uap->gidsetsize;
81894619Sjhb	if (ngrp > NGROUPS)
81994619Sjhb		return (EINVAL);
82094619Sjhb	tempcred = crget();
82199009Salfred	error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t));
82294619Sjhb	if (error != 0) {
82394619Sjhb		crfree(tempcred);
82494619Sjhb		return (error);
82594619Sjhb	}
82694619Sjhb	newcred = crget();
82794619Sjhb	PROC_LOCK(p);
82877183Srwatson	oldcred = p->p_ucred;
829145147Srwatson
830145147Srwatson#ifdef MAC
831145147Srwatson	error = mac_check_proc_setgroups(p, oldcred, ngrp,
832145147Srwatson	    tempcred->cr_groups);
833145147Srwatson	if (error)
834145147Srwatson		goto fail;
835145147Srwatson#endif
836145147Srwatson
837132653Scperciva	error = suser_cred(oldcred, SUSER_ALLOWJAIL);
838145147Srwatson	if (error)
839145147Srwatson		goto fail;
840145147Srwatson
84124447Speter	/*
84224447Speter	 * XXX A little bit lazy here.  We could test if anything has
84324447Speter	 * changed before crcopy() and setting P_SUGID.
84424447Speter	 */
84594619Sjhb	crcopy(newcred, oldcred);
84624447Speter	if (ngrp < 1) {
84724447Speter		/*
84824447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
84924447Speter		 * groups vector on non-BSD systems (which generally do not
85024447Speter		 * have the egid in the groups[0]).  We risk security holes
85124447Speter		 * when running non-BSD software if we do not do the same.
85224447Speter		 */
85377183Srwatson		newcred->cr_ngroups = 1;
85424447Speter	} else {
85594619Sjhb		bcopy(tempcred->cr_groups, newcred->cr_groups,
85694619Sjhb		    ngrp * sizeof(gid_t));
85777183Srwatson		newcred->cr_ngroups = ngrp;
85824447Speter	}
85931891Ssef	setsugid(p);
86077183Srwatson	p->p_ucred = newcred;
86194619Sjhb	PROC_UNLOCK(p);
86294619Sjhb	crfree(tempcred);
86377183Srwatson	crfree(oldcred);
86494619Sjhb	return (0);
865145147Srwatson
866145147Srwatsonfail:
867145147Srwatson	PROC_UNLOCK(p);
868145147Srwatson	crfree(newcred);
869145147Srwatson	crfree(tempcred);
870145147Srwatson	return (error);
8711541Srgrimes}
8721541Srgrimes
87312221Sbde#ifndef _SYS_SYSPROTO_H_
8741541Srgrimesstruct setreuid_args {
8759238Sache	uid_t	ruid;
8769238Sache	uid_t	euid;
8771541Srgrimes};
87812221Sbde#endif
87982749Sdillon/*
88082749Sdillon * MPSAFE
88182749Sdillon */
8821541Srgrimes/* ARGSUSED */
8831549Srgrimesint
88493580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap)
8851541Srgrimes{
88683366Sjulian	struct proc *p = td->td_proc;
88777183Srwatson	struct ucred *newcred, *oldcred;
88887218Srwatson	uid_t euid, ruid;
88998417Salfred	struct uidinfo *euip, *ruip;
89087218Srwatson	int error;
8911541Srgrimes
89287218Srwatson	euid = uap->euid;
8939238Sache	ruid = uap->ruid;
89494619Sjhb	newcred = crget();
89598417Salfred	euip = uifind(euid);
89698417Salfred	ruip = uifind(ruid);
89794619Sjhb	PROC_LOCK(p);
89877183Srwatson	oldcred = p->p_ucred;
899145147Srwatson
900145147Srwatson#ifdef MAC
901145147Srwatson	error = mac_check_proc_setreuid(p, oldcred, ruid, euid);
902145147Srwatson	if (error)
903145147Srwatson		goto fail;
904145147Srwatson#endif
905145147Srwatson
90677183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
90777183Srwatson	      ruid != oldcred->cr_svuid) ||
90877183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
90977183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
910145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
911145147Srwatson		goto fail;
912145147Srwatson
91394619Sjhb	crcopy(newcred, oldcred);
91477183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
91598417Salfred		change_euid(newcred, euip);
91631891Ssef		setsugid(p);
91724450Speter	}
91877183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
91998417Salfred		change_ruid(newcred, ruip);
92031891Ssef		setsugid(p);
9218135Sache	}
92277183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
92377183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
92477183Srwatson		change_svuid(newcred, newcred->cr_uid);
92531891Ssef		setsugid(p);
92624450Speter	}
92777183Srwatson	p->p_ucred = newcred;
92894619Sjhb	PROC_UNLOCK(p);
92998417Salfred	uifree(ruip);
93098417Salfred	uifree(euip);
93177183Srwatson	crfree(oldcred);
93294619Sjhb	return (0);
933145147Srwatson
934145147Srwatsonfail:
935145147Srwatson	PROC_UNLOCK(p);
936145147Srwatson	uifree(ruip);
937145147Srwatson	uifree(euip);
938145147Srwatson	crfree(newcred);
939145147Srwatson	return (error);
9401541Srgrimes}
9411541Srgrimes
94212221Sbde#ifndef _SYS_SYSPROTO_H_
9431541Srgrimesstruct setregid_args {
9449238Sache	gid_t	rgid;
9459238Sache	gid_t	egid;
9461541Srgrimes};
94712221Sbde#endif
94882749Sdillon/*
94982749Sdillon * MPSAFE
95082749Sdillon */
9511541Srgrimes/* ARGSUSED */
9521549Srgrimesint
95393580Sjhbsetregid(register struct thread *td, struct setregid_args *uap)
9541541Srgrimes{
95583366Sjulian	struct proc *p = td->td_proc;
95677183Srwatson	struct ucred *newcred, *oldcred;
95787218Srwatson	gid_t egid, rgid;
95887218Srwatson	int error;
9591541Srgrimes
96087218Srwatson	egid = uap->egid;
9619238Sache	rgid = uap->rgid;
96294619Sjhb	newcred = crget();
96394619Sjhb	PROC_LOCK(p);
96477183Srwatson	oldcred = p->p_ucred;
965145147Srwatson
966145147Srwatson#ifdef MAC
967145147Srwatson	error = mac_check_proc_setregid(p, oldcred, rgid, egid);
968145147Srwatson	if (error)
969145147Srwatson		goto fail;
970145147Srwatson#endif
971145147Srwatson
97277183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
97377183Srwatson	    rgid != oldcred->cr_svgid) ||
97477183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
97577183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
976145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
977145147Srwatson		goto fail;
97894619Sjhb
97994619Sjhb	crcopy(newcred, oldcred);
98077183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
98177183Srwatson		change_egid(newcred, egid);
98231891Ssef		setsugid(p);
98324450Speter	}
98477183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
98577183Srwatson		change_rgid(newcred, rgid);
98631891Ssef		setsugid(p);
98724450Speter	}
98877183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
98977183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
99077183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
99131891Ssef		setsugid(p);
99224450Speter	}
99377812Sru	p->p_ucred = newcred;
99494619Sjhb	PROC_UNLOCK(p);
99577812Sru	crfree(oldcred);
99694619Sjhb	return (0);
997145147Srwatson
998145147Srwatsonfail:
999145147Srwatson	PROC_UNLOCK(p);
1000145147Srwatson	crfree(newcred);
1001145147Srwatson	return (error);
10021541Srgrimes}
10031541Srgrimes
100456115Speter/*
100556115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
100656115Speter * saved uid is explicit.
100756115Speter */
100856115Speter
100924453Speter#ifndef _SYS_SYSPROTO_H_
101056115Speterstruct setresuid_args {
101156115Speter	uid_t	ruid;
101256115Speter	uid_t	euid;
101356115Speter	uid_t	suid;
101456115Speter};
101556115Speter#endif
101682749Sdillon/*
101782749Sdillon * MPSAFE
101882749Sdillon */
101956115Speter/* ARGSUSED */
102056115Speterint
102193580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap)
102256115Speter{
102383366Sjulian	struct proc *p = td->td_proc;
102477183Srwatson	struct ucred *newcred, *oldcred;
102587218Srwatson	uid_t euid, ruid, suid;
102698417Salfred	struct uidinfo *euip, *ruip;
102756115Speter	int error;
102856115Speter
102987218Srwatson	euid = uap->euid;
103056115Speter	ruid = uap->ruid;
103156115Speter	suid = uap->suid;
103294619Sjhb	newcred = crget();
103398417Salfred	euip = uifind(euid);
103498417Salfred	ruip = uifind(ruid);
103594619Sjhb	PROC_LOCK(p);
103677183Srwatson	oldcred = p->p_ucred;
1037145147Srwatson
1038145147Srwatson#ifdef MAC
1039145147Srwatson	error = mac_check_proc_setresuid(p, oldcred, ruid, euid, suid);
1040145147Srwatson	if (error)
1041145147Srwatson		goto fail;
1042145147Srwatson#endif
1043145147Srwatson
104477183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
104577183Srwatson	     ruid != oldcred->cr_svuid &&
104677183Srwatson	      ruid != oldcred->cr_uid) ||
104777183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
104877183Srwatson	    euid != oldcred->cr_svuid &&
104977183Srwatson	      euid != oldcred->cr_uid) ||
105077183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
105177183Srwatson	    suid != oldcred->cr_svuid &&
105277183Srwatson	      suid != oldcred->cr_uid)) &&
1053145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
1054145147Srwatson		goto fail;
105594619Sjhb
105694619Sjhb	crcopy(newcred, oldcred);
105777183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
105898417Salfred		change_euid(newcred, euip);
105956115Speter		setsugid(p);
106056115Speter	}
106177183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
106298417Salfred		change_ruid(newcred, ruip);
106356115Speter		setsugid(p);
106456115Speter	}
106577183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
106677183Srwatson		change_svuid(newcred, suid);
106756115Speter		setsugid(p);
106856115Speter	}
106977183Srwatson	p->p_ucred = newcred;
107094619Sjhb	PROC_UNLOCK(p);
107198417Salfred	uifree(ruip);
107298417Salfred	uifree(euip);
107377183Srwatson	crfree(oldcred);
107494619Sjhb	return (0);
1075145147Srwatson
1076145147Srwatsonfail:
1077145147Srwatson	PROC_UNLOCK(p);
1078145147Srwatson	uifree(ruip);
1079145147Srwatson	uifree(euip);
1080145147Srwatson	crfree(newcred);
1081145147Srwatson	return (error);
1082145147Srwatson
108356115Speter}
108456115Speter
108556115Speter/*
108656115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
108756115Speter * saved gid is explicit.
108856115Speter */
108956115Speter
109056115Speter#ifndef _SYS_SYSPROTO_H_
109156115Speterstruct setresgid_args {
109256115Speter	gid_t	rgid;
109356115Speter	gid_t	egid;
109456115Speter	gid_t	sgid;
109556115Speter};
109656115Speter#endif
109787466Srwatson/*
109882749Sdillon * MPSAFE
109982749Sdillon */
110056115Speter/* ARGSUSED */
110156115Speterint
110293580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap)
110356115Speter{
110483366Sjulian	struct proc *p = td->td_proc;
110577183Srwatson	struct ucred *newcred, *oldcred;
110687218Srwatson	gid_t egid, rgid, sgid;
110756115Speter	int error;
110856115Speter
110987218Srwatson	egid = uap->egid;
111056115Speter	rgid = uap->rgid;
111156115Speter	sgid = uap->sgid;
111294619Sjhb	newcred = crget();
111394619Sjhb	PROC_LOCK(p);
111477183Srwatson	oldcred = p->p_ucred;
1115145147Srwatson
1116145147Srwatson#ifdef MAC
1117145147Srwatson	error = mac_check_proc_setresgid(p, oldcred, rgid, egid, sgid);
1118145147Srwatson	if (error)
1119145147Srwatson		goto fail;
1120145147Srwatson#endif
1121145147Srwatson
112277183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
112377183Srwatson	      rgid != oldcred->cr_svgid &&
112477183Srwatson	      rgid != oldcred->cr_groups[0]) ||
112577183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
112677183Srwatson	      egid != oldcred->cr_svgid &&
112777183Srwatson	      egid != oldcred->cr_groups[0]) ||
112877183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
112977183Srwatson	      sgid != oldcred->cr_svgid &&
113077183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1131145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
1132145147Srwatson		goto fail;
113394619Sjhb
113494619Sjhb	crcopy(newcred, oldcred);
113577183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
113677183Srwatson		change_egid(newcred, egid);
113756115Speter		setsugid(p);
113856115Speter	}
113977183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
114077183Srwatson		change_rgid(newcred, rgid);
114156115Speter		setsugid(p);
114256115Speter	}
114377183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
114477183Srwatson		change_svgid(newcred, sgid);
114556115Speter		setsugid(p);
114656115Speter	}
114777183Srwatson	p->p_ucred = newcred;
114894619Sjhb	PROC_UNLOCK(p);
114977183Srwatson	crfree(oldcred);
115094619Sjhb	return (0);
1151145147Srwatson
1152145147Srwatsonfail:
1153145147Srwatson	PROC_UNLOCK(p);
1154145147Srwatson	crfree(newcred);
1155145147Srwatson	return (error);
115656115Speter}
115756115Speter
115856115Speter#ifndef _SYS_SYSPROTO_H_
115956115Speterstruct getresuid_args {
116056115Speter	uid_t	*ruid;
116156115Speter	uid_t	*euid;
116256115Speter	uid_t	*suid;
116356115Speter};
116456115Speter#endif
116582749Sdillon/*
116682749Sdillon * MPSAFE
116782749Sdillon */
116856115Speter/* ARGSUSED */
116956115Speterint
117093580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap)
117156115Speter{
117282749Sdillon	struct ucred *cred;
117356115Speter	int error1 = 0, error2 = 0, error3 = 0;
117456115Speter
117593264Sdillon	cred = td->td_ucred;
117656115Speter	if (uap->ruid)
117799009Salfred		error1 = copyout(&cred->cr_ruid,
117899009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
117956115Speter	if (uap->euid)
118099009Salfred		error2 = copyout(&cred->cr_uid,
118199009Salfred		    uap->euid, sizeof(cred->cr_uid));
118256115Speter	if (uap->suid)
118399009Salfred		error3 = copyout(&cred->cr_svuid,
118499009Salfred		    uap->suid, sizeof(cred->cr_svuid));
118587218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
118656115Speter}
118756115Speter
118856115Speter#ifndef _SYS_SYSPROTO_H_
118956115Speterstruct getresgid_args {
119056115Speter	gid_t	*rgid;
119156115Speter	gid_t	*egid;
119256115Speter	gid_t	*sgid;
119356115Speter};
119456115Speter#endif
119582749Sdillon/*
119682749Sdillon * MPSAFE
119782749Sdillon */
119856115Speter/* ARGSUSED */
119956115Speterint
120093580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap)
120156115Speter{
120282749Sdillon	struct ucred *cred;
120356115Speter	int error1 = 0, error2 = 0, error3 = 0;
120456115Speter
120593264Sdillon	cred = td->td_ucred;
120656115Speter	if (uap->rgid)
120799009Salfred		error1 = copyout(&cred->cr_rgid,
120899009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
120956115Speter	if (uap->egid)
121099009Salfred		error2 = copyout(&cred->cr_groups[0],
121199009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
121256115Speter	if (uap->sgid)
121399009Salfred		error3 = copyout(&cred->cr_svgid,
121499009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
121587218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
121656115Speter}
121756115Speter
121856115Speter#ifndef _SYS_SYSPROTO_H_
121924453Speterstruct issetugid_args {
122024453Speter	int dummy;
122124453Speter};
122224453Speter#endif
122387218Srwatson/*
1224116121Sjhb * MPSAFE
122587218Srwatson */
122624453Speter/* ARGSUSED */
122724453Speterint
122893580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap)
122924453Speter{
123083366Sjulian	struct proc *p = td->td_proc;
123183366Sjulian
123224453Speter	/*
123324453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
123424453Speter	 * we use P_SUGID because we consider changing the owners as
123524453Speter	 * "tainting" as well.
123624453Speter	 * This is significant for procs that start as root and "become"
123724453Speter	 * a user without an exec - programs cannot know *everything*
123824453Speter	 * that libc *might* have put in their data segment.
123924453Speter	 */
124091140Stanimura	PROC_LOCK(p);
124183366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
124291140Stanimura	PROC_UNLOCK(p);
124324453Speter	return (0);
124424453Speter}
124524453Speter
124682749Sdillon/*
124782749Sdillon * MPSAFE
124882749Sdillon */
124975426Srwatsonint
125093580Sjhb__setugid(struct thread *td, struct __setugid_args *uap)
125175426Srwatson{
125282749Sdillon#ifdef REGRESSION
125394619Sjhb	struct proc *p;
125475426Srwatson
125594619Sjhb	p = td->td_proc;
125675426Srwatson	switch (uap->flag) {
125775426Srwatson	case 0:
125894619Sjhb		PROC_LOCK(p);
125994619Sjhb		p->p_flag &= ~P_SUGID;
126094619Sjhb		PROC_UNLOCK(p);
126194619Sjhb		return (0);
126275426Srwatson	case 1:
126394619Sjhb		PROC_LOCK(p);
126494619Sjhb		p->p_flag |= P_SUGID;
126594619Sjhb		PROC_UNLOCK(p);
126694619Sjhb		return (0);
126775426Srwatson	default:
126894619Sjhb		return (EINVAL);
126975426Srwatson	}
127075426Srwatson#else /* !REGRESSION */
127187218Srwatson
127275426Srwatson	return (ENOSYS);
127387218Srwatson#endif /* REGRESSION */
127475426Srwatson}
127575426Srwatson
12761541Srgrimes/*
12771541Srgrimes * Check if gid is a member of the group set.
127893264Sdillon *
127993264Sdillon * MPSAFE (cred must be held)
12801541Srgrimes */
12811549Srgrimesint
128293580Sjhbgroupmember(gid_t gid, struct ucred *cred)
12831541Srgrimes{
12841541Srgrimes	register gid_t *gp;
12851541Srgrimes	gid_t *egp;
12861541Srgrimes
12871541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
12881541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
12891541Srgrimes		if (*gp == gid)
12901541Srgrimes			return (1);
12911541Srgrimes	return (0);
12921541Srgrimes}
12931541Srgrimes
129482424Srwatson/*
129589414Sarr * `suser_enabled' (which can be set by the security.suser_enabled
129682466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect.
129782466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege,
129882466Srwatson * overriding many mandatory and discretionary protections.  If it is zero,
129982466Srwatson * uid 0 is offered no special privilege in the kernel security policy.
130082466Srwatson * Setting it to zero may seriously impact the functionality of many
130182466Srwatson * existing userland programs, and should not be done without careful
130282466Srwatson * consideration of the consequences.
130382424Srwatson */
130482693Srwatsonint	suser_enabled = 1;
130589414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW,
130682693Srwatson    &suser_enabled, 0, "processes with uid 0 have privilege");
130789414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled);
130861287Srwatson
13091541Srgrimes/*
131082466Srwatson * Test whether the specified credentials imply "super-user" privilege.
1311132255Scperciva * Return 0 or EPERM.
13121541Srgrimes */
13131549Srgrimesint
131493593Sjhbsuser_cred(struct ucred *cred, int flag)
131546112Sphk{
131687218Srwatson
131782693Srwatson	if (!suser_enabled)
131861282Srwatson		return (EPERM);
1319132255Scperciva	if (((flag & SUSER_RUID) ? cred->cr_ruid : cred->cr_uid) != 0)
132046155Sphk		return (EPERM);
1321132653Scperciva	if (jailed(cred) && !(flag & SUSER_ALLOWJAIL))
132246155Sphk		return (EPERM);
132346155Sphk	return (0);
13241541Srgrimes}
13251541Srgrimes
132683639Srwatson/*
132793593Sjhb * Shortcut to hide contents of struct td and struct proc from the
132893593Sjhb * caller, promoting binary compatibility.
132993593Sjhb */
133093593Sjhbint
133193593Sjhbsuser(struct thread *td)
133293593Sjhb{
133393593Sjhb
1334132548Srwatson#ifdef INVARIANTS
1335132548Srwatson	if (td != curthread) {
1336132548Srwatson		printf("suser: thread %p (%d %s) != curthread %p (%d %s)\n",
1337132548Srwatson		    td, td->td_proc->p_pid, td->td_proc->p_comm,
1338132548Srwatson		    curthread, curthread->td_proc->p_pid,
1339132548Srwatson		    curthread->td_proc->p_comm);
1340132548Srwatson#ifdef KDB
1341132548Srwatson		kdb_backtrace();
1342132548Srwatson#endif
1343132548Srwatson	}
1344132548Srwatson#endif
134593593Sjhb	return (suser_cred(td->td_ucred, 0));
134693593Sjhb}
134793593Sjhb
134893593Sjhb/*
134987218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
135087218Srwatson * implements (securelevel > level).  securelevel_ge() implements
135187218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
135287218Srwatson * functions return EPERM on "success" and 0 on "failure".
135383639Srwatson *
135493264Sdillon * MPSAFE
135583639Srwatson */
135683639Srwatsonint
135783639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
135883639Srwatson{
135987218Srwatson	int active_securelevel;
136083639Srwatson
136187218Srwatson	active_securelevel = securelevel;
136293732Sjhb	KASSERT(cr != NULL, ("securelevel_gt: null cr"));
1363140678Srwatson	if (cr->cr_prison != NULL)
136487218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
136587218Srwatson		    active_securelevel);
136687218Srwatson	return (active_securelevel > level ? EPERM : 0);
136783639Srwatson}
136883639Srwatson
136983639Srwatsonint
137083639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
137183639Srwatson{
137287218Srwatson	int active_securelevel;
137383639Srwatson
137487218Srwatson	active_securelevel = securelevel;
137593732Sjhb	KASSERT(cr != NULL, ("securelevel_ge: null cr"));
1376140678Srwatson	if (cr->cr_prison != NULL)
137787218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
137887218Srwatson		    active_securelevel);
137987218Srwatson	return (active_securelevel >= level ? EPERM : 0);
138083639Srwatson}
138183639Srwatson
138284736Srwatson/*
138387144Srwatson * 'see_other_uids' determines whether or not visibility of processes
138487218Srwatson * and sockets with credentials holding different real uids is possible
138587138Srwatson * using a variety of system MIBs.
138687218Srwatson * XXX: data declarations should be together near the beginning of the file.
138784736Srwatson */
138887144Srwatsonstatic int	see_other_uids = 1;
138989414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
139087218Srwatson    &see_other_uids, 0,
139184736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
139284736Srwatson
139382466Srwatson/*-
139492923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
139592923Srwatson * 'see_other_uids' policy.
139692923Srwatson * Returns: 0 for permitted, ESRCH otherwise
139792923Srwatson * Locks: none
139892923Srwatson * References: *u1 and *u2 must not change during the call
139992923Srwatson *             u1 may equal u2, in which case only one reference is required
140092923Srwatson */
140192923Srwatsonstatic int
140292923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
140392923Srwatson{
140492923Srwatson
140592923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1406132653Scperciva		if (suser_cred(u1, SUSER_ALLOWJAIL) != 0)
140792923Srwatson			return (ESRCH);
140892923Srwatson	}
140992923Srwatson	return (0);
141092923Srwatson}
141192923Srwatson
1412122869Srwatson/*
1413122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1414122869Srwatson * and sockets with credentials holding different real gids is possible
1415122869Srwatson * using a variety of system MIBs.
1416122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1417122869Srwatson */
1418122869Srwatsonstatic int	see_other_gids = 1;
1419122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1420122869Srwatson    &see_other_gids, 0,
1421122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1422122869Srwatson
1423122869Srwatson/*
1424122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1425122869Srwatson * 'see_other_gids' policy.
1426122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1427122869Srwatson * Locks: none
1428122869Srwatson * References: *u1 and *u2 must not change during the call
1429122869Srwatson *             u1 may equal u2, in which case only one reference is required
1430122869Srwatson */
1431122869Srwatsonstatic int
1432122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1433122869Srwatson{
1434122869Srwatson	int i, match;
1435122869Srwatson
1436122869Srwatson	if (!see_other_gids) {
1437122869Srwatson		match = 0;
1438122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1439122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1440122869Srwatson				match = 1;
1441122869Srwatson			if (match)
1442122869Srwatson				break;
1443122869Srwatson		}
1444122869Srwatson		if (!match) {
1445132653Scperciva			if (suser_cred(u1, SUSER_ALLOWJAIL) != 0)
1446122869Srwatson				return (ESRCH);
1447122869Srwatson		}
1448122869Srwatson	}
1449122869Srwatson	return (0);
1450122869Srwatson}
1451122869Srwatson
145292923Srwatson/*-
145382466Srwatson * Determine if u1 "can see" the subject specified by u2.
145474956Srwatson * Returns: 0 for permitted, an errno value otherwise
145574956Srwatson * Locks: none
145687218Srwatson * References: *u1 and *u2 must not change during the call
145774956Srwatson *             u1 may equal u2, in which case only one reference is required
145874956Srwatson */
145974956Srwatsonint
146083742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
146165237Srwatson{
146272786Srwatson	int error;
146353518Sphk
146474956Srwatson	if ((error = prison_check(u1, u2)))
146572786Srwatson		return (error);
1466101003Srwatson#ifdef MAC
1467101003Srwatson	if ((error = mac_check_cred_visible(u1, u2)))
1468101003Srwatson		return (error);
1469101003Srwatson#endif
147092923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
147192923Srwatson		return (error);
1472122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1473122869Srwatson		return (error);
147465237Srwatson	return (0);
147565237Srwatson}
147665237Srwatson
147782466Srwatson/*-
147896886Sjhb * Determine if td "can see" the subject specified by p.
147982424Srwatson * Returns: 0 for permitted, an errno value otherwise
148096886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
148196886Sjhb *        should be curthread.
148296886Sjhb * References: td and p must be valid for the lifetime of the call
148382424Srwatson */
148479335Srwatsonint
148596886Sjhbp_cansee(struct thread *td, struct proc *p)
148674956Srwatson{
148774956Srwatson
148883742Srwatson	/* Wrap cr_cansee() for all functionality. */
148996886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
149096886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
149196886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
149274956Srwatson}
149374956Srwatson
1494120052Srwatson/*
1495120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1496120052Srwatson * signals by unprivileged processes to processes that have changed their
1497120052Srwatson * credentials since the last invocation of execve().  This can prevent
1498120052Srwatson * the leakage of cached information or retained privileges as a result
1499120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1500120052Srwatson * may interfere with some applications that expect to be able to
1501120052Srwatson * deliver these signals to peer processes after having given up
1502120052Srwatson * privilege.
1503120052Srwatson */
1504120052Srwatsonstatic int	conservative_signals = 1;
1505120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1506120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1507120052Srwatson    "sending certain signals to processes whose credentials have changed");
150882466Srwatson/*-
150988943Srwatson * Determine whether cred may deliver the specified signal to proc.
151088943Srwatson * Returns: 0 for permitted, an errno value otherwise.
151188943Srwatson * Locks: A lock must be held for proc.
151288943Srwatson * References: cred and proc must be valid for the lifetime of the call.
151375437Srwatson */
151475437Srwatsonint
1515141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum)
151653518Sphk{
151782466Srwatson	int error;
151884826Sjhb
151996886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
152075437Srwatson	/*
152188943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
152288943Srwatson	 * same jail as cred, if cred is in jail.
152375437Srwatson	 */
152488943Srwatson	error = prison_check(cred, proc->p_ucred);
152588943Srwatson	if (error)
152672786Srwatson		return (error);
1527101003Srwatson#ifdef MAC
1528101003Srwatson	if ((error = mac_check_proc_signal(cred, proc, signum)))
1529101003Srwatson		return (error);
1530101003Srwatson#endif
1531122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
153292923Srwatson		return (error);
1533122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1534122869Srwatson		return (error);
153565237Srwatson
153665237Srwatson	/*
153782424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
153882424Srwatson	 * bit on the target process.  If the bit is set, then additional
153982424Srwatson	 * restrictions are placed on the set of available signals.
154075437Srwatson	 */
1541141815Ssobomax	if (conservative_signals && (proc->p_flag & P_SUGID)) {
154275437Srwatson		switch (signum) {
154375437Srwatson		case 0:
154475437Srwatson		case SIGKILL:
154575437Srwatson		case SIGINT:
154675437Srwatson		case SIGTERM:
1547120052Srwatson		case SIGALRM:
154875437Srwatson		case SIGSTOP:
154975437Srwatson		case SIGTTIN:
155075437Srwatson		case SIGTTOU:
155175437Srwatson		case SIGTSTP:
155275437Srwatson		case SIGHUP:
155375437Srwatson		case SIGUSR1:
155475437Srwatson		case SIGUSR2:
155582466Srwatson			/*
155682466Srwatson			 * Generally, permit job and terminal control
155782466Srwatson			 * signals.
155882466Srwatson			 */
155975437Srwatson			break;
156075437Srwatson		default:
156188943Srwatson			/* Not permitted without privilege. */
1562132653Scperciva			error = suser_cred(cred, SUSER_ALLOWJAIL);
156375437Srwatson			if (error)
156475437Srwatson				return (error);
156575437Srwatson		}
156665237Srwatson	}
156765237Srwatson
156875480Srwatson	/*
156982424Srwatson	 * Generally, the target credential's ruid or svuid must match the
157075480Srwatson	 * subject credential's ruid or euid.
157175480Srwatson	 */
157288943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
157388943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
157488943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
157588943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
157688943Srwatson		/* Not permitted without privilege. */
1577132653Scperciva		error = suser_cred(cred, SUSER_ALLOWJAIL);
157875480Srwatson		if (error)
157975480Srwatson			return (error);
158075480Srwatson	}
158175480Srwatson
158287218Srwatson	return (0);
158353518Sphk}
158453518Sphk
158588943Srwatson
158682466Srwatson/*-
158796886Sjhb * Determine whether td may deliver the specified signal to p.
158888943Srwatson * Returns: 0 for permitted, an errno value otherwise
158996886Sjhb * Locks: Sufficient locks to protect various components of td and p
159096886Sjhb *        must be held.  td must be curthread, and a lock must be
159196886Sjhb *        held for p.
159296886Sjhb * References: td and p must be valid for the lifetime of the call
159388943Srwatson */
159488943Srwatsonint
1595141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum)
159688943Srwatson{
159788943Srwatson
159896886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
159996886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
160096886Sjhb	if (td->td_proc == p)
160188943Srwatson		return (0);
160288943Srwatson
160388943Srwatson	/*
160488943Srwatson	 * UNIX signalling semantics require that processes in the same
160588943Srwatson	 * session always be able to deliver SIGCONT to one another,
160688943Srwatson	 * overriding the remaining protections.
160788943Srwatson	 */
160896886Sjhb	/* XXX: This will require an additional lock of some sort. */
160996886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
161088943Srwatson		return (0);
1611143108Ssobomax	/*
1612143800Ssobomax	 * Some compat layers use SIGTHR and higher signals for
1613143800Ssobomax	 * communication between different kernel threads of the same
1614143800Ssobomax	 * process, so that they expect that it's always possible to
1615143800Ssobomax	 * deliver them, even for suid applications where cr_cansignal() can
1616143108Ssobomax	 * deny such ability for security consideration.  It should be
1617143108Ssobomax	 * pretty safe to do since the only way to create two processes
1618143108Ssobomax	 * with the same p_leader is via rfork(2).
1619143108Ssobomax	 */
1620143805Ssobomax	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
1621143805Ssobomax	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
1622143108Ssobomax		return (0);
162388943Srwatson
1624141815Ssobomax	return (cr_cansignal(td->td_ucred, p, signum));
162588943Srwatson}
162688943Srwatson
162788943Srwatson/*-
162896886Sjhb * Determine whether td may reschedule p.
162982466Srwatson * Returns: 0 for permitted, an errno value otherwise
163096886Sjhb * Locks: Sufficient locks to protect various components of td and p
163196886Sjhb *        must be held.  td must be curthread, and a lock must
163296886Sjhb *        be held for p.
163396886Sjhb * References: td and p must be valid for the lifetime of the call
163482424Srwatson */
163579335Srwatsonint
163696886Sjhbp_cansched(struct thread *td, struct proc *p)
163765237Srwatson{
163872786Srwatson	int error;
163965237Srwatson
164096886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
164196886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
164296886Sjhb	if (td->td_proc == p)
164365237Srwatson		return (0);
164496886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
164572786Srwatson		return (error);
1646101003Srwatson#ifdef MAC
1647101003Srwatson	if ((error = mac_check_proc_sched(td->td_ucred, p)))
1648101003Srwatson		return (error);
1649101003Srwatson#endif
165096886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
165192923Srwatson		return (error);
1652122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1653122869Srwatson		return (error);
165496886Sjhb	if (td->td_ucred->cr_ruid == p->p_ucred->cr_ruid)
165565237Srwatson		return (0);
165696886Sjhb	if (td->td_ucred->cr_uid == p->p_ucred->cr_ruid)
165765237Srwatson		return (0);
1658132653Scperciva	if (suser_cred(td->td_ucred, SUSER_ALLOWJAIL) == 0)
165965237Srwatson		return (0);
166065237Srwatson
166165237Srwatson#ifdef CAPABILITIES
1662132653Scperciva	if (!cap_check(NULL, td, CAP_SYS_NICE, SUSER_ALLOWJAIL))
166365237Srwatson		return (0);
166465237Srwatson#endif
166565237Srwatson
166665237Srwatson	return (EPERM);
166765237Srwatson}
166865237Srwatson
166982424Srwatson/*
167087280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
167187280Srwatson * unprivileged inter-process debugging services, including some procfs
167287280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
167387280Srwatson * debugging has been involved in a variety of security problems, and sites
167487280Srwatson * not requiring the service might choose to disable it when hardening
167587280Srwatson * systems.
167682424Srwatson *
167782424Srwatson * XXX: Should modifying and reading this variable require locking?
167887218Srwatson * XXX: data declarations should be together near the beginning of the file.
167982424Srwatson */
168087144Srwatsonstatic int	unprivileged_proc_debug = 1;
168189414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
168287218Srwatson    &unprivileged_proc_debug, 0,
168380735Srwatson    "Unprivileged processes may use process debugging facilities");
168480735Srwatson
168582466Srwatson/*-
168696886Sjhb * Determine whether td may debug p.
168782466Srwatson * Returns: 0 for permitted, an errno value otherwise
168896886Sjhb * Locks: Sufficient locks to protect various components of td and p
168996886Sjhb *        must be held.  td must be curthread, and a lock must
169096886Sjhb *        be held for p.
169196886Sjhb * References: td and p must be valid for the lifetime of the call
169282424Srwatson */
169379335Srwatsonint
169496886Sjhbp_candebug(struct thread *td, struct proc *p)
169565237Srwatson{
169687218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
169765237Srwatson
169896886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
169996886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
170087144Srwatson	if (!unprivileged_proc_debug) {
1701132653Scperciva		error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
170284727Srwatson		if (error)
170384727Srwatson			return (error);
170484727Srwatson	}
170596886Sjhb	if (td->td_proc == p)
170684636Sdes		return (0);
170796886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
170872786Srwatson		return (error);
1709101003Srwatson#ifdef MAC
1710101003Srwatson	if ((error = mac_check_proc_debug(td->td_ucred, p)))
1711101003Srwatson		return (error);
1712101003Srwatson#endif
171396886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
171492923Srwatson		return (error);
1715122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1716122869Srwatson		return (error);
171765237Srwatson
171882466Srwatson	/*
171996886Sjhb	 * Is p's group set a subset of td's effective group set?  This
172096886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
172182466Srwatson	 */
172285895Srwatson	grpsubset = 1;
172396886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
172496886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
172585895Srwatson			grpsubset = 0;
172685895Srwatson			break;
172785895Srwatson		}
172885895Srwatson	}
172985895Srwatson	grpsubset = grpsubset &&
173096886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
173196886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
173285895Srwatson
173385895Srwatson	/*
173496886Sjhb	 * Are the uids present in p's credential equal to td's
173596886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
173685895Srwatson	 */
173796886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
173896886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
173996886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
174085895Srwatson
174185895Srwatson	/*
174285895Srwatson	 * Has the credential of the process changed since the last exec()?
174385895Srwatson	 */
174496886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
174585895Srwatson
174685895Srwatson	/*
174796886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
174885895Srwatson	 * or the credential has changed, require appropriate privilege
174996886Sjhb	 * for td to debug p.  For POSIX.1e capabilities, this will
175085895Srwatson	 * require CAP_SYS_PTRACE.
175185895Srwatson	 */
175285895Srwatson	if (!grpsubset || !uidsubset || credentialchanged) {
1753132653Scperciva		error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
175484727Srwatson		if (error)
175565237Srwatson			return (error);
175682466Srwatson	}
175765237Srwatson
175887218Srwatson	/* Can't trace init when securelevel > 0. */
175996886Sjhb	if (p == initproc) {
176096886Sjhb		error = securelevel_gt(td->td_ucred, 0);
176183639Srwatson		if (error)
176283639Srwatson			return (error);
176383639Srwatson	}
176465237Srwatson
176585880Srwatson	/*
176685880Srwatson	 * Can't trace a process that's currently exec'ing.
176785880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
176885880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
176985880Srwatson	 * should be moved to the caller's of p_candebug().
177085880Srwatson	 */
177196886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
177285598Sdes		return (EAGAIN);
177387466Srwatson
177465237Srwatson	return (0);
177565237Srwatson}
177665237Srwatson
177792976Srwatson/*-
177892976Srwatson * Determine whether the subject represented by cred can "see" a socket.
177992976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
178092976Srwatson */
178192976Srwatsonint
178292976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
178392976Srwatson{
178492976Srwatson	int error;
178592976Srwatson
178692976Srwatson	error = prison_check(cred, so->so_cred);
178792976Srwatson	if (error)
178892976Srwatson		return (ENOENT);
1789101003Srwatson#ifdef MAC
1790130398Srwatson	SOCK_LOCK(so);
1791101003Srwatson	error = mac_check_socket_visible(cred, so);
1792130398Srwatson	SOCK_UNLOCK(so);
1793101003Srwatson	if (error)
1794101003Srwatson		return (error);
1795101003Srwatson#endif
179692976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
179792976Srwatson		return (ENOENT);
1798122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1799122869Srwatson		return (ENOENT);
180092976Srwatson
180192976Srwatson	return (0);
180292976Srwatson}
180392976Srwatson
1804145234Srwatson/*-
1805145234Srwatson * Determine whether td can wait for the exit of p.
1806145234Srwatson * Returns: 0 for permitted, an errno value otherwise
1807145234Srwatson * Locks: Sufficient locks to protect various components of td and p
1808145234Srwatson *        must be held.  td must be curthread, and a lock must
1809145234Srwatson *        be held for p.
1810145234Srwatson * References: td and p must be valid for the lifetime of the call
1811145234Srwatson
1812145234Srwatson */
1813145234Srwatsonint
1814145234Srwatsonp_canwait(struct thread *td, struct proc *p)
1815145234Srwatson{
1816145234Srwatson	int error;
1817145234Srwatson
1818145234Srwatson	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1819145234Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
1820145234Srwatson	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1821145234Srwatson		return (error);
1822145234Srwatson#ifdef MAC
1823145234Srwatson	if ((error = mac_check_proc_wait(td->td_ucred, p)))
1824145234Srwatson		return (error);
1825145234Srwatson#endif
1826145234Srwatson#if 0
1827145234Srwatson	/* XXXMAC: This could have odd effects on some shells. */
1828145234Srwatson	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
1829145234Srwatson		return (error);
1830145234Srwatson#endif
1831145234Srwatson
1832145234Srwatson	return (0);
1833145234Srwatson}
1834145234Srwatson
183553518Sphk/*
18361541Srgrimes * Allocate a zeroed cred structure.
1837116406Srwatson * MPSAFE
18381541Srgrimes */
18391541Srgrimesstruct ucred *
184093580Sjhbcrget(void)
18411541Srgrimes{
18421541Srgrimes	register struct ucred *cr;
18431541Srgrimes
1844111119Simp	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1845150634Sjhb	refcount_init(&cr->cr_ref, 1);
1846101001Srwatson#ifdef MAC
1847101001Srwatson	mac_init_cred(cr);
1848101001Srwatson#endif
18491541Srgrimes	return (cr);
18501541Srgrimes}
18511541Srgrimes
18521541Srgrimes/*
185382466Srwatson * Claim another reference to a ucred structure.
1854116406Srwatson * MPSAFE
185569401Salfred */
185684827Sjhbstruct ucred *
185793580Sjhbcrhold(struct ucred *cr)
185869401Salfred{
185969401Salfred
1860150634Sjhb	refcount_acquire(&cr->cr_ref);
186184827Sjhb	return (cr);
186269401Salfred}
186369401Salfred
186469401Salfred/*
18651541Srgrimes * Free a cred structure.
18661541Srgrimes * Throws away space when ref count gets to 0.
1867116406Srwatson * MPSAFE
18681541Srgrimes */
18691549Srgrimesvoid
187093580Sjhbcrfree(struct ucred *cr)
18711541Srgrimes{
187269239Salfred
187375632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1874150634Sjhb	KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred"));
1875150634Sjhb	if (refcount_release(&cr->cr_ref)) {
187665495Struckman		/*
187765495Struckman		 * Some callers of crget(), such as nfs_statfs(),
187865495Struckman		 * allocate a temporary credential, but don't
187965495Struckman		 * allocate a uidinfo structure.
188065495Struckman		 */
188165495Struckman		if (cr->cr_uidinfo != NULL)
188265495Struckman			uifree(cr->cr_uidinfo);
188377277Srwatson		if (cr->cr_ruidinfo != NULL)
188477277Srwatson			uifree(cr->cr_ruidinfo);
188572786Srwatson		/*
188672786Srwatson		 * Free a prison, if any.
188772786Srwatson		 */
188872786Srwatson		if (jailed(cr))
188972786Srwatson			prison_free(cr->cr_prison);
1890101001Srwatson#ifdef MAC
1891101001Srwatson		mac_destroy_cred(cr);
1892101001Srwatson#endif
189399009Salfred		FREE(cr, M_CRED);
189490756Sdillon	}
18951541Srgrimes}
18961541Srgrimes
18971541Srgrimes/*
189884827Sjhb * Check to see if this ucred is shared.
1899116406Srwatson * MPSAFE
19001541Srgrimes */
190184827Sjhbint
190293580Sjhbcrshared(struct ucred *cr)
19031541Srgrimes{
19041541Srgrimes
1905150634Sjhb	return (cr->cr_ref > 1);
19061541Srgrimes}
19071541Srgrimes
19081541Srgrimes/*
190984827Sjhb * Copy a ucred's contents from a template.  Does not block.
1910116406Srwatson * MPSAFE
191184827Sjhb */
191284827Sjhbvoid
191393580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
191484827Sjhb{
191584827Sjhb
191684827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
191784827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
191887218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
191984827Sjhb		(caddr_t)&src->cr_startcopy));
192084827Sjhb	uihold(dest->cr_uidinfo);
192184827Sjhb	uihold(dest->cr_ruidinfo);
192284827Sjhb	if (jailed(dest))
192384827Sjhb		prison_hold(dest->cr_prison);
1924101001Srwatson#ifdef MAC
1925123173Srwatson	mac_copy_cred(src, dest);
1926101001Srwatson#endif
192784827Sjhb}
192884827Sjhb
192984827Sjhb/*
19301541Srgrimes * Dup cred struct to a new held one.
1931116406Srwatson * MPSAFE
19321541Srgrimes */
19331541Srgrimesstruct ucred *
193493580Sjhbcrdup(struct ucred *cr)
19351541Srgrimes{
19361541Srgrimes	struct ucred *newcr;
19371541Srgrimes
193884827Sjhb	newcr = crget();
193984827Sjhb	crcopy(newcr, cr);
19401541Srgrimes	return (newcr);
19411541Srgrimes}
19421541Srgrimes
19431541Srgrimes/*
194491354Sdd * Fill in a struct xucred based on a struct ucred.
1945116406Srwatson * MPSAFE
194691354Sdd */
194791354Sddvoid
194893580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
194991354Sdd{
195091354Sdd
195191354Sdd	bzero(xcr, sizeof(*xcr));
195291354Sdd	xcr->cr_version = XUCRED_VERSION;
195391354Sdd	xcr->cr_uid = cr->cr_uid;
195491354Sdd	xcr->cr_ngroups = cr->cr_ngroups;
195591354Sdd	bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
195691354Sdd}
195791354Sdd
195891354Sdd/*
195990748Sjulian * small routine to swap a thread's current ucred for the correct one
196090748Sjulian * taken from the process.
1961116406Srwatson * MPSAFE
196290748Sjulian */
196390748Sjulianvoid
196490748Sjuliancred_update_thread(struct thread *td)
196590748Sjulian{
196690748Sjulian	struct proc *p;
196791405Sjhb	struct ucred *cred;
196890748Sjulian
196990748Sjulian	p = td->td_proc;
197091405Sjhb	cred = td->td_ucred;
197190748Sjulian	PROC_LOCK(p);
197290748Sjulian	td->td_ucred = crhold(p->p_ucred);
197390748Sjulian	PROC_UNLOCK(p);
197491405Sjhb	if (cred != NULL)
197591405Sjhb		crfree(cred);
197690748Sjulian}
197790748Sjulian
197890748Sjulian/*
19791541Srgrimes * Get login name, if available.
19801541Srgrimes */
198112221Sbde#ifndef _SYS_SYSPROTO_H_
19821541Srgrimesstruct getlogin_args {
19831541Srgrimes	char	*namebuf;
19841541Srgrimes	u_int	namelen;
19851541Srgrimes};
198612221Sbde#endif
198782749Sdillon/*
198882749Sdillon * MPSAFE
198982749Sdillon */
19901541Srgrimes/* ARGSUSED */
19911549Srgrimesint
199293580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap)
19931541Srgrimes{
199482749Sdillon	int error;
199591140Stanimura	char login[MAXLOGNAME];
199683366Sjulian	struct proc *p = td->td_proc;
19971541Srgrimes
199823358Sache	if (uap->namelen > MAXLOGNAME)
199923359Sache		uap->namelen = MAXLOGNAME;
200091140Stanimura	PROC_LOCK(p);
200191140Stanimura	SESS_LOCK(p->p_session);
200291140Stanimura	bcopy(p->p_session->s_login, login, uap->namelen);
200391140Stanimura	SESS_UNLOCK(p->p_session);
200491140Stanimura	PROC_UNLOCK(p);
200599009Salfred	error = copyout(login, uap->namebuf, uap->namelen);
200682749Sdillon	return(error);
20071541Srgrimes}
20081541Srgrimes
20091541Srgrimes/*
20101541Srgrimes * Set login name.
20111541Srgrimes */
201212221Sbde#ifndef _SYS_SYSPROTO_H_
20131541Srgrimesstruct setlogin_args {
20141541Srgrimes	char	*namebuf;
20151541Srgrimes};
201612221Sbde#endif
201782749Sdillon/*
201882749Sdillon * MPSAFE
201982749Sdillon */
20201541Srgrimes/* ARGSUSED */
20211549Srgrimesint
202293580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap)
20231541Srgrimes{
202483366Sjulian	struct proc *p = td->td_proc;
20251541Srgrimes	int error;
202623330Sache	char logintmp[MAXLOGNAME];
20271541Srgrimes
2028132653Scperciva	error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
202994619Sjhb	if (error)
203094619Sjhb		return (error);
203199009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
203287218Srwatson	if (error == ENAMETOOLONG)
20331541Srgrimes		error = EINVAL;
203491140Stanimura	else if (!error) {
203591140Stanimura		PROC_LOCK(p);
203691140Stanimura		SESS_LOCK(p->p_session);
203791140Stanimura		(void) memcpy(p->p_session->s_login, logintmp,
203823330Sache		    sizeof(logintmp));
203991140Stanimura		SESS_UNLOCK(p->p_session);
204091140Stanimura		PROC_UNLOCK(p);
204191140Stanimura	}
20421541Srgrimes	return (error);
20431541Srgrimes}
204431891Ssef
204531891Ssefvoid
204693580Sjhbsetsugid(struct proc *p)
204731891Ssef{
204898403Salfred
204998403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
205031891Ssef	p->p_flag |= P_SUGID;
205155707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
205231891Ssef		p->p_stops = 0;
205331891Ssef}
205465495Struckman
205582466Srwatson/*-
205682466Srwatson * Change a process's effective uid.
205777183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
205877183Srwatson * References: newcred must be an exclusive credential reference for the
205977183Srwatson *             duration of the call.
206065495Struckman */
206165495Struckmanvoid
206298417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
206365495Struckman{
206465495Struckman
206598417Salfred	newcred->cr_uid = euip->ui_uid;
206698417Salfred	uihold(euip);
206777183Srwatson	uifree(newcred->cr_uidinfo);
206898417Salfred	newcred->cr_uidinfo = euip;
206965495Struckman}
207065495Struckman
207182466Srwatson/*-
207282466Srwatson * Change a process's effective gid.
207377183Srwatson * Side effects: newcred->cr_gid will be modified.
207477183Srwatson * References: newcred must be an exclusive credential reference for the
207577183Srwatson *             duration of the call.
207665495Struckman */
207767629Sgallatinvoid
207893580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
207965495Struckman{
208065495Struckman
208177183Srwatson	newcred->cr_groups[0] = egid;
208265495Struckman}
208377183Srwatson
208482466Srwatson/*-
208582466Srwatson * Change a process's real uid.
208677183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
208777183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
208877183Srwatson *               counts will be updated.
208977183Srwatson * References: newcred must be an exclusive credential reference for the
209077183Srwatson *             duration of the call.
209177183Srwatson */
209277183Srwatsonvoid
209398417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
209477183Srwatson{
209577183Srwatson
209677183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
209798417Salfred	newcred->cr_ruid = ruip->ui_uid;
209898417Salfred	uihold(ruip);
209977183Srwatson	uifree(newcred->cr_ruidinfo);
210098417Salfred	newcred->cr_ruidinfo = ruip;
210177183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
210277183Srwatson}
210377183Srwatson
210482466Srwatson/*-
210582466Srwatson * Change a process's real gid.
210677183Srwatson * Side effects: newcred->cr_rgid will be updated.
210777183Srwatson * References: newcred must be an exclusive credential reference for the
210877183Srwatson *             duration of the call.
210977183Srwatson */
211077183Srwatsonvoid
211193580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
211277183Srwatson{
211377183Srwatson
211477183Srwatson	newcred->cr_rgid = rgid;
211577183Srwatson}
211677183Srwatson
211782466Srwatson/*-
211882466Srwatson * Change a process's saved uid.
211977183Srwatson * Side effects: newcred->cr_svuid will be updated.
212077183Srwatson * References: newcred must be an exclusive credential reference for the
212177183Srwatson *             duration of the call.
212277183Srwatson */
212377183Srwatsonvoid
212493580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
212577183Srwatson{
212677183Srwatson
212777183Srwatson	newcred->cr_svuid = svuid;
212877183Srwatson}
212977183Srwatson
213082466Srwatson/*-
213182466Srwatson * Change a process's saved gid.
213277183Srwatson * Side effects: newcred->cr_svgid will be updated.
213377183Srwatson * References: newcred must be an exclusive credential reference for the
213477183Srwatson *             duration of the call.
213577183Srwatson */
213677183Srwatsonvoid
213793580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
213877183Srwatson{
213977183Srwatson
214077183Srwatson	newcred->cr_svgid = svgid;
214177183Srwatson}
2142