kern_prot.c revision 145147
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 145147 2005-04-16 13:29:15Z rwatson $");
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>
5791140Stanimura#include <sys/sx.h>
581541Srgrimes#include <sys/proc.h>
5976166Smarkm#include <sys/sysproto.h>
6087218Srwatson#include <sys/jail.h>
6131891Ssef#include <sys/pioctl.h>
6265495Struckman#include <sys/resourcevar.h>
6392976Srwatson#include <sys/socket.h>
6492976Srwatson#include <sys/socketvar.h>
6561287Srwatson#include <sys/sysctl.h>
661541Srgrimes
6730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6830354Sphk
6989414SarrSYSCTL_DECL(_security);
7089414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0,
7187138Srwatson    "BSD security policy");
7287138Srwatson
7312221Sbde#ifndef _SYS_SYSPROTO_H_
7411332Sswallacestruct getpid_args {
751541Srgrimes	int	dummy;
761541Srgrimes};
7712221Sbde#endif
7858717Sdillon/*
7982749Sdillon * MPSAFE
8082749Sdillon */
811541Srgrimes/* ARGSUSED */
821549Srgrimesint
8393580Sjhbgetpid(struct thread *td, struct getpid_args *uap)
841541Srgrimes{
8583366Sjulian	struct proc *p = td->td_proc;
861541Srgrimes
8783366Sjulian	td->td_retval[0] = p->p_pid;
88130344Sphk#if defined(COMPAT_43)
8974728Sjhb	PROC_LOCK(p);
9083366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
9174728Sjhb	PROC_UNLOCK(p);
921541Srgrimes#endif
931541Srgrimes	return (0);
941541Srgrimes}
951541Srgrimes
9612221Sbde#ifndef _SYS_SYSPROTO_H_
9711332Sswallacestruct getppid_args {
9811332Sswallace        int     dummy;
9911332Sswallace};
10012221Sbde#endif
10182749Sdillon/*
10282749Sdillon * MPSAFE
10382749Sdillon */
1041541Srgrimes/* ARGSUSED */
1051549Srgrimesint
10693580Sjhbgetppid(struct thread *td, struct getppid_args *uap)
1071541Srgrimes{
10883366Sjulian	struct proc *p = td->td_proc;
1091541Srgrimes
11074728Sjhb	PROC_LOCK(p);
11183366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
11274728Sjhb	PROC_UNLOCK(p);
1131541Srgrimes	return (0);
1141541Srgrimes}
1151541Srgrimes
11687466Srwatson/*
11787218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
11858717Sdillon */
11912221Sbde#ifndef _SYS_SYSPROTO_H_
12011332Sswallacestruct getpgrp_args {
12111332Sswallace        int     dummy;
12211332Sswallace};
12312221Sbde#endif
12482749Sdillon/*
12582749Sdillon * MPSAFE
12682749Sdillon */
1271549Srgrimesint
12893580Sjhbgetpgrp(struct thread *td, struct getpgrp_args *uap)
1291541Srgrimes{
13083366Sjulian	struct proc *p = td->td_proc;
1311541Srgrimes
13291140Stanimura	PROC_LOCK(p);
13383366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
13491140Stanimura	PROC_UNLOCK(p);
1351541Srgrimes	return (0);
1361541Srgrimes}
1371541Srgrimes
13828401Speter/* Get an arbitary pid's process group id */
13912221Sbde#ifndef _SYS_SYSPROTO_H_
14028401Speterstruct getpgid_args {
14128401Speter	pid_t	pid;
14228401Speter};
14328401Speter#endif
14482749Sdillon/*
14582749Sdillon * MPSAFE
14682749Sdillon */
14728401Speterint
14893580Sjhbgetpgid(struct thread *td, struct getpgid_args *uap)
14928401Speter{
150114031Sjhb	struct proc *p;
15192985Sjhb	int error;
15241726Struckman
15391140Stanimura	if (uap->pid == 0) {
154114031Sjhb		p = td->td_proc;
15591140Stanimura		PROC_LOCK(p);
156114031Sjhb	} else {
157114031Sjhb		p = pfind(uap->pid);
158114031Sjhb		if (p == NULL)
159114031Sjhb			return (ESRCH);
160114031Sjhb		error = p_cansee(td, p);
161114031Sjhb		if (error) {
162114031Sjhb			PROC_UNLOCK(p);
163114031Sjhb			return (error);
164114031Sjhb		}
16575893Sjhb	}
166114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
167114031Sjhb	PROC_UNLOCK(p);
168114031Sjhb	return (0);
16928401Speter}
17028401Speter
17128401Speter/*
17228401Speter * Get an arbitary pid's session id.
17328401Speter */
17428401Speter#ifndef _SYS_SYSPROTO_H_
17528401Speterstruct getsid_args {
17628401Speter	pid_t	pid;
17728401Speter};
17828401Speter#endif
17982749Sdillon/*
18082749Sdillon * MPSAFE
18182749Sdillon */
18228401Speterint
18393580Sjhbgetsid(struct thread *td, struct getsid_args *uap)
18428401Speter{
185114031Sjhb	struct proc *p;
18687218Srwatson	int error;
18741726Struckman
18891140Stanimura	if (uap->pid == 0) {
189114031Sjhb		p = td->td_proc;
19091140Stanimura		PROC_LOCK(p);
191114031Sjhb	} else {
192114031Sjhb		p = pfind(uap->pid);
193114031Sjhb		if (p == NULL)
194114031Sjhb			return (ESRCH);
195114031Sjhb		error = p_cansee(td, p);
196114031Sjhb		if (error) {
197114031Sjhb			PROC_UNLOCK(p);
198114031Sjhb			return (error);
199114031Sjhb		}
20075893Sjhb	}
201114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
202114031Sjhb	PROC_UNLOCK(p);
203114031Sjhb	return (0);
20428401Speter}
20528401Speter
20628401Speter#ifndef _SYS_SYSPROTO_H_
20711332Sswallacestruct getuid_args {
20811332Sswallace        int     dummy;
20911332Sswallace};
21012221Sbde#endif
21182749Sdillon/*
21282749Sdillon * MPSAFE
21382749Sdillon */
2141541Srgrimes/* ARGSUSED */
2151549Srgrimesint
21693580Sjhbgetuid(struct thread *td, struct getuid_args *uap)
2171541Srgrimes{
2181541Srgrimes
21992987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
220130344Sphk#if defined(COMPAT_43)
22192987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2221541Srgrimes#endif
2231541Srgrimes	return (0);
2241541Srgrimes}
2251541Srgrimes
22612221Sbde#ifndef _SYS_SYSPROTO_H_
22711332Sswallacestruct geteuid_args {
22811332Sswallace        int     dummy;
22911332Sswallace};
23012221Sbde#endif
23187218Srwatson/*
23287218Srwatson * MPSAFE
23387218Srwatson */
2341541Srgrimes/* ARGSUSED */
2351549Srgrimesint
23693580Sjhbgeteuid(struct thread *td, struct geteuid_args *uap)
2371541Srgrimes{
23892987Sjhb
23992987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2401541Srgrimes	return (0);
2411541Srgrimes}
2421541Srgrimes
24312221Sbde#ifndef _SYS_SYSPROTO_H_
24411332Sswallacestruct getgid_args {
24511332Sswallace        int     dummy;
24611332Sswallace};
24712221Sbde#endif
24882749Sdillon/*
24982749Sdillon * MPSAFE
25082749Sdillon */
2511541Srgrimes/* ARGSUSED */
2521549Srgrimesint
25393580Sjhbgetgid(struct thread *td, struct getgid_args *uap)
2541541Srgrimes{
2551541Srgrimes
25692987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
257130344Sphk#if defined(COMPAT_43)
25892987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2591541Srgrimes#endif
2601541Srgrimes	return (0);
2611541Srgrimes}
2621541Srgrimes
2631541Srgrimes/*
2641541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2651541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2661541Srgrimes * correctly in a library function.
2671541Srgrimes */
26812221Sbde#ifndef _SYS_SYSPROTO_H_
26911332Sswallacestruct getegid_args {
27011332Sswallace        int     dummy;
27111332Sswallace};
27212221Sbde#endif
27382749Sdillon/*
27482749Sdillon * MPSAFE
27582749Sdillon */
2761541Srgrimes/* ARGSUSED */
2771549Srgrimesint
27893580Sjhbgetegid(struct thread *td, struct getegid_args *uap)
2791541Srgrimes{
2801541Srgrimes
28192987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2821541Srgrimes	return (0);
2831541Srgrimes}
2841541Srgrimes
28512221Sbde#ifndef _SYS_SYSPROTO_H_
2861541Srgrimesstruct getgroups_args {
2871541Srgrimes	u_int	gidsetsize;
2881541Srgrimes	gid_t	*gidset;
2891541Srgrimes};
29012221Sbde#endif
29182749Sdillon/*
29282749Sdillon * MPSAFE
29382749Sdillon */
2941549Srgrimesint
29593580Sjhbgetgroups(struct thread *td, register struct getgroups_args *uap)
2961541Srgrimes{
29782749Sdillon	struct ucred *cred;
29877183Srwatson	u_int ngrp;
29987218Srwatson	int error;
3001541Srgrimes
30192987Sjhb	cred = td->td_ucred;
3021541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
30383366Sjulian		td->td_retval[0] = cred->cr_ngroups;
30492987Sjhb		return (0);
3051541Srgrimes	}
30692987Sjhb	if (ngrp < cred->cr_ngroups)
30792987Sjhb		return (EINVAL);
30877183Srwatson	ngrp = cred->cr_ngroups;
30999009Salfred	error = copyout(cred->cr_groups, uap->gidset, ngrp * sizeof(gid_t));
31093264Sdillon	if (error == 0)
31193557Sjhb		td->td_retval[0] = ngrp;
31293264Sdillon	return (error);
3131541Srgrimes}
3141541Srgrimes
31512221Sbde#ifndef _SYS_SYSPROTO_H_
31612207Sbdestruct setsid_args {
31711332Sswallace        int     dummy;
31811332Sswallace};
31912221Sbde#endif
32082749Sdillon/*
32182749Sdillon * MPSAFE
32282749Sdillon */
3231541Srgrimes/* ARGSUSED */
3241549Srgrimesint
32593580Sjhbsetsid(register struct thread *td, struct setsid_args *uap)
3261541Srgrimes{
32791140Stanimura	struct pgrp *pgrp;
32882749Sdillon	int error;
32983366Sjulian	struct proc *p = td->td_proc;
33091140Stanimura	struct pgrp *newpgrp;
33191140Stanimura	struct session *newsess;
3321541Srgrimes
33391140Stanimura	error = 0;
33491140Stanimura	pgrp = NULL;
33591140Stanimura
336111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
337111119Simp	MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
33891140Stanimura
33994859Sjhb	sx_xlock(&proctree_lock);
34091140Stanimura
34191140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
34291140Stanimura		if (pgrp != NULL)
34391140Stanimura			PGRP_UNLOCK(pgrp);
34482749Sdillon		error = EPERM;
34591140Stanimura	} else {
34691140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
34783366Sjulian		td->td_retval[0] = p->p_pid;
34894859Sjhb		newpgrp = NULL;
34994859Sjhb		newsess = NULL;
3501541Srgrimes	}
35191140Stanimura
35294859Sjhb	sx_xunlock(&proctree_lock);
35391140Stanimura
35495973Stanimura	if (newpgrp != NULL)
35595973Stanimura		FREE(newpgrp, M_PGRP);
35695973Stanimura	if (newsess != NULL)
35795973Stanimura		FREE(newsess, M_SESSION);
35891140Stanimura
35994859Sjhb	return (error);
3601541Srgrimes}
3611541Srgrimes
3621541Srgrimes/*
3631541Srgrimes * set process group (setpgid/old setpgrp)
3641541Srgrimes *
3651541Srgrimes * caller does setpgid(targpid, targpgid)
3661541Srgrimes *
3671541Srgrimes * pid must be caller or child of caller (ESRCH)
3681541Srgrimes * if a child
3691541Srgrimes *	pid must be in same session (EPERM)
3701541Srgrimes *	pid can't have done an exec (EACCES)
3711541Srgrimes * if pgid != pid
3721541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3731541Srgrimes * pid must not be session leader (EPERM)
3741541Srgrimes */
37512221Sbde#ifndef _SYS_SYSPROTO_H_
3761541Srgrimesstruct setpgid_args {
37787218Srwatson	int	pid;		/* target process id */
37887218Srwatson	int	pgid;		/* target pgrp id */
3791541Srgrimes};
38012221Sbde#endif
38182749Sdillon/*
38282749Sdillon * MPSAFE
38382749Sdillon */
3841541Srgrimes/* ARGSUSED */
3851549Srgrimesint
38693580Sjhbsetpgid(struct thread *td, register struct setpgid_args *uap)
3871541Srgrimes{
38883366Sjulian	struct proc *curp = td->td_proc;
38987218Srwatson	register struct proc *targp;	/* target process */
39087218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
39175448Srwatson	int error;
39291140Stanimura	struct pgrp *newpgrp;
3931541Srgrimes
39420677Sbde	if (uap->pgid < 0)
39520677Sbde		return (EINVAL);
39691140Stanimura
39791140Stanimura	error = 0;
39891140Stanimura
399111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
40091140Stanimura
40194859Sjhb	sx_xlock(&proctree_lock);
4021541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
40391140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
40482749Sdillon			error = ESRCH;
40594859Sjhb			goto done;
40675893Sjhb		}
40791140Stanimura		if (!inferior(targp)) {
40891140Stanimura			PROC_UNLOCK(targp);
40991371Stanimura			error = ESRCH;
41094859Sjhb			goto done;
41191140Stanimura		}
412132568Srwatson		if ((error = p_cansee(td, targp))) {
41375893Sjhb			PROC_UNLOCK(targp);
41494859Sjhb			goto done;
41575893Sjhb		}
41675893Sjhb		if (targp->p_pgrp == NULL ||
41775893Sjhb		    targp->p_session != curp->p_session) {
41875893Sjhb			PROC_UNLOCK(targp);
41982749Sdillon			error = EPERM;
42094859Sjhb			goto done;
42175893Sjhb		}
42275893Sjhb		if (targp->p_flag & P_EXEC) {
42375893Sjhb			PROC_UNLOCK(targp);
42482749Sdillon			error = EACCES;
42594859Sjhb			goto done;
42675893Sjhb		}
42791140Stanimura		PROC_UNLOCK(targp);
42891140Stanimura	} else
4291541Srgrimes		targp = curp;
43075893Sjhb	if (SESS_LEADER(targp)) {
43182749Sdillon		error = EPERM;
43294859Sjhb		goto done;
43375893Sjhb	}
43487218Srwatson	if (uap->pgid == 0)
4351541Srgrimes		uap->pgid = targp->p_pid;
436117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
437117214Scognet		if (uap->pgid == targp->p_pid) {
438117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
439117214Scognet			    NULL);
440117214Scognet			if (error == 0)
441117214Scognet				newpgrp = NULL;
442117214Scognet		} else
443117214Scognet			error = EPERM;
44491140Stanimura	} else {
445117214Scognet		if (pgrp == targp->p_pgrp) {
446117214Scognet			PGRP_UNLOCK(pgrp);
44794859Sjhb			goto done;
44875893Sjhb		}
449117214Scognet		if (pgrp->pg_id != targp->p_pid &&
450117214Scognet		    pgrp->pg_session != curp->p_session) {
45191140Stanimura			PGRP_UNLOCK(pgrp);
452117214Scognet			error = EPERM;
45391140Stanimura			goto done;
45491140Stanimura		}
45591140Stanimura		PGRP_UNLOCK(pgrp);
45691140Stanimura		error = enterthispgrp(targp, pgrp);
45782749Sdillon	}
45891140Stanimuradone:
45994859Sjhb	sx_xunlock(&proctree_lock);
46094859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
46194859Sjhb	    ("setpgid failed and newpgrp is NULL"));
46295973Stanimura	if (newpgrp != NULL)
46391140Stanimura		FREE(newpgrp, M_PGRP);
46482749Sdillon	return (error);
4651541Srgrimes}
4661541Srgrimes
46724448Speter/*
46824448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
46972093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47024448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
47124448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
47224448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
47324448Speter * does not set the saved id - this is dangerous for traditional BSD
47424448Speter * programs.  For this reason, we *really* do not want to set
47524448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
47624448Speter */
47724448Speter#define POSIX_APPENDIX_B_4_2_2
47824448Speter
47912221Sbde#ifndef _SYS_SYSPROTO_H_
4801541Srgrimesstruct setuid_args {
4811541Srgrimes	uid_t	uid;
4821541Srgrimes};
48312221Sbde#endif
48482749Sdillon/*
48582749Sdillon * MPSAFE
48682749Sdillon */
4871541Srgrimes/* ARGSUSED */
4881549Srgrimesint
48993580Sjhbsetuid(struct thread *td, struct setuid_args *uap)
4901541Srgrimes{
49183366Sjulian	struct proc *p = td->td_proc;
49277183Srwatson	struct ucred *newcred, *oldcred;
49377183Srwatson	uid_t uid;
49498417Salfred	struct uidinfo *uip;
49587218Srwatson	int error;
4961541Srgrimes
49777183Srwatson	uid = uap->uid;
49894619Sjhb	newcred = crget();
49998417Salfred	uip = uifind(uid);
50094619Sjhb	PROC_LOCK(p);
50187219Srwatson	oldcred = p->p_ucred;
50287466Srwatson
503145147Srwatson#ifdef MAC
504145147Srwatson	error = mac_check_proc_setuid(p, oldcred, uid);
505145147Srwatson	if (error)
506145147Srwatson		goto fail;
507145147Srwatson#endif
508145147Srwatson
50924448Speter	/*
51024448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
51124448Speter	 *
51287218Srwatson	 * Note that setuid(geteuid()) is a special case of
51324448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
51472093Sasmodai	 * to use this clause to be compatible with traditional BSD
51524448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
51624448Speter	 * three id's (assuming you have privs).
51724448Speter	 *
51824448Speter	 * Notes on the logic.  We do things in three steps.
51924448Speter	 * 1: We determine if the euid is going to change, and do EPERM
52024448Speter	 *    right away.  We unconditionally change the euid later if this
52124448Speter	 *    test is satisfied, simplifying that part of the logic.
52287218Srwatson	 * 2: We determine if the real and/or saved uids are going to
52324448Speter	 *    change.  Determined by compile options.
52424448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
52524448Speter	 */
52677183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
52717994Sache#ifdef _POSIX_SAVED_IDS
52877183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
52917994Sache#endif
53024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53177183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
53224448Speter#endif
533145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
534145147Srwatson		goto fail;
53524448Speter
53698417Salfred	/*
53798417Salfred	 * Copy credentials so other references do not see our changes.
53898417Salfred	 */
53994619Sjhb	crcopy(newcred, oldcred);
54024448Speter#ifdef _POSIX_SAVED_IDS
5411541Srgrimes	/*
54224448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
54324448Speter	 * If so, we are changing the real uid and/or saved uid.
5441541Srgrimes	 */
54517994Sache	if (
54624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
54777183Srwatson	    uid == oldcred->cr_uid ||
54817994Sache#endif
549132653Scperciva	    suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */
55017994Sache#endif
55124448Speter	{
55224448Speter		/*
55365495Struckman		 * Set the real uid and transfer proc count to new user.
55424448Speter		 */
55577183Srwatson		if (uid != oldcred->cr_ruid) {
55698417Salfred			change_ruid(newcred, uip);
55765495Struckman			setsugid(p);
55824448Speter		}
55924448Speter		/*
56024448Speter		 * Set saved uid
56124448Speter		 *
56224448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
56324448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
56424448Speter		 * is important that we should do this.
56524448Speter		 */
56677183Srwatson		if (uid != oldcred->cr_svuid) {
56777183Srwatson			change_svuid(newcred, uid);
56831891Ssef			setsugid(p);
56924448Speter		}
5708141Sache	}
57124448Speter
57224448Speter	/*
57324448Speter	 * In all permitted cases, we are changing the euid.
57424448Speter	 */
57577183Srwatson	if (uid != oldcred->cr_uid) {
57698417Salfred		change_euid(newcred, uip);
57731891Ssef		setsugid(p);
57824448Speter	}
57977183Srwatson	p->p_ucred = newcred;
58094619Sjhb	PROC_UNLOCK(p);
58198417Salfred	uifree(uip);
58277183Srwatson	crfree(oldcred);
58394619Sjhb	return (0);
584145147Srwatson
585145147Srwatsonfail:
586145147Srwatson	PROC_UNLOCK(p);
587145147Srwatson	uifree(uip);
588145147Srwatson	crfree(newcred);
589145147Srwatson	return (error);
5901541Srgrimes}
5911541Srgrimes
59212221Sbde#ifndef _SYS_SYSPROTO_H_
5931541Srgrimesstruct seteuid_args {
5941541Srgrimes	uid_t	euid;
5951541Srgrimes};
59612221Sbde#endif
59782749Sdillon/*
59882749Sdillon * MPSAFE
59982749Sdillon */
6001541Srgrimes/* ARGSUSED */
6011549Srgrimesint
60293580Sjhbseteuid(struct thread *td, struct seteuid_args *uap)
6031541Srgrimes{
60483366Sjulian	struct proc *p = td->td_proc;
60577183Srwatson	struct ucred *newcred, *oldcred;
60677183Srwatson	uid_t euid;
60798417Salfred	struct uidinfo *euip;
60887218Srwatson	int error;
6091541Srgrimes
6101541Srgrimes	euid = uap->euid;
61194619Sjhb	newcred = crget();
61298417Salfred	euip = uifind(euid);
61394619Sjhb	PROC_LOCK(p);
61477183Srwatson	oldcred = p->p_ucred;
615145147Srwatson
616145147Srwatson#ifdef MAC
617145147Srwatson	error = mac_check_proc_seteuid(p, oldcred, euid);
618145147Srwatson	if (error)
619145147Srwatson		goto fail;
620145147Srwatson#endif
621145147Srwatson
62277183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
62377183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
624145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
625145147Srwatson		goto fail;
626145147Srwatson
6271541Srgrimes	/*
6281541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
6291541Srgrimes	 * not see our changes.
6301541Srgrimes	 */
63194619Sjhb	crcopy(newcred, oldcred);
63277183Srwatson	if (oldcred->cr_uid != euid) {
63398417Salfred		change_euid(newcred, euip);
63431891Ssef		setsugid(p);
63524449Speter	}
63677183Srwatson	p->p_ucred = newcred;
63794619Sjhb	PROC_UNLOCK(p);
63898417Salfred	uifree(euip);
63977183Srwatson	crfree(oldcred);
64094619Sjhb	return (0);
641145147Srwatson
642145147Srwatsonfail:
643145147Srwatson	PROC_UNLOCK(p);
644145147Srwatson	uifree(euip);
645145147Srwatson	crfree(newcred);
646145147Srwatson	return (error);
6471541Srgrimes}
6481541Srgrimes
64912221Sbde#ifndef _SYS_SYSPROTO_H_
6501541Srgrimesstruct setgid_args {
6511541Srgrimes	gid_t	gid;
6521541Srgrimes};
65312221Sbde#endif
65482749Sdillon/*
65582749Sdillon * MPSAFE
65682749Sdillon */
6571541Srgrimes/* ARGSUSED */
6581549Srgrimesint
65993580Sjhbsetgid(struct thread *td, struct setgid_args *uap)
6601541Srgrimes{
66183366Sjulian	struct proc *p = td->td_proc;
66277183Srwatson	struct ucred *newcred, *oldcred;
66377183Srwatson	gid_t gid;
66487218Srwatson	int error;
6651541Srgrimes
66677183Srwatson	gid = uap->gid;
66794619Sjhb	newcred = crget();
66894619Sjhb	PROC_LOCK(p);
66977183Srwatson	oldcred = p->p_ucred;
67087466Srwatson
671145147Srwatson#ifdef MAC
672145147Srwatson	error = mac_check_proc_setgid(p, oldcred, gid);
673145147Srwatson	if (error)
674145147Srwatson		goto fail;
675145147Srwatson#endif
676145147Srwatson
67724448Speter	/*
67824448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
67924448Speter	 *
68024448Speter	 * Note that setgid(getegid()) is a special case of
68124448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
68272093Sasmodai	 * to use this clause to be compatible with traditional BSD
68324448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
68424448Speter	 * three id's (assuming you have privs).
68524448Speter	 *
68624448Speter	 * For notes on the logic here, see setuid() above.
68724448Speter	 */
68877183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
68917994Sache#ifdef _POSIX_SAVED_IDS
69077183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
69117994Sache#endif
69224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
69377183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
69424448Speter#endif
695145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
696145147Srwatson		goto fail;
69724448Speter
69894619Sjhb	crcopy(newcred, oldcred);
69917994Sache#ifdef _POSIX_SAVED_IDS
70024448Speter	/*
70124448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
70224448Speter	 * If so, we are changing the real uid and saved gid.
70324448Speter	 */
70424448Speter	if (
70524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
70677183Srwatson	    gid == oldcred->cr_groups[0] ||
70717994Sache#endif
708132653Scperciva	    suser_cred(oldcred, SUSER_ALLOWJAIL) == 0) /* we are using privs */
70924448Speter#endif
71024448Speter	{
71124448Speter		/*
71224448Speter		 * Set real gid
71324448Speter		 */
71477183Srwatson		if (oldcred->cr_rgid != gid) {
71577183Srwatson			change_rgid(newcred, gid);
71631891Ssef			setsugid(p);
71724448Speter		}
71824448Speter		/*
71924448Speter		 * Set saved gid
72024448Speter		 *
72124448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
72224448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
72324448Speter		 * is important that we should do this.
72424448Speter		 */
72577183Srwatson		if (oldcred->cr_svgid != gid) {
72677183Srwatson			change_svgid(newcred, gid);
72731891Ssef			setsugid(p);
72824448Speter		}
7298141Sache	}
73024448Speter	/*
73124448Speter	 * In all cases permitted cases, we are changing the egid.
73224448Speter	 * Copy credentials so other references do not see our changes.
73324448Speter	 */
73477183Srwatson	if (oldcred->cr_groups[0] != gid) {
73577183Srwatson		change_egid(newcred, gid);
73631891Ssef		setsugid(p);
73724448Speter	}
73877183Srwatson	p->p_ucred = newcred;
73994619Sjhb	PROC_UNLOCK(p);
74077183Srwatson	crfree(oldcred);
74194619Sjhb	return (0);
742145147Srwatson
743145147Srwatsonfail:
744145147Srwatson	PROC_UNLOCK(p);
745145147Srwatson	crfree(newcred);
746145147Srwatson	return (error);
7471541Srgrimes}
7481541Srgrimes
74912221Sbde#ifndef _SYS_SYSPROTO_H_
7501541Srgrimesstruct setegid_args {
7511541Srgrimes	gid_t	egid;
7521541Srgrimes};
75312221Sbde#endif
75482749Sdillon/*
75582749Sdillon * MPSAFE
75682749Sdillon */
7571541Srgrimes/* ARGSUSED */
7581549Srgrimesint
75993580Sjhbsetegid(struct thread *td, struct setegid_args *uap)
7601541Srgrimes{
76183366Sjulian	struct proc *p = td->td_proc;
76277183Srwatson	struct ucred *newcred, *oldcred;
76377183Srwatson	gid_t egid;
76487218Srwatson	int error;
7651541Srgrimes
7661541Srgrimes	egid = uap->egid;
76794619Sjhb	newcred = crget();
76894619Sjhb	PROC_LOCK(p);
76977183Srwatson	oldcred = p->p_ucred;
770145147Srwatson
771145147Srwatson#ifdef MAC
772145147Srwatson	error = mac_check_proc_setegid(p, oldcred, egid);
773145147Srwatson	if (error)
774145147Srwatson		goto fail;
775145147Srwatson#endif
776145147Srwatson
77777183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
77877183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
779145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
780145147Srwatson		goto fail;
781145147Srwatson
78294619Sjhb	crcopy(newcred, oldcred);
78377183Srwatson	if (oldcred->cr_groups[0] != egid) {
78477183Srwatson		change_egid(newcred, egid);
78531891Ssef		setsugid(p);
78624449Speter	}
78777183Srwatson	p->p_ucred = newcred;
78894619Sjhb	PROC_UNLOCK(p);
78977183Srwatson	crfree(oldcred);
79094619Sjhb	return (0);
791145147Srwatson
792145147Srwatsonfail:
793145147Srwatson	PROC_UNLOCK(p);
794145147Srwatson	crfree(newcred);
795145147Srwatson	return (error);
7961541Srgrimes}
7971541Srgrimes
79812221Sbde#ifndef _SYS_SYSPROTO_H_
7991541Srgrimesstruct setgroups_args {
8001541Srgrimes	u_int	gidsetsize;
8011541Srgrimes	gid_t	*gidset;
8021541Srgrimes};
80312221Sbde#endif
80482749Sdillon/*
80582749Sdillon * MPSAFE
80682749Sdillon */
8071541Srgrimes/* ARGSUSED */
8081549Srgrimesint
80993580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap)
8101541Srgrimes{
81183366Sjulian	struct proc *p = td->td_proc;
81294619Sjhb	struct ucred *newcred, *tempcred, *oldcred;
81377183Srwatson	u_int ngrp;
8141541Srgrimes	int error;
8151541Srgrimes
81687220Srwatson	ngrp = uap->gidsetsize;
81794619Sjhb	if (ngrp > NGROUPS)
81894619Sjhb		return (EINVAL);
81994619Sjhb	tempcred = crget();
82099009Salfred	error = copyin(uap->gidset, tempcred->cr_groups, ngrp * sizeof(gid_t));
82194619Sjhb	if (error != 0) {
82294619Sjhb		crfree(tempcred);
82394619Sjhb		return (error);
82494619Sjhb	}
82594619Sjhb	newcred = crget();
82694619Sjhb	PROC_LOCK(p);
82777183Srwatson	oldcred = p->p_ucred;
828145147Srwatson
829145147Srwatson#ifdef MAC
830145147Srwatson	error = mac_check_proc_setgroups(p, oldcred, ngrp,
831145147Srwatson	    tempcred->cr_groups);
832145147Srwatson	if (error)
833145147Srwatson		goto fail;
834145147Srwatson#endif
835145147Srwatson
836132653Scperciva	error = suser_cred(oldcred, SUSER_ALLOWJAIL);
837145147Srwatson	if (error)
838145147Srwatson		goto fail;
839145147Srwatson
84024447Speter	/*
84124447Speter	 * XXX A little bit lazy here.  We could test if anything has
84224447Speter	 * changed before crcopy() and setting P_SUGID.
84324447Speter	 */
84494619Sjhb	crcopy(newcred, oldcred);
84524447Speter	if (ngrp < 1) {
84624447Speter		/*
84724447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
84824447Speter		 * groups vector on non-BSD systems (which generally do not
84924447Speter		 * have the egid in the groups[0]).  We risk security holes
85024447Speter		 * when running non-BSD software if we do not do the same.
85124447Speter		 */
85277183Srwatson		newcred->cr_ngroups = 1;
85324447Speter	} else {
85494619Sjhb		bcopy(tempcred->cr_groups, newcred->cr_groups,
85594619Sjhb		    ngrp * sizeof(gid_t));
85677183Srwatson		newcred->cr_ngroups = ngrp;
85724447Speter	}
85831891Ssef	setsugid(p);
85977183Srwatson	p->p_ucred = newcred;
86094619Sjhb	PROC_UNLOCK(p);
86194619Sjhb	crfree(tempcred);
86277183Srwatson	crfree(oldcred);
86394619Sjhb	return (0);
864145147Srwatson
865145147Srwatsonfail:
866145147Srwatson	PROC_UNLOCK(p);
867145147Srwatson	crfree(newcred);
868145147Srwatson	crfree(tempcred);
869145147Srwatson	return (error);
8701541Srgrimes}
8711541Srgrimes
87212221Sbde#ifndef _SYS_SYSPROTO_H_
8731541Srgrimesstruct setreuid_args {
8749238Sache	uid_t	ruid;
8759238Sache	uid_t	euid;
8761541Srgrimes};
87712221Sbde#endif
87882749Sdillon/*
87982749Sdillon * MPSAFE
88082749Sdillon */
8811541Srgrimes/* ARGSUSED */
8821549Srgrimesint
88393580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap)
8841541Srgrimes{
88583366Sjulian	struct proc *p = td->td_proc;
88677183Srwatson	struct ucred *newcred, *oldcred;
88787218Srwatson	uid_t euid, ruid;
88898417Salfred	struct uidinfo *euip, *ruip;
88987218Srwatson	int error;
8901541Srgrimes
89187218Srwatson	euid = uap->euid;
8929238Sache	ruid = uap->ruid;
89394619Sjhb	newcred = crget();
89498417Salfred	euip = uifind(euid);
89598417Salfred	ruip = uifind(ruid);
89694619Sjhb	PROC_LOCK(p);
89777183Srwatson	oldcred = p->p_ucred;
898145147Srwatson
899145147Srwatson#ifdef MAC
900145147Srwatson	error = mac_check_proc_setreuid(p, oldcred, ruid, euid);
901145147Srwatson	if (error)
902145147Srwatson		goto fail;
903145147Srwatson#endif
904145147Srwatson
90577183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
90677183Srwatson	      ruid != oldcred->cr_svuid) ||
90777183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
90877183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
909145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
910145147Srwatson		goto fail;
911145147Srwatson
91294619Sjhb	crcopy(newcred, oldcred);
91377183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
91498417Salfred		change_euid(newcred, euip);
91531891Ssef		setsugid(p);
91624450Speter	}
91777183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
91898417Salfred		change_ruid(newcred, ruip);
91931891Ssef		setsugid(p);
9208135Sache	}
92177183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
92277183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
92377183Srwatson		change_svuid(newcred, newcred->cr_uid);
92431891Ssef		setsugid(p);
92524450Speter	}
92677183Srwatson	p->p_ucred = newcred;
92794619Sjhb	PROC_UNLOCK(p);
92898417Salfred	uifree(ruip);
92998417Salfred	uifree(euip);
93077183Srwatson	crfree(oldcred);
93194619Sjhb	return (0);
932145147Srwatson
933145147Srwatsonfail:
934145147Srwatson	PROC_UNLOCK(p);
935145147Srwatson	uifree(ruip);
936145147Srwatson	uifree(euip);
937145147Srwatson	crfree(newcred);
938145147Srwatson	return (error);
9391541Srgrimes}
9401541Srgrimes
94112221Sbde#ifndef _SYS_SYSPROTO_H_
9421541Srgrimesstruct setregid_args {
9439238Sache	gid_t	rgid;
9449238Sache	gid_t	egid;
9451541Srgrimes};
94612221Sbde#endif
94782749Sdillon/*
94882749Sdillon * MPSAFE
94982749Sdillon */
9501541Srgrimes/* ARGSUSED */
9511549Srgrimesint
95293580Sjhbsetregid(register struct thread *td, struct setregid_args *uap)
9531541Srgrimes{
95483366Sjulian	struct proc *p = td->td_proc;
95577183Srwatson	struct ucred *newcred, *oldcred;
95687218Srwatson	gid_t egid, rgid;
95787218Srwatson	int error;
9581541Srgrimes
95987218Srwatson	egid = uap->egid;
9609238Sache	rgid = uap->rgid;
96194619Sjhb	newcred = crget();
96294619Sjhb	PROC_LOCK(p);
96377183Srwatson	oldcred = p->p_ucred;
964145147Srwatson
965145147Srwatson#ifdef MAC
966145147Srwatson	error = mac_check_proc_setregid(p, oldcred, rgid, egid);
967145147Srwatson	if (error)
968145147Srwatson		goto fail;
969145147Srwatson#endif
970145147Srwatson
97177183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
97277183Srwatson	    rgid != oldcred->cr_svgid) ||
97377183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
97477183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
975145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
976145147Srwatson		goto fail;
97794619Sjhb
97894619Sjhb	crcopy(newcred, oldcred);
97977183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
98077183Srwatson		change_egid(newcred, egid);
98131891Ssef		setsugid(p);
98224450Speter	}
98377183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
98477183Srwatson		change_rgid(newcred, rgid);
98531891Ssef		setsugid(p);
98624450Speter	}
98777183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
98877183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
98977183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
99031891Ssef		setsugid(p);
99124450Speter	}
99277812Sru	p->p_ucred = newcred;
99394619Sjhb	PROC_UNLOCK(p);
99477812Sru	crfree(oldcred);
99594619Sjhb	return (0);
996145147Srwatson
997145147Srwatsonfail:
998145147Srwatson	PROC_UNLOCK(p);
999145147Srwatson	crfree(newcred);
1000145147Srwatson	return (error);
10011541Srgrimes}
10021541Srgrimes
100356115Speter/*
100456115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
100556115Speter * saved uid is explicit.
100656115Speter */
100756115Speter
100824453Speter#ifndef _SYS_SYSPROTO_H_
100956115Speterstruct setresuid_args {
101056115Speter	uid_t	ruid;
101156115Speter	uid_t	euid;
101256115Speter	uid_t	suid;
101356115Speter};
101456115Speter#endif
101582749Sdillon/*
101682749Sdillon * MPSAFE
101782749Sdillon */
101856115Speter/* ARGSUSED */
101956115Speterint
102093580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap)
102156115Speter{
102283366Sjulian	struct proc *p = td->td_proc;
102377183Srwatson	struct ucred *newcred, *oldcred;
102487218Srwatson	uid_t euid, ruid, suid;
102598417Salfred	struct uidinfo *euip, *ruip;
102656115Speter	int error;
102756115Speter
102887218Srwatson	euid = uap->euid;
102956115Speter	ruid = uap->ruid;
103056115Speter	suid = uap->suid;
103194619Sjhb	newcred = crget();
103298417Salfred	euip = uifind(euid);
103398417Salfred	ruip = uifind(ruid);
103494619Sjhb	PROC_LOCK(p);
103577183Srwatson	oldcred = p->p_ucred;
1036145147Srwatson
1037145147Srwatson#ifdef MAC
1038145147Srwatson	error = mac_check_proc_setresuid(p, oldcred, ruid, euid, suid);
1039145147Srwatson	if (error)
1040145147Srwatson		goto fail;
1041145147Srwatson#endif
1042145147Srwatson
104377183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
104477183Srwatson	     ruid != oldcred->cr_svuid &&
104577183Srwatson	      ruid != oldcred->cr_uid) ||
104677183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
104777183Srwatson	    euid != oldcred->cr_svuid &&
104877183Srwatson	      euid != oldcred->cr_uid) ||
104977183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
105077183Srwatson	    suid != oldcred->cr_svuid &&
105177183Srwatson	      suid != oldcred->cr_uid)) &&
1052145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
1053145147Srwatson		goto fail;
105494619Sjhb
105594619Sjhb	crcopy(newcred, oldcred);
105677183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
105798417Salfred		change_euid(newcred, euip);
105856115Speter		setsugid(p);
105956115Speter	}
106077183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
106198417Salfred		change_ruid(newcred, ruip);
106256115Speter		setsugid(p);
106356115Speter	}
106477183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
106577183Srwatson		change_svuid(newcred, suid);
106656115Speter		setsugid(p);
106756115Speter	}
106877183Srwatson	p->p_ucred = newcred;
106994619Sjhb	PROC_UNLOCK(p);
107098417Salfred	uifree(ruip);
107198417Salfred	uifree(euip);
107277183Srwatson	crfree(oldcred);
107394619Sjhb	return (0);
1074145147Srwatson
1075145147Srwatsonfail:
1076145147Srwatson	PROC_UNLOCK(p);
1077145147Srwatson	uifree(ruip);
1078145147Srwatson	uifree(euip);
1079145147Srwatson	crfree(newcred);
1080145147Srwatson	return (error);
1081145147Srwatson
108256115Speter}
108356115Speter
108456115Speter/*
108556115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
108656115Speter * saved gid is explicit.
108756115Speter */
108856115Speter
108956115Speter#ifndef _SYS_SYSPROTO_H_
109056115Speterstruct setresgid_args {
109156115Speter	gid_t	rgid;
109256115Speter	gid_t	egid;
109356115Speter	gid_t	sgid;
109456115Speter};
109556115Speter#endif
109687466Srwatson/*
109782749Sdillon * MPSAFE
109882749Sdillon */
109956115Speter/* ARGSUSED */
110056115Speterint
110193580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap)
110256115Speter{
110383366Sjulian	struct proc *p = td->td_proc;
110477183Srwatson	struct ucred *newcred, *oldcred;
110587218Srwatson	gid_t egid, rgid, sgid;
110656115Speter	int error;
110756115Speter
110887218Srwatson	egid = uap->egid;
110956115Speter	rgid = uap->rgid;
111056115Speter	sgid = uap->sgid;
111194619Sjhb	newcred = crget();
111294619Sjhb	PROC_LOCK(p);
111377183Srwatson	oldcred = p->p_ucred;
1114145147Srwatson
1115145147Srwatson#ifdef MAC
1116145147Srwatson	error = mac_check_proc_setresgid(p, oldcred, rgid, egid, sgid);
1117145147Srwatson	if (error)
1118145147Srwatson		goto fail;
1119145147Srwatson#endif
1120145147Srwatson
112177183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
112277183Srwatson	      rgid != oldcred->cr_svgid &&
112377183Srwatson	      rgid != oldcred->cr_groups[0]) ||
112477183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
112577183Srwatson	      egid != oldcred->cr_svgid &&
112677183Srwatson	      egid != oldcred->cr_groups[0]) ||
112777183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
112877183Srwatson	      sgid != oldcred->cr_svgid &&
112977183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1130145147Srwatson	    (error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0)
1131145147Srwatson		goto fail;
113294619Sjhb
113394619Sjhb	crcopy(newcred, oldcred);
113477183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
113577183Srwatson		change_egid(newcred, egid);
113656115Speter		setsugid(p);
113756115Speter	}
113877183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
113977183Srwatson		change_rgid(newcred, rgid);
114056115Speter		setsugid(p);
114156115Speter	}
114277183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
114377183Srwatson		change_svgid(newcred, sgid);
114456115Speter		setsugid(p);
114556115Speter	}
114677183Srwatson	p->p_ucred = newcred;
114794619Sjhb	PROC_UNLOCK(p);
114877183Srwatson	crfree(oldcred);
114994619Sjhb	return (0);
1150145147Srwatson
1151145147Srwatsonfail:
1152145147Srwatson	PROC_UNLOCK(p);
1153145147Srwatson	crfree(newcred);
1154145147Srwatson	return (error);
115556115Speter}
115656115Speter
115756115Speter#ifndef _SYS_SYSPROTO_H_
115856115Speterstruct getresuid_args {
115956115Speter	uid_t	*ruid;
116056115Speter	uid_t	*euid;
116156115Speter	uid_t	*suid;
116256115Speter};
116356115Speter#endif
116482749Sdillon/*
116582749Sdillon * MPSAFE
116682749Sdillon */
116756115Speter/* ARGSUSED */
116856115Speterint
116993580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap)
117056115Speter{
117182749Sdillon	struct ucred *cred;
117256115Speter	int error1 = 0, error2 = 0, error3 = 0;
117356115Speter
117493264Sdillon	cred = td->td_ucred;
117556115Speter	if (uap->ruid)
117699009Salfred		error1 = copyout(&cred->cr_ruid,
117799009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
117856115Speter	if (uap->euid)
117999009Salfred		error2 = copyout(&cred->cr_uid,
118099009Salfred		    uap->euid, sizeof(cred->cr_uid));
118156115Speter	if (uap->suid)
118299009Salfred		error3 = copyout(&cred->cr_svuid,
118399009Salfred		    uap->suid, sizeof(cred->cr_svuid));
118487218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
118556115Speter}
118656115Speter
118756115Speter#ifndef _SYS_SYSPROTO_H_
118856115Speterstruct getresgid_args {
118956115Speter	gid_t	*rgid;
119056115Speter	gid_t	*egid;
119156115Speter	gid_t	*sgid;
119256115Speter};
119356115Speter#endif
119482749Sdillon/*
119582749Sdillon * MPSAFE
119682749Sdillon */
119756115Speter/* ARGSUSED */
119856115Speterint
119993580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap)
120056115Speter{
120182749Sdillon	struct ucred *cred;
120256115Speter	int error1 = 0, error2 = 0, error3 = 0;
120356115Speter
120493264Sdillon	cred = td->td_ucred;
120556115Speter	if (uap->rgid)
120699009Salfred		error1 = copyout(&cred->cr_rgid,
120799009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
120856115Speter	if (uap->egid)
120999009Salfred		error2 = copyout(&cred->cr_groups[0],
121099009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
121156115Speter	if (uap->sgid)
121299009Salfred		error3 = copyout(&cred->cr_svgid,
121399009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
121487218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
121556115Speter}
121656115Speter
121756115Speter#ifndef _SYS_SYSPROTO_H_
121824453Speterstruct issetugid_args {
121924453Speter	int dummy;
122024453Speter};
122124453Speter#endif
122287218Srwatson/*
1223116121Sjhb * MPSAFE
122487218Srwatson */
122524453Speter/* ARGSUSED */
122624453Speterint
122793580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap)
122824453Speter{
122983366Sjulian	struct proc *p = td->td_proc;
123083366Sjulian
123124453Speter	/*
123224453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
123324453Speter	 * we use P_SUGID because we consider changing the owners as
123424453Speter	 * "tainting" as well.
123524453Speter	 * This is significant for procs that start as root and "become"
123624453Speter	 * a user without an exec - programs cannot know *everything*
123724453Speter	 * that libc *might* have put in their data segment.
123824453Speter	 */
123991140Stanimura	PROC_LOCK(p);
124083366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
124191140Stanimura	PROC_UNLOCK(p);
124224453Speter	return (0);
124324453Speter}
124424453Speter
124582749Sdillon/*
124682749Sdillon * MPSAFE
124782749Sdillon */
124875426Srwatsonint
124993580Sjhb__setugid(struct thread *td, struct __setugid_args *uap)
125075426Srwatson{
125182749Sdillon#ifdef REGRESSION
125294619Sjhb	struct proc *p;
125375426Srwatson
125494619Sjhb	p = td->td_proc;
125575426Srwatson	switch (uap->flag) {
125675426Srwatson	case 0:
125794619Sjhb		PROC_LOCK(p);
125894619Sjhb		p->p_flag &= ~P_SUGID;
125994619Sjhb		PROC_UNLOCK(p);
126094619Sjhb		return (0);
126175426Srwatson	case 1:
126294619Sjhb		PROC_LOCK(p);
126394619Sjhb		p->p_flag |= P_SUGID;
126494619Sjhb		PROC_UNLOCK(p);
126594619Sjhb		return (0);
126675426Srwatson	default:
126794619Sjhb		return (EINVAL);
126875426Srwatson	}
126975426Srwatson#else /* !REGRESSION */
127087218Srwatson
127175426Srwatson	return (ENOSYS);
127287218Srwatson#endif /* REGRESSION */
127375426Srwatson}
127475426Srwatson
12751541Srgrimes/*
12761541Srgrimes * Check if gid is a member of the group set.
127793264Sdillon *
127893264Sdillon * MPSAFE (cred must be held)
12791541Srgrimes */
12801549Srgrimesint
128193580Sjhbgroupmember(gid_t gid, struct ucred *cred)
12821541Srgrimes{
12831541Srgrimes	register gid_t *gp;
12841541Srgrimes	gid_t *egp;
12851541Srgrimes
12861541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
12871541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
12881541Srgrimes		if (*gp == gid)
12891541Srgrimes			return (1);
12901541Srgrimes	return (0);
12911541Srgrimes}
12921541Srgrimes
129382424Srwatson/*
129489414Sarr * `suser_enabled' (which can be set by the security.suser_enabled
129582466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect.
129682466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege,
129782466Srwatson * overriding many mandatory and discretionary protections.  If it is zero,
129882466Srwatson * uid 0 is offered no special privilege in the kernel security policy.
129982466Srwatson * Setting it to zero may seriously impact the functionality of many
130082466Srwatson * existing userland programs, and should not be done without careful
130182466Srwatson * consideration of the consequences.
130282424Srwatson */
130382693Srwatsonint	suser_enabled = 1;
130489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW,
130582693Srwatson    &suser_enabled, 0, "processes with uid 0 have privilege");
130689414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled);
130761287Srwatson
13081541Srgrimes/*
130982466Srwatson * Test whether the specified credentials imply "super-user" privilege.
1310132255Scperciva * Return 0 or EPERM.
13111541Srgrimes */
13121549Srgrimesint
131393593Sjhbsuser_cred(struct ucred *cred, int flag)
131446112Sphk{
131587218Srwatson
131682693Srwatson	if (!suser_enabled)
131761282Srwatson		return (EPERM);
1318132255Scperciva	if (((flag & SUSER_RUID) ? cred->cr_ruid : cred->cr_uid) != 0)
131946155Sphk		return (EPERM);
1320132653Scperciva	if (jailed(cred) && !(flag & SUSER_ALLOWJAIL))
132146155Sphk		return (EPERM);
132246155Sphk	return (0);
13231541Srgrimes}
13241541Srgrimes
132583639Srwatson/*
132693593Sjhb * Shortcut to hide contents of struct td and struct proc from the
132793593Sjhb * caller, promoting binary compatibility.
132893593Sjhb */
132993593Sjhbint
133093593Sjhbsuser(struct thread *td)
133193593Sjhb{
133293593Sjhb
1333132548Srwatson#ifdef INVARIANTS
1334132548Srwatson	if (td != curthread) {
1335132548Srwatson		printf("suser: thread %p (%d %s) != curthread %p (%d %s)\n",
1336132548Srwatson		    td, td->td_proc->p_pid, td->td_proc->p_comm,
1337132548Srwatson		    curthread, curthread->td_proc->p_pid,
1338132548Srwatson		    curthread->td_proc->p_comm);
1339132548Srwatson#ifdef KDB
1340132548Srwatson		kdb_backtrace();
1341132548Srwatson#endif
1342132548Srwatson	}
1343132548Srwatson#endif
134493593Sjhb	return (suser_cred(td->td_ucred, 0));
134593593Sjhb}
134693593Sjhb
134793593Sjhb/*
134887218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
134987218Srwatson * implements (securelevel > level).  securelevel_ge() implements
135087218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
135187218Srwatson * functions return EPERM on "success" and 0 on "failure".
135283639Srwatson *
135393264Sdillon * MPSAFE
135483639Srwatson */
135583639Srwatsonint
135683639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
135783639Srwatson{
135887218Srwatson	int active_securelevel;
135983639Srwatson
136087218Srwatson	active_securelevel = securelevel;
136193732Sjhb	KASSERT(cr != NULL, ("securelevel_gt: null cr"));
1362140678Srwatson	if (cr->cr_prison != NULL)
136387218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
136487218Srwatson		    active_securelevel);
136587218Srwatson	return (active_securelevel > level ? EPERM : 0);
136683639Srwatson}
136783639Srwatson
136883639Srwatsonint
136983639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
137083639Srwatson{
137187218Srwatson	int active_securelevel;
137283639Srwatson
137387218Srwatson	active_securelevel = securelevel;
137493732Sjhb	KASSERT(cr != NULL, ("securelevel_ge: null cr"));
1375140678Srwatson	if (cr->cr_prison != NULL)
137687218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
137787218Srwatson		    active_securelevel);
137887218Srwatson	return (active_securelevel >= level ? EPERM : 0);
137983639Srwatson}
138083639Srwatson
138184736Srwatson/*
138287144Srwatson * 'see_other_uids' determines whether or not visibility of processes
138387218Srwatson * and sockets with credentials holding different real uids is possible
138487138Srwatson * using a variety of system MIBs.
138587218Srwatson * XXX: data declarations should be together near the beginning of the file.
138684736Srwatson */
138787144Srwatsonstatic int	see_other_uids = 1;
138889414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
138987218Srwatson    &see_other_uids, 0,
139084736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
139184736Srwatson
139282466Srwatson/*-
139392923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
139492923Srwatson * 'see_other_uids' policy.
139592923Srwatson * Returns: 0 for permitted, ESRCH otherwise
139692923Srwatson * Locks: none
139792923Srwatson * References: *u1 and *u2 must not change during the call
139892923Srwatson *             u1 may equal u2, in which case only one reference is required
139992923Srwatson */
140092923Srwatsonstatic int
140192923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
140292923Srwatson{
140392923Srwatson
140492923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1405132653Scperciva		if (suser_cred(u1, SUSER_ALLOWJAIL) != 0)
140692923Srwatson			return (ESRCH);
140792923Srwatson	}
140892923Srwatson	return (0);
140992923Srwatson}
141092923Srwatson
1411122869Srwatson/*
1412122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1413122869Srwatson * and sockets with credentials holding different real gids is possible
1414122869Srwatson * using a variety of system MIBs.
1415122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1416122869Srwatson */
1417122869Srwatsonstatic int	see_other_gids = 1;
1418122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1419122869Srwatson    &see_other_gids, 0,
1420122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1421122869Srwatson
1422122869Srwatson/*
1423122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1424122869Srwatson * 'see_other_gids' policy.
1425122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1426122869Srwatson * Locks: none
1427122869Srwatson * References: *u1 and *u2 must not change during the call
1428122869Srwatson *             u1 may equal u2, in which case only one reference is required
1429122869Srwatson */
1430122869Srwatsonstatic int
1431122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1432122869Srwatson{
1433122869Srwatson	int i, match;
1434122869Srwatson
1435122869Srwatson	if (!see_other_gids) {
1436122869Srwatson		match = 0;
1437122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1438122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1439122869Srwatson				match = 1;
1440122869Srwatson			if (match)
1441122869Srwatson				break;
1442122869Srwatson		}
1443122869Srwatson		if (!match) {
1444132653Scperciva			if (suser_cred(u1, SUSER_ALLOWJAIL) != 0)
1445122869Srwatson				return (ESRCH);
1446122869Srwatson		}
1447122869Srwatson	}
1448122869Srwatson	return (0);
1449122869Srwatson}
1450122869Srwatson
145192923Srwatson/*-
145282466Srwatson * Determine if u1 "can see" the subject specified by u2.
145374956Srwatson * Returns: 0 for permitted, an errno value otherwise
145474956Srwatson * Locks: none
145587218Srwatson * References: *u1 and *u2 must not change during the call
145674956Srwatson *             u1 may equal u2, in which case only one reference is required
145774956Srwatson */
145874956Srwatsonint
145983742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
146065237Srwatson{
146172786Srwatson	int error;
146253518Sphk
146374956Srwatson	if ((error = prison_check(u1, u2)))
146472786Srwatson		return (error);
1465101003Srwatson#ifdef MAC
1466101003Srwatson	if ((error = mac_check_cred_visible(u1, u2)))
1467101003Srwatson		return (error);
1468101003Srwatson#endif
146992923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
147092923Srwatson		return (error);
1471122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1472122869Srwatson		return (error);
147365237Srwatson	return (0);
147465237Srwatson}
147565237Srwatson
147682466Srwatson/*-
147796886Sjhb * Determine if td "can see" the subject specified by p.
147882424Srwatson * Returns: 0 for permitted, an errno value otherwise
147996886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
148096886Sjhb *        should be curthread.
148196886Sjhb * References: td and p must be valid for the lifetime of the call
148282424Srwatson */
148379335Srwatsonint
148496886Sjhbp_cansee(struct thread *td, struct proc *p)
148574956Srwatson{
148674956Srwatson
148783742Srwatson	/* Wrap cr_cansee() for all functionality. */
148896886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
148996886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
149096886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
149174956Srwatson}
149274956Srwatson
1493120052Srwatson/*
1494120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1495120052Srwatson * signals by unprivileged processes to processes that have changed their
1496120052Srwatson * credentials since the last invocation of execve().  This can prevent
1497120052Srwatson * the leakage of cached information or retained privileges as a result
1498120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1499120052Srwatson * may interfere with some applications that expect to be able to
1500120052Srwatson * deliver these signals to peer processes after having given up
1501120052Srwatson * privilege.
1502120052Srwatson */
1503120052Srwatsonstatic int	conservative_signals = 1;
1504120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1505120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1506120052Srwatson    "sending certain signals to processes whose credentials have changed");
150782466Srwatson/*-
150888943Srwatson * Determine whether cred may deliver the specified signal to proc.
150988943Srwatson * Returns: 0 for permitted, an errno value otherwise.
151088943Srwatson * Locks: A lock must be held for proc.
151188943Srwatson * References: cred and proc must be valid for the lifetime of the call.
151275437Srwatson */
151375437Srwatsonint
1514141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum)
151553518Sphk{
151682466Srwatson	int error;
151784826Sjhb
151896886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
151975437Srwatson	/*
152088943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
152188943Srwatson	 * same jail as cred, if cred is in jail.
152275437Srwatson	 */
152388943Srwatson	error = prison_check(cred, proc->p_ucred);
152488943Srwatson	if (error)
152572786Srwatson		return (error);
1526101003Srwatson#ifdef MAC
1527101003Srwatson	if ((error = mac_check_proc_signal(cred, proc, signum)))
1528101003Srwatson		return (error);
1529101003Srwatson#endif
1530122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
153192923Srwatson		return (error);
1532122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1533122869Srwatson		return (error);
153465237Srwatson
153565237Srwatson	/*
153682424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
153782424Srwatson	 * bit on the target process.  If the bit is set, then additional
153882424Srwatson	 * restrictions are placed on the set of available signals.
153975437Srwatson	 */
1540141815Ssobomax	if (conservative_signals && (proc->p_flag & P_SUGID)) {
154175437Srwatson		switch (signum) {
154275437Srwatson		case 0:
154375437Srwatson		case SIGKILL:
154475437Srwatson		case SIGINT:
154575437Srwatson		case SIGTERM:
1546120052Srwatson		case SIGALRM:
154775437Srwatson		case SIGSTOP:
154875437Srwatson		case SIGTTIN:
154975437Srwatson		case SIGTTOU:
155075437Srwatson		case SIGTSTP:
155175437Srwatson		case SIGHUP:
155275437Srwatson		case SIGUSR1:
155375437Srwatson		case SIGUSR2:
155482466Srwatson			/*
155582466Srwatson			 * Generally, permit job and terminal control
155682466Srwatson			 * signals.
155782466Srwatson			 */
155875437Srwatson			break;
155975437Srwatson		default:
156088943Srwatson			/* Not permitted without privilege. */
1561132653Scperciva			error = suser_cred(cred, SUSER_ALLOWJAIL);
156275437Srwatson			if (error)
156375437Srwatson				return (error);
156475437Srwatson		}
156565237Srwatson	}
156665237Srwatson
156775480Srwatson	/*
156882424Srwatson	 * Generally, the target credential's ruid or svuid must match the
156975480Srwatson	 * subject credential's ruid or euid.
157075480Srwatson	 */
157188943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
157288943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
157388943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
157488943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
157588943Srwatson		/* Not permitted without privilege. */
1576132653Scperciva		error = suser_cred(cred, SUSER_ALLOWJAIL);
157775480Srwatson		if (error)
157875480Srwatson			return (error);
157975480Srwatson	}
158075480Srwatson
158187218Srwatson	return (0);
158253518Sphk}
158353518Sphk
158488943Srwatson
158582466Srwatson/*-
158696886Sjhb * Determine whether td may deliver the specified signal to p.
158788943Srwatson * Returns: 0 for permitted, an errno value otherwise
158896886Sjhb * Locks: Sufficient locks to protect various components of td and p
158996886Sjhb *        must be held.  td must be curthread, and a lock must be
159096886Sjhb *        held for p.
159196886Sjhb * References: td and p must be valid for the lifetime of the call
159288943Srwatson */
159388943Srwatsonint
1594141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum)
159588943Srwatson{
159688943Srwatson
159796886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
159896886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
159996886Sjhb	if (td->td_proc == p)
160088943Srwatson		return (0);
160188943Srwatson
160288943Srwatson	/*
160388943Srwatson	 * UNIX signalling semantics require that processes in the same
160488943Srwatson	 * session always be able to deliver SIGCONT to one another,
160588943Srwatson	 * overriding the remaining protections.
160688943Srwatson	 */
160796886Sjhb	/* XXX: This will require an additional lock of some sort. */
160896886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
160988943Srwatson		return (0);
1610143108Ssobomax	/*
1611143800Ssobomax	 * Some compat layers use SIGTHR and higher signals for
1612143800Ssobomax	 * communication between different kernel threads of the same
1613143800Ssobomax	 * process, so that they expect that it's always possible to
1614143800Ssobomax	 * deliver them, even for suid applications where cr_cansignal() can
1615143108Ssobomax	 * deny such ability for security consideration.  It should be
1616143108Ssobomax	 * pretty safe to do since the only way to create two processes
1617143108Ssobomax	 * with the same p_leader is via rfork(2).
1618143108Ssobomax	 */
1619143805Ssobomax	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
1620143805Ssobomax	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
1621143108Ssobomax		return (0);
162288943Srwatson
1623141815Ssobomax	return (cr_cansignal(td->td_ucred, p, signum));
162488943Srwatson}
162588943Srwatson
162688943Srwatson/*-
162796886Sjhb * Determine whether td may reschedule p.
162882466Srwatson * Returns: 0 for permitted, an errno value otherwise
162996886Sjhb * Locks: Sufficient locks to protect various components of td and p
163096886Sjhb *        must be held.  td must be curthread, and a lock must
163196886Sjhb *        be held for p.
163296886Sjhb * References: td and p must be valid for the lifetime of the call
163382424Srwatson */
163479335Srwatsonint
163596886Sjhbp_cansched(struct thread *td, struct proc *p)
163665237Srwatson{
163772786Srwatson	int error;
163865237Srwatson
163996886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
164096886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
164196886Sjhb	if (td->td_proc == p)
164265237Srwatson		return (0);
164396886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
164472786Srwatson		return (error);
1645101003Srwatson#ifdef MAC
1646101003Srwatson	if ((error = mac_check_proc_sched(td->td_ucred, p)))
1647101003Srwatson		return (error);
1648101003Srwatson#endif
164996886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
165092923Srwatson		return (error);
1651122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1652122869Srwatson		return (error);
165396886Sjhb	if (td->td_ucred->cr_ruid == p->p_ucred->cr_ruid)
165465237Srwatson		return (0);
165596886Sjhb	if (td->td_ucred->cr_uid == p->p_ucred->cr_ruid)
165665237Srwatson		return (0);
1657132653Scperciva	if (suser_cred(td->td_ucred, SUSER_ALLOWJAIL) == 0)
165865237Srwatson		return (0);
165965237Srwatson
166065237Srwatson#ifdef CAPABILITIES
1661132653Scperciva	if (!cap_check(NULL, td, CAP_SYS_NICE, SUSER_ALLOWJAIL))
166265237Srwatson		return (0);
166365237Srwatson#endif
166465237Srwatson
166565237Srwatson	return (EPERM);
166665237Srwatson}
166765237Srwatson
166882424Srwatson/*
166987280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
167087280Srwatson * unprivileged inter-process debugging services, including some procfs
167187280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
167287280Srwatson * debugging has been involved in a variety of security problems, and sites
167387280Srwatson * not requiring the service might choose to disable it when hardening
167487280Srwatson * systems.
167582424Srwatson *
167682424Srwatson * XXX: Should modifying and reading this variable require locking?
167787218Srwatson * XXX: data declarations should be together near the beginning of the file.
167882424Srwatson */
167987144Srwatsonstatic int	unprivileged_proc_debug = 1;
168089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
168187218Srwatson    &unprivileged_proc_debug, 0,
168280735Srwatson    "Unprivileged processes may use process debugging facilities");
168380735Srwatson
168482466Srwatson/*-
168596886Sjhb * Determine whether td may debug p.
168682466Srwatson * Returns: 0 for permitted, an errno value otherwise
168796886Sjhb * Locks: Sufficient locks to protect various components of td and p
168896886Sjhb *        must be held.  td must be curthread, and a lock must
168996886Sjhb *        be held for p.
169096886Sjhb * References: td and p must be valid for the lifetime of the call
169182424Srwatson */
169279335Srwatsonint
169396886Sjhbp_candebug(struct thread *td, struct proc *p)
169465237Srwatson{
169587218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
169665237Srwatson
169796886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
169896886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
169987144Srwatson	if (!unprivileged_proc_debug) {
1700132653Scperciva		error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
170184727Srwatson		if (error)
170284727Srwatson			return (error);
170384727Srwatson	}
170496886Sjhb	if (td->td_proc == p)
170584636Sdes		return (0);
170696886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
170772786Srwatson		return (error);
1708101003Srwatson#ifdef MAC
1709101003Srwatson	if ((error = mac_check_proc_debug(td->td_ucred, p)))
1710101003Srwatson		return (error);
1711101003Srwatson#endif
171296886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
171392923Srwatson		return (error);
1714122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1715122869Srwatson		return (error);
171665237Srwatson
171782466Srwatson	/*
171896886Sjhb	 * Is p's group set a subset of td's effective group set?  This
171996886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
172082466Srwatson	 */
172185895Srwatson	grpsubset = 1;
172296886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
172396886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
172485895Srwatson			grpsubset = 0;
172585895Srwatson			break;
172685895Srwatson		}
172785895Srwatson	}
172885895Srwatson	grpsubset = grpsubset &&
172996886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
173096886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
173185895Srwatson
173285895Srwatson	/*
173396886Sjhb	 * Are the uids present in p's credential equal to td's
173496886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
173585895Srwatson	 */
173696886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
173796886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
173896886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
173985895Srwatson
174085895Srwatson	/*
174185895Srwatson	 * Has the credential of the process changed since the last exec()?
174285895Srwatson	 */
174396886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
174485895Srwatson
174585895Srwatson	/*
174696886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
174785895Srwatson	 * or the credential has changed, require appropriate privilege
174896886Sjhb	 * for td to debug p.  For POSIX.1e capabilities, this will
174985895Srwatson	 * require CAP_SYS_PTRACE.
175085895Srwatson	 */
175185895Srwatson	if (!grpsubset || !uidsubset || credentialchanged) {
1752132653Scperciva		error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
175384727Srwatson		if (error)
175465237Srwatson			return (error);
175582466Srwatson	}
175665237Srwatson
175787218Srwatson	/* Can't trace init when securelevel > 0. */
175896886Sjhb	if (p == initproc) {
175996886Sjhb		error = securelevel_gt(td->td_ucred, 0);
176083639Srwatson		if (error)
176183639Srwatson			return (error);
176283639Srwatson	}
176365237Srwatson
176485880Srwatson	/*
176585880Srwatson	 * Can't trace a process that's currently exec'ing.
176685880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
176785880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
176885880Srwatson	 * should be moved to the caller's of p_candebug().
176985880Srwatson	 */
177096886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
177185598Sdes		return (EAGAIN);
177287466Srwatson
177365237Srwatson	return (0);
177465237Srwatson}
177565237Srwatson
177692976Srwatson/*-
177792976Srwatson * Determine whether the subject represented by cred can "see" a socket.
177892976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
177992976Srwatson */
178092976Srwatsonint
178192976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
178292976Srwatson{
178392976Srwatson	int error;
178492976Srwatson
178592976Srwatson	error = prison_check(cred, so->so_cred);
178692976Srwatson	if (error)
178792976Srwatson		return (ENOENT);
1788101003Srwatson#ifdef MAC
1789130398Srwatson	SOCK_LOCK(so);
1790101003Srwatson	error = mac_check_socket_visible(cred, so);
1791130398Srwatson	SOCK_UNLOCK(so);
1792101003Srwatson	if (error)
1793101003Srwatson		return (error);
1794101003Srwatson#endif
179592976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
179692976Srwatson		return (ENOENT);
1797122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1798122869Srwatson		return (ENOENT);
179992976Srwatson
180092976Srwatson	return (0);
180192976Srwatson}
180292976Srwatson
180353518Sphk/*
18041541Srgrimes * Allocate a zeroed cred structure.
1805116406Srwatson * MPSAFE
18061541Srgrimes */
18071541Srgrimesstruct ucred *
180893580Sjhbcrget(void)
18091541Srgrimes{
18101541Srgrimes	register struct ucred *cr;
18111541Srgrimes
1812111119Simp	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
18131541Srgrimes	cr->cr_ref = 1;
1814117494Struckman	cr->cr_mtxp = mtx_pool_find(mtxpool_sleep, cr);
1815101001Srwatson#ifdef MAC
1816101001Srwatson	mac_init_cred(cr);
1817101001Srwatson#endif
18181541Srgrimes	return (cr);
18191541Srgrimes}
18201541Srgrimes
18211541Srgrimes/*
182282466Srwatson * Claim another reference to a ucred structure.
1823116406Srwatson * MPSAFE
182469401Salfred */
182584827Sjhbstruct ucred *
182693580Sjhbcrhold(struct ucred *cr)
182769401Salfred{
182869401Salfred
182990756Sdillon	mtx_lock(cr->cr_mtxp);
183069401Salfred	cr->cr_ref++;
183190756Sdillon	mtx_unlock(cr->cr_mtxp);
183284827Sjhb	return (cr);
183369401Salfred}
183469401Salfred
183569401Salfred/*
18361541Srgrimes * Free a cred structure.
18371541Srgrimes * Throws away space when ref count gets to 0.
1838116406Srwatson * MPSAFE
18391541Srgrimes */
18401549Srgrimesvoid
184193580Sjhbcrfree(struct ucred *cr)
18421541Srgrimes{
184390756Sdillon	struct mtx *mtxp = cr->cr_mtxp;
184469239Salfred
184590756Sdillon	mtx_lock(mtxp);
184675632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
184765495Struckman	if (--cr->cr_ref == 0) {
1848124884Srwatson		mtx_unlock(mtxp);
184965495Struckman		/*
185065495Struckman		 * Some callers of crget(), such as nfs_statfs(),
185165495Struckman		 * allocate a temporary credential, but don't
185265495Struckman		 * allocate a uidinfo structure.
185365495Struckman		 */
185465495Struckman		if (cr->cr_uidinfo != NULL)
185565495Struckman			uifree(cr->cr_uidinfo);
185677277Srwatson		if (cr->cr_ruidinfo != NULL)
185777277Srwatson			uifree(cr->cr_ruidinfo);
185872786Srwatson		/*
185972786Srwatson		 * Free a prison, if any.
186072786Srwatson		 */
186172786Srwatson		if (jailed(cr))
186272786Srwatson			prison_free(cr->cr_prison);
1863101001Srwatson#ifdef MAC
1864101001Srwatson		mac_destroy_cred(cr);
1865101001Srwatson#endif
186699009Salfred		FREE(cr, M_CRED);
186790756Sdillon	} else {
186890756Sdillon		mtx_unlock(mtxp);
186990756Sdillon	}
18701541Srgrimes}
18711541Srgrimes
18721541Srgrimes/*
187384827Sjhb * Check to see if this ucred is shared.
1874116406Srwatson * MPSAFE
18751541Srgrimes */
187684827Sjhbint
187793580Sjhbcrshared(struct ucred *cr)
18781541Srgrimes{
187984827Sjhb	int shared;
18801541Srgrimes
188190756Sdillon	mtx_lock(cr->cr_mtxp);
188284827Sjhb	shared = (cr->cr_ref > 1);
188390756Sdillon	mtx_unlock(cr->cr_mtxp);
188484827Sjhb	return (shared);
18851541Srgrimes}
18861541Srgrimes
18871541Srgrimes/*
188884827Sjhb * Copy a ucred's contents from a template.  Does not block.
1889116406Srwatson * MPSAFE
189084827Sjhb */
189184827Sjhbvoid
189293580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
189384827Sjhb{
189484827Sjhb
189584827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
189684827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
189787218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
189884827Sjhb		(caddr_t)&src->cr_startcopy));
189984827Sjhb	uihold(dest->cr_uidinfo);
190084827Sjhb	uihold(dest->cr_ruidinfo);
190184827Sjhb	if (jailed(dest))
190284827Sjhb		prison_hold(dest->cr_prison);
1903101001Srwatson#ifdef MAC
1904123173Srwatson	mac_copy_cred(src, dest);
1905101001Srwatson#endif
190684827Sjhb}
190784827Sjhb
190884827Sjhb/*
19091541Srgrimes * Dup cred struct to a new held one.
1910116406Srwatson * MPSAFE
19111541Srgrimes */
19121541Srgrimesstruct ucred *
191393580Sjhbcrdup(struct ucred *cr)
19141541Srgrimes{
19151541Srgrimes	struct ucred *newcr;
19161541Srgrimes
191784827Sjhb	newcr = crget();
191884827Sjhb	crcopy(newcr, cr);
19191541Srgrimes	return (newcr);
19201541Srgrimes}
19211541Srgrimes
19221541Srgrimes/*
192391354Sdd * Fill in a struct xucred based on a struct ucred.
1924116406Srwatson * MPSAFE
192591354Sdd */
192691354Sddvoid
192793580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
192891354Sdd{
192991354Sdd
193091354Sdd	bzero(xcr, sizeof(*xcr));
193191354Sdd	xcr->cr_version = XUCRED_VERSION;
193291354Sdd	xcr->cr_uid = cr->cr_uid;
193391354Sdd	xcr->cr_ngroups = cr->cr_ngroups;
193491354Sdd	bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
193591354Sdd}
193691354Sdd
193791354Sdd/*
193890748Sjulian * small routine to swap a thread's current ucred for the correct one
193990748Sjulian * taken from the process.
1940116406Srwatson * MPSAFE
194190748Sjulian */
194290748Sjulianvoid
194390748Sjuliancred_update_thread(struct thread *td)
194490748Sjulian{
194590748Sjulian	struct proc *p;
194691405Sjhb	struct ucred *cred;
194790748Sjulian
194890748Sjulian	p = td->td_proc;
194991405Sjhb	cred = td->td_ucred;
195090748Sjulian	PROC_LOCK(p);
195190748Sjulian	td->td_ucred = crhold(p->p_ucred);
195290748Sjulian	PROC_UNLOCK(p);
195391405Sjhb	if (cred != NULL)
195491405Sjhb		crfree(cred);
195590748Sjulian}
195690748Sjulian
195790748Sjulian/*
19581541Srgrimes * Get login name, if available.
19591541Srgrimes */
196012221Sbde#ifndef _SYS_SYSPROTO_H_
19611541Srgrimesstruct getlogin_args {
19621541Srgrimes	char	*namebuf;
19631541Srgrimes	u_int	namelen;
19641541Srgrimes};
196512221Sbde#endif
196682749Sdillon/*
196782749Sdillon * MPSAFE
196882749Sdillon */
19691541Srgrimes/* ARGSUSED */
19701549Srgrimesint
197193580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap)
19721541Srgrimes{
197382749Sdillon	int error;
197491140Stanimura	char login[MAXLOGNAME];
197583366Sjulian	struct proc *p = td->td_proc;
19761541Srgrimes
197723358Sache	if (uap->namelen > MAXLOGNAME)
197823359Sache		uap->namelen = MAXLOGNAME;
197991140Stanimura	PROC_LOCK(p);
198091140Stanimura	SESS_LOCK(p->p_session);
198191140Stanimura	bcopy(p->p_session->s_login, login, uap->namelen);
198291140Stanimura	SESS_UNLOCK(p->p_session);
198391140Stanimura	PROC_UNLOCK(p);
198499009Salfred	error = copyout(login, uap->namebuf, uap->namelen);
198582749Sdillon	return(error);
19861541Srgrimes}
19871541Srgrimes
19881541Srgrimes/*
19891541Srgrimes * Set login name.
19901541Srgrimes */
199112221Sbde#ifndef _SYS_SYSPROTO_H_
19921541Srgrimesstruct setlogin_args {
19931541Srgrimes	char	*namebuf;
19941541Srgrimes};
199512221Sbde#endif
199682749Sdillon/*
199782749Sdillon * MPSAFE
199882749Sdillon */
19991541Srgrimes/* ARGSUSED */
20001549Srgrimesint
200193580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap)
20021541Srgrimes{
200383366Sjulian	struct proc *p = td->td_proc;
20041541Srgrimes	int error;
200523330Sache	char logintmp[MAXLOGNAME];
20061541Srgrimes
2007132653Scperciva	error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL);
200894619Sjhb	if (error)
200994619Sjhb		return (error);
201099009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
201187218Srwatson	if (error == ENAMETOOLONG)
20121541Srgrimes		error = EINVAL;
201391140Stanimura	else if (!error) {
201491140Stanimura		PROC_LOCK(p);
201591140Stanimura		SESS_LOCK(p->p_session);
201691140Stanimura		(void) memcpy(p->p_session->s_login, logintmp,
201723330Sache		    sizeof(logintmp));
201891140Stanimura		SESS_UNLOCK(p->p_session);
201991140Stanimura		PROC_UNLOCK(p);
202091140Stanimura	}
20211541Srgrimes	return (error);
20221541Srgrimes}
202331891Ssef
202431891Ssefvoid
202593580Sjhbsetsugid(struct proc *p)
202631891Ssef{
202798403Salfred
202898403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
202931891Ssef	p->p_flag |= P_SUGID;
203055707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
203131891Ssef		p->p_stops = 0;
203231891Ssef}
203365495Struckman
203482466Srwatson/*-
203582466Srwatson * Change a process's effective uid.
203677183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
203777183Srwatson * References: newcred must be an exclusive credential reference for the
203877183Srwatson *             duration of the call.
203965495Struckman */
204065495Struckmanvoid
204198417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
204265495Struckman{
204365495Struckman
204498417Salfred	newcred->cr_uid = euip->ui_uid;
204598417Salfred	uihold(euip);
204677183Srwatson	uifree(newcred->cr_uidinfo);
204798417Salfred	newcred->cr_uidinfo = euip;
204865495Struckman}
204965495Struckman
205082466Srwatson/*-
205182466Srwatson * Change a process's effective gid.
205277183Srwatson * Side effects: newcred->cr_gid will be modified.
205377183Srwatson * References: newcred must be an exclusive credential reference for the
205477183Srwatson *             duration of the call.
205565495Struckman */
205667629Sgallatinvoid
205793580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
205865495Struckman{
205965495Struckman
206077183Srwatson	newcred->cr_groups[0] = egid;
206165495Struckman}
206277183Srwatson
206382466Srwatson/*-
206482466Srwatson * Change a process's real uid.
206577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
206677183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
206777183Srwatson *               counts will be updated.
206877183Srwatson * References: newcred must be an exclusive credential reference for the
206977183Srwatson *             duration of the call.
207077183Srwatson */
207177183Srwatsonvoid
207298417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
207377183Srwatson{
207477183Srwatson
207577183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
207698417Salfred	newcred->cr_ruid = ruip->ui_uid;
207798417Salfred	uihold(ruip);
207877183Srwatson	uifree(newcred->cr_ruidinfo);
207998417Salfred	newcred->cr_ruidinfo = ruip;
208077183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
208177183Srwatson}
208277183Srwatson
208382466Srwatson/*-
208482466Srwatson * Change a process's real gid.
208577183Srwatson * Side effects: newcred->cr_rgid will be updated.
208677183Srwatson * References: newcred must be an exclusive credential reference for the
208777183Srwatson *             duration of the call.
208877183Srwatson */
208977183Srwatsonvoid
209093580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
209177183Srwatson{
209277183Srwatson
209377183Srwatson	newcred->cr_rgid = rgid;
209477183Srwatson}
209577183Srwatson
209682466Srwatson/*-
209782466Srwatson * Change a process's saved uid.
209877183Srwatson * Side effects: newcred->cr_svuid will be updated.
209977183Srwatson * References: newcred must be an exclusive credential reference for the
210077183Srwatson *             duration of the call.
210177183Srwatson */
210277183Srwatsonvoid
210393580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
210477183Srwatson{
210577183Srwatson
210677183Srwatson	newcred->cr_svuid = svuid;
210777183Srwatson}
210877183Srwatson
210982466Srwatson/*-
211082466Srwatson * Change a process's saved gid.
211177183Srwatson * Side effects: newcred->cr_svgid will be updated.
211277183Srwatson * References: newcred must be an exclusive credential reference for the
211377183Srwatson *             duration of the call.
211477183Srwatson */
211577183Srwatsonvoid
211693580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
211777183Srwatson{
211877183Srwatson
211977183Srwatson	newcred->cr_svgid = svgid;
212077183Srwatson}
2121