xref: /freebsd/sys/kern/kern_prot.c (revision 704993284389fbfa09876d163b54efffbf5d312e)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
5df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
6df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
7df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
9eb725b4eSRobert Watson  * Copyright (c) 2000-2001 Robert N. M. Watson.  All rights reserved.
10df8bae1dSRodney W. Grimes  *
11df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
12df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
13df8bae1dSRodney W. Grimes  * are met:
14df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
16df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
18df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
20df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
21df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
22df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
23df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
40c3aac50fSPeter Wemm  * $FreeBSD$
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes /*
44df8bae1dSRodney W. Grimes  * System calls related to processes and protection
45df8bae1dSRodney W. Grimes  */
46df8bae1dSRodney W. Grimes 
475591b823SEivind Eklund #include "opt_compat.h"
485591b823SEivind Eklund 
49df8bae1dSRodney W. Grimes #include <sys/param.h>
50df8bae1dSRodney W. Grimes #include <sys/systm.h>
51fb919e4dSMark Murray #include <sys/acct.h>
521c5bb3eaSPeter Wemm #include <sys/kernel.h>
5398f03f90SJake Burkholder #include <sys/lock.h>
54f591779bSSeigo Tanimura #include <sys/malloc.h>
55fb919e4dSMark Murray #include <sys/mutex.h>
565b29d6e9SJohn Baldwin #include <sys/sx.h>
57f591779bSSeigo Tanimura #include <sys/proc.h>
58fb919e4dSMark Murray #include <sys/sysproto.h>
59eb725b4eSRobert Watson #include <sys/jail.h>
60d5f81602SSean Eric Fagan #include <sys/pioctl.h>
61f535380cSDon Lewis #include <sys/resourcevar.h>
6229dc1288SRobert Watson #include <sys/socket.h>
6329dc1288SRobert Watson #include <sys/socketvar.h>
64579f4eb4SRobert Watson #include <sys/sysctl.h>
65df8bae1dSRodney W. Grimes 
66a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
67a1c995b6SPoul-Henning Kamp 
68d0615c64SAndrew R. Reiter SYSCTL_DECL(_security);
69d0615c64SAndrew R. Reiter SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0,
7048713bdcSRobert Watson     "BSD security policy");
7148713bdcSRobert Watson 
72d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
73ad7507e2SSteven Wallace struct getpid_args {
74df8bae1dSRodney W. Grimes 	int	dummy;
75df8bae1dSRodney W. Grimes };
76d2d3e875SBruce Evans #endif
77835a82eeSMatthew Dillon /*
78835a82eeSMatthew Dillon  * MPSAFE
79835a82eeSMatthew Dillon  */
80df8bae1dSRodney W. Grimes /* ARGSUSED */
8126f9a767SRodney W. Grimes int
824c44ad8eSJohn Baldwin getpid(struct thread *td, struct getpid_args *uap)
83df8bae1dSRodney W. Grimes {
84b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
85d23f5958SMatthew Dillon 	int s;
86df8bae1dSRodney W. Grimes 
87d23f5958SMatthew Dillon 	s = mtx_lock_giant(kern_giant_proc);
88b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pid;
89df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
90bae3a80bSJohn Baldwin 	PROC_LOCK(p);
91b40ce416SJulian Elischer 	td->td_retval[1] = p->p_pptr->p_pid;
92bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
93df8bae1dSRodney W. Grimes #endif
94d23f5958SMatthew Dillon 	mtx_unlock_giant(s);
95df8bae1dSRodney W. Grimes 	return (0);
96df8bae1dSRodney W. Grimes }
97df8bae1dSRodney W. Grimes 
98d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
99ad7507e2SSteven Wallace struct getppid_args {
100ad7507e2SSteven Wallace         int     dummy;
101ad7507e2SSteven Wallace };
102d2d3e875SBruce Evans #endif
103835a82eeSMatthew Dillon /*
104835a82eeSMatthew Dillon  * MPSAFE
105835a82eeSMatthew Dillon  */
106df8bae1dSRodney W. Grimes /* ARGSUSED */
10726f9a767SRodney W. Grimes int
1084c44ad8eSJohn Baldwin getppid(struct thread *td, struct getppid_args *uap)
109df8bae1dSRodney W. Grimes {
110b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
111d23f5958SMatthew Dillon 	int s;
112df8bae1dSRodney W. Grimes 
113d23f5958SMatthew Dillon 	s = mtx_lock_giant(kern_giant_proc);
114bae3a80bSJohn Baldwin 	PROC_LOCK(p);
115b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pptr->p_pid;
116bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
117d23f5958SMatthew Dillon 	mtx_unlock_giant(s);
118df8bae1dSRodney W. Grimes 	return (0);
119df8bae1dSRodney W. Grimes }
120df8bae1dSRodney W. Grimes 
12136e9f877SMatthew Dillon /*
122eb725b4eSRobert Watson  * Get process group ID; note that POSIX getpgrp takes no parameter.
12336e9f877SMatthew Dillon  */
124d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
125ad7507e2SSteven Wallace struct getpgrp_args {
126ad7507e2SSteven Wallace         int     dummy;
127ad7507e2SSteven Wallace };
128d2d3e875SBruce Evans #endif
129835a82eeSMatthew Dillon /*
130835a82eeSMatthew Dillon  * MPSAFE
131835a82eeSMatthew Dillon  */
13226f9a767SRodney W. Grimes int
1334c44ad8eSJohn Baldwin getpgrp(struct thread *td, struct getpgrp_args *uap)
134df8bae1dSRodney W. Grimes {
135b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
136f591779bSSeigo Tanimura 	int s;
137df8bae1dSRodney W. Grimes 
138f591779bSSeigo Tanimura 	s = mtx_lock_giant(kern_giant_proc);
139f591779bSSeigo Tanimura 	PROC_LOCK(p);
140b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
141f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
142f591779bSSeigo Tanimura 	mtx_unlock_giant(s);
143df8bae1dSRodney W. Grimes 	return (0);
144df8bae1dSRodney W. Grimes }
145df8bae1dSRodney W. Grimes 
1461a5018a0SPeter Wemm /* Get an arbitary pid's process group id */
1471a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1481a5018a0SPeter Wemm struct getpgid_args {
1491a5018a0SPeter Wemm 	pid_t	pid;
1501a5018a0SPeter Wemm };
1511a5018a0SPeter Wemm #endif
152835a82eeSMatthew Dillon /*
153835a82eeSMatthew Dillon  * MPSAFE
154835a82eeSMatthew Dillon  */
1551a5018a0SPeter Wemm int
1564c44ad8eSJohn Baldwin getpgid(struct thread *td, struct getpgid_args *uap)
1571a5018a0SPeter Wemm {
158b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
15965de0c7aSDon Lewis 	struct proc *pt;
160f2ae7368SJohn Baldwin 	int error;
16165de0c7aSDon Lewis 
162f2ae7368SJohn Baldwin 	mtx_lock(&Giant);
163eb725b4eSRobert Watson 	error = 0;
164f591779bSSeigo Tanimura 	if (uap->pid == 0) {
165f591779bSSeigo Tanimura 		PROC_LOCK(p);
166b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pgrp->pg_id;
167f591779bSSeigo Tanimura 		PROC_UNLOCK(p);
168f591779bSSeigo Tanimura 	} else if ((pt = pfind(uap->pid)) == NULL)
169835a82eeSMatthew Dillon 		error = ESRCH;
1706a90c862SJohn Baldwin 	else {
1716a90c862SJohn Baldwin 		error = p_cansee(p, pt);
1726a90c862SJohn Baldwin 		if (error == 0)
173b40ce416SJulian Elischer 			td->td_retval[0] = pt->p_pgrp->pg_id;
17433a9ed9dSJohn Baldwin 		PROC_UNLOCK(pt);
17533a9ed9dSJohn Baldwin 	}
176f2ae7368SJohn Baldwin 	mtx_unlock(&Giant);
177835a82eeSMatthew Dillon 	return (error);
1781a5018a0SPeter Wemm }
1791a5018a0SPeter Wemm 
1801a5018a0SPeter Wemm /*
1811a5018a0SPeter Wemm  * Get an arbitary pid's session id.
1821a5018a0SPeter Wemm  */
1831a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1841a5018a0SPeter Wemm struct getsid_args {
1851a5018a0SPeter Wemm 	pid_t	pid;
1861a5018a0SPeter Wemm };
1871a5018a0SPeter Wemm #endif
188835a82eeSMatthew Dillon /*
189835a82eeSMatthew Dillon  * MPSAFE
190835a82eeSMatthew Dillon  */
1911a5018a0SPeter Wemm int
1924c44ad8eSJohn Baldwin getsid(struct thread *td, struct getsid_args *uap)
1931a5018a0SPeter Wemm {
194b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
19565de0c7aSDon Lewis 	struct proc *pt;
196eb725b4eSRobert Watson 	int error;
19765de0c7aSDon Lewis 
198f2ae7368SJohn Baldwin 	mtx_lock(&Giant);
199eb725b4eSRobert Watson 	error = 0;
200f591779bSSeigo Tanimura 	if (uap->pid == 0) {
201f591779bSSeigo Tanimura 		PROC_LOCK(p);
202b40ce416SJulian Elischer 		td->td_retval[0] = p->p_session->s_sid;
203f591779bSSeigo Tanimura 		PROC_UNLOCK(p);
204f591779bSSeigo Tanimura 	} else if ((pt = pfind(uap->pid)) == NULL)
205835a82eeSMatthew Dillon 		error = ESRCH;
2066a90c862SJohn Baldwin 	else {
2076a90c862SJohn Baldwin 		error = p_cansee(p, pt);
2086a90c862SJohn Baldwin 		if (error == 0)
209b40ce416SJulian Elischer 			td->td_retval[0] = pt->p_session->s_sid;
21033a9ed9dSJohn Baldwin 		PROC_UNLOCK(pt);
21133a9ed9dSJohn Baldwin 	}
212f2ae7368SJohn Baldwin 	mtx_unlock(&Giant);
213835a82eeSMatthew Dillon 	return (error);
2141a5018a0SPeter Wemm }
2151a5018a0SPeter Wemm 
216d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
217ad7507e2SSteven Wallace struct getuid_args {
218ad7507e2SSteven Wallace         int     dummy;
219ad7507e2SSteven Wallace };
220d2d3e875SBruce Evans #endif
221835a82eeSMatthew Dillon /*
222835a82eeSMatthew Dillon  * MPSAFE
223835a82eeSMatthew Dillon  */
224df8bae1dSRodney W. Grimes /* ARGSUSED */
22526f9a767SRodney W. Grimes int
2264c44ad8eSJohn Baldwin getuid(struct thread *td, struct getuid_args *uap)
227df8bae1dSRodney W. Grimes {
228df8bae1dSRodney W. Grimes 
229d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_ruid;
230df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
231d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_uid;
232df8bae1dSRodney W. Grimes #endif
233df8bae1dSRodney W. Grimes 	return (0);
234df8bae1dSRodney W. Grimes }
235df8bae1dSRodney W. Grimes 
236d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
237ad7507e2SSteven Wallace struct geteuid_args {
238ad7507e2SSteven Wallace         int     dummy;
239ad7507e2SSteven Wallace };
240d2d3e875SBruce Evans #endif
241eb725b4eSRobert Watson /*
242eb725b4eSRobert Watson  * MPSAFE
243eb725b4eSRobert Watson  */
244df8bae1dSRodney W. Grimes /* ARGSUSED */
24526f9a767SRodney W. Grimes int
2464c44ad8eSJohn Baldwin geteuid(struct thread *td, struct geteuid_args *uap)
247df8bae1dSRodney W. Grimes {
248d846883bSJohn Baldwin 
249d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_uid;
250df8bae1dSRodney W. Grimes 	return (0);
251df8bae1dSRodney W. Grimes }
252df8bae1dSRodney W. Grimes 
253d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
254ad7507e2SSteven Wallace struct getgid_args {
255ad7507e2SSteven Wallace         int     dummy;
256ad7507e2SSteven Wallace };
257d2d3e875SBruce Evans #endif
258835a82eeSMatthew Dillon /*
259835a82eeSMatthew Dillon  * MPSAFE
260835a82eeSMatthew Dillon  */
261df8bae1dSRodney W. Grimes /* ARGSUSED */
26226f9a767SRodney W. Grimes int
2634c44ad8eSJohn Baldwin getgid(struct thread *td, struct getgid_args *uap)
264df8bae1dSRodney W. Grimes {
265df8bae1dSRodney W. Grimes 
266d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_rgid;
267df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
268d846883bSJohn Baldwin 	td->td_retval[1] = td->td_ucred->cr_groups[0];
269df8bae1dSRodney W. Grimes #endif
270df8bae1dSRodney W. Grimes 	return (0);
271df8bae1dSRodney W. Grimes }
272df8bae1dSRodney W. Grimes 
273df8bae1dSRodney W. Grimes /*
274df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
275df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
276df8bae1dSRodney W. Grimes  * correctly in a library function.
277df8bae1dSRodney W. Grimes  */
278d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
279ad7507e2SSteven Wallace struct getegid_args {
280ad7507e2SSteven Wallace         int     dummy;
281ad7507e2SSteven Wallace };
282d2d3e875SBruce Evans #endif
283835a82eeSMatthew Dillon /*
284835a82eeSMatthew Dillon  * MPSAFE
285835a82eeSMatthew Dillon  */
286df8bae1dSRodney W. Grimes /* ARGSUSED */
28726f9a767SRodney W. Grimes int
2884c44ad8eSJohn Baldwin getegid(struct thread *td, struct getegid_args *uap)
289df8bae1dSRodney W. Grimes {
290df8bae1dSRodney W. Grimes 
291d846883bSJohn Baldwin 	td->td_retval[0] = td->td_ucred->cr_groups[0];
292df8bae1dSRodney W. Grimes 	return (0);
293df8bae1dSRodney W. Grimes }
294df8bae1dSRodney W. Grimes 
295d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
296df8bae1dSRodney W. Grimes struct getgroups_args {
297df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
298df8bae1dSRodney W. Grimes 	gid_t	*gidset;
299df8bae1dSRodney W. Grimes };
300d2d3e875SBruce Evans #endif
301835a82eeSMatthew Dillon /*
302835a82eeSMatthew Dillon  * MPSAFE
303835a82eeSMatthew Dillon  */
30426f9a767SRodney W. Grimes int
3054c44ad8eSJohn Baldwin getgroups(struct thread *td, register struct getgroups_args *uap)
306df8bae1dSRodney W. Grimes {
307835a82eeSMatthew Dillon 	struct ucred *cred;
308b1fc0ec1SRobert Watson 	u_int ngrp;
309eb725b4eSRobert Watson 	int error;
310df8bae1dSRodney W. Grimes 
311d846883bSJohn Baldwin 	cred = td->td_ucred;
312df8bae1dSRodney W. Grimes 	if ((ngrp = uap->gidsetsize) == 0) {
313b40ce416SJulian Elischer 		td->td_retval[0] = cred->cr_ngroups;
314d846883bSJohn Baldwin 		return (0);
315df8bae1dSRodney W. Grimes 	}
316d846883bSJohn Baldwin 	if (ngrp < cred->cr_ngroups)
317d846883bSJohn Baldwin 		return (EINVAL);
318b1fc0ec1SRobert Watson 	ngrp = cred->cr_ngroups;
319d846883bSJohn Baldwin 	error = copyout((caddr_t)cred->cr_groups, (caddr_t)uap->gidset,
320d846883bSJohn Baldwin 	    ngrp * sizeof(gid_t));
321d74ac681SMatthew Dillon 	if (error == 0)
322d846883bSJohn Baldwin 		td->td_retval[0] = ngrp;
323d74ac681SMatthew Dillon 	return (error);
324df8bae1dSRodney W. Grimes }
325df8bae1dSRodney W. Grimes 
326d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
32782970b81SBruce Evans struct setsid_args {
328ad7507e2SSteven Wallace         int     dummy;
329ad7507e2SSteven Wallace };
330d2d3e875SBruce Evans #endif
331835a82eeSMatthew Dillon /*
332835a82eeSMatthew Dillon  * MPSAFE
333835a82eeSMatthew Dillon  */
334df8bae1dSRodney W. Grimes /* ARGSUSED */
33526f9a767SRodney W. Grimes int
3364c44ad8eSJohn Baldwin setsid(register struct thread *td, struct setsid_args *uap)
337df8bae1dSRodney W. Grimes {
338f591779bSSeigo Tanimura 	struct pgrp *pgrp;
339835a82eeSMatthew Dillon 	int error;
340b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
341f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
342f591779bSSeigo Tanimura 	struct session *newsess;
343f591779bSSeigo Tanimura 
344f591779bSSeigo Tanimura 	error = 0;
345f591779bSSeigo Tanimura 	pgrp = NULL;
346df8bae1dSRodney W. Grimes 
347835a82eeSMatthew Dillon 	mtx_lock(&Giant);
348f591779bSSeigo Tanimura 
349f591779bSSeigo Tanimura 	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
350f591779bSSeigo Tanimura 	MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
351f591779bSSeigo Tanimura 
352f591779bSSeigo Tanimura 	PGRPSESS_XLOCK();
353f591779bSSeigo Tanimura 
354f591779bSSeigo Tanimura 	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
355f591779bSSeigo Tanimura 		if (pgrp != NULL)
356f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
357835a82eeSMatthew Dillon 		error = EPERM;
358f591779bSSeigo Tanimura 		goto fail;
359f591779bSSeigo Tanimura 	} else {
360f591779bSSeigo Tanimura 		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
361b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
362835a82eeSMatthew Dillon 		error = 0;
363df8bae1dSRodney W. Grimes 	}
364f591779bSSeigo Tanimura 	PGRPSESS_XUNLOCK();
365835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
366f591779bSSeigo Tanimura 	return (0);
367f591779bSSeigo Tanimura 
368f591779bSSeigo Tanimura fail:
369f591779bSSeigo Tanimura 	PGRPSESS_XUNLOCK();
370f591779bSSeigo Tanimura 
371f591779bSSeigo Tanimura 	FREE(newpgrp, M_PGRP);
372f591779bSSeigo Tanimura 	FREE(newsess, M_SESSION);
373f591779bSSeigo Tanimura 
374f591779bSSeigo Tanimura 	mtx_unlock(&Giant);
375f591779bSSeigo Tanimura 	return (0);
376df8bae1dSRodney W. Grimes }
377df8bae1dSRodney W. Grimes 
378df8bae1dSRodney W. Grimes /*
379df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
380df8bae1dSRodney W. Grimes  *
381df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
382df8bae1dSRodney W. Grimes  *
383df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
384df8bae1dSRodney W. Grimes  * if a child
385df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
386df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
387df8bae1dSRodney W. Grimes  * if pgid != pid
388df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
389df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
390df8bae1dSRodney W. Grimes  */
391d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
392df8bae1dSRodney W. Grimes struct setpgid_args {
393df8bae1dSRodney W. Grimes 	int	pid;		/* target process id */
394df8bae1dSRodney W. Grimes 	int	pgid;		/* target pgrp id */
395df8bae1dSRodney W. Grimes };
396d2d3e875SBruce Evans #endif
397835a82eeSMatthew Dillon /*
398835a82eeSMatthew Dillon  * MPSAFE
399835a82eeSMatthew Dillon  */
400df8bae1dSRodney W. Grimes /* ARGSUSED */
40126f9a767SRodney W. Grimes int
4024c44ad8eSJohn Baldwin setpgid(struct thread *td, register struct setpgid_args *uap)
403df8bae1dSRodney W. Grimes {
404b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
405df8bae1dSRodney W. Grimes 	register struct proc *targp;	/* target process */
406df8bae1dSRodney W. Grimes 	register struct pgrp *pgrp;	/* target pgrp */
407eb9e5c1dSRobert Watson 	int error;
408f591779bSSeigo Tanimura 	struct pgrp *newpgrp;
409df8bae1dSRodney W. Grimes 
41078f64bccSBruce Evans 	if (uap->pgid < 0)
41178f64bccSBruce Evans 		return (EINVAL);
412f591779bSSeigo Tanimura 
413f591779bSSeigo Tanimura 	error = 0;
414f591779bSSeigo Tanimura 
415835a82eeSMatthew Dillon 	mtx_lock(&Giant);
416f591779bSSeigo Tanimura 
417f591779bSSeigo Tanimura 	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
418f591779bSSeigo Tanimura 
419f591779bSSeigo Tanimura 	PGRPSESS_XLOCK();
420f591779bSSeigo Tanimura 
421df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
422f591779bSSeigo Tanimura 		sx_slock(&proctree_lock);
423f591779bSSeigo Tanimura 		if ((targp = pfind(uap->pid)) == NULL) {
42433a9ed9dSJohn Baldwin 			if (targp)
42533a9ed9dSJohn Baldwin 				PROC_UNLOCK(targp);
426f591779bSSeigo Tanimura 			sx_sunlock(&proctree_lock);
427835a82eeSMatthew Dillon 			error = ESRCH;
428f591779bSSeigo Tanimura 			goto fail;
42933a9ed9dSJohn Baldwin 		}
430f591779bSSeigo Tanimura 		if (!inferior(targp)) {
431f591779bSSeigo Tanimura 			PROC_UNLOCK(targp);
432f591779bSSeigo Tanimura 			sx_sunlock(&proctree_lock);
4332f932587SSeigo Tanimura 			error = ESRCH;
434f591779bSSeigo Tanimura 			goto fail;
435f591779bSSeigo Tanimura 		}
436f591779bSSeigo Tanimura 		sx_sunlock(&proctree_lock);
437a0f75161SRobert Watson 		if ((error = p_cansee(curproc, targp))) {
43833a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
439f591779bSSeigo Tanimura 			goto fail;
44033a9ed9dSJohn Baldwin 		}
44133a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
44233a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
44333a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
444835a82eeSMatthew Dillon 			error = EPERM;
445f591779bSSeigo Tanimura 			goto fail;
44633a9ed9dSJohn Baldwin 		}
44733a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
44833a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
449835a82eeSMatthew Dillon 			error = EACCES;
450f591779bSSeigo Tanimura 			goto fail;
45133a9ed9dSJohn Baldwin 		}
45233a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
453f591779bSSeigo Tanimura 	} else
454f591779bSSeigo Tanimura 		targp = curp;
455f591779bSSeigo Tanimura 	if (SESS_LEADER(targp)) {
456835a82eeSMatthew Dillon 		error = EPERM;
457f591779bSSeigo Tanimura 		goto fail;
45833a9ed9dSJohn Baldwin 	}
459eb725b4eSRobert Watson 	if (uap->pgid == 0)
460df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
461f591779bSSeigo Tanimura 	if (uap->pgid == targp->p_pid) {
462f591779bSSeigo Tanimura 		if (targp->p_pgid == uap->pgid)
463f591779bSSeigo Tanimura 			goto done;
464f591779bSSeigo Tanimura 		error = enterpgrp(targp, uap->pgid, newpgrp, NULL);
465f591779bSSeigo Tanimura 		if (error == 0)
466f591779bSSeigo Tanimura 			newpgrp = NULL;
467f591779bSSeigo Tanimura 	} else {
468f591779bSSeigo Tanimura 		if ((pgrp = pgfind(uap->pgid)) == NULL ||
46933a9ed9dSJohn Baldwin 		    pgrp->pg_session != curp->p_session) {
470f591779bSSeigo Tanimura 			if (pgrp != NULL)
471f591779bSSeigo Tanimura 				PGRP_UNLOCK(pgrp);
472835a82eeSMatthew Dillon 			error = EPERM;
473f591779bSSeigo Tanimura 			goto fail;
474835a82eeSMatthew Dillon 		}
475f591779bSSeigo Tanimura 		if (pgrp == targp->p_pgrp) {
476f591779bSSeigo Tanimura 			PGRP_UNLOCK(pgrp);
477f591779bSSeigo Tanimura 			goto done;
47833a9ed9dSJohn Baldwin 		}
479f591779bSSeigo Tanimura 		PGRP_UNLOCK(pgrp);
480f591779bSSeigo Tanimura 		error = enterthispgrp(targp, pgrp);
481f591779bSSeigo Tanimura 	}
482f591779bSSeigo Tanimura done:
483f591779bSSeigo Tanimura 	PGRPSESS_XUNLOCK();
484f591779bSSeigo Tanimura 	if (newpgrp != NULL)
485f591779bSSeigo Tanimura 		FREE(newpgrp, M_PGRP);
486f591779bSSeigo Tanimura 	mtx_unlock(&Giant);
487f591779bSSeigo Tanimura 	return (0);
488f591779bSSeigo Tanimura 
489f591779bSSeigo Tanimura fail:
490f591779bSSeigo Tanimura 	PGRPSESS_XUNLOCK();
491f591779bSSeigo Tanimura 
492f591779bSSeigo Tanimura 	KASSERT(newpgrp != NULL, ("setpgid failed and newpgrp is null."));
4932f932587SSeigo Tanimura 	KASSERT(error != 0, ("setpgid successfully failed?"));
494f591779bSSeigo Tanimura 	FREE(newpgrp, M_PGRP);
495f591779bSSeigo Tanimura 
496835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
497835a82eeSMatthew Dillon 	return (error);
498df8bae1dSRodney W. Grimes }
499df8bae1dSRodney W. Grimes 
500a08f4bf6SPeter Wemm /*
501a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
5022fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
503a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
504a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
505a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
506a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
507a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
508a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
509a08f4bf6SPeter Wemm  */
510a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
511a08f4bf6SPeter Wemm 
512d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
513df8bae1dSRodney W. Grimes struct setuid_args {
514df8bae1dSRodney W. Grimes 	uid_t	uid;
515df8bae1dSRodney W. Grimes };
516d2d3e875SBruce Evans #endif
517835a82eeSMatthew Dillon /*
518835a82eeSMatthew Dillon  * MPSAFE
519835a82eeSMatthew Dillon  */
520df8bae1dSRodney W. Grimes /* ARGSUSED */
52126f9a767SRodney W. Grimes int
5224c44ad8eSJohn Baldwin setuid(struct thread *td, struct setuid_args *uap)
523df8bae1dSRodney W. Grimes {
524b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
525b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
526b1fc0ec1SRobert Watson 	uid_t uid;
527eb725b4eSRobert Watson 	int error;
528df8bae1dSRodney W. Grimes 
529eb725b4eSRobert Watson 	uid = uap->uid;
530835a82eeSMatthew Dillon 	mtx_lock(&Giant);
531eb725b4eSRobert Watson 	error = 0;
532f605567cSRobert Watson 	oldcred = p->p_ucred;
5335a92ee3cSRobert Watson 
534a08f4bf6SPeter Wemm 	/*
535a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
536a08f4bf6SPeter Wemm 	 *
537a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
538a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5392fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
540a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
541a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
542a08f4bf6SPeter Wemm 	 *
543a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
544a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
545a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
546a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
547eb725b4eSRobert Watson 	 * 2: We determine if the real and/or saved uids are going to
548a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
549a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
550a08f4bf6SPeter Wemm 	 */
551b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5523f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
553b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
554a08f4bf6SPeter Wemm #endif
555a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
556b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5573f246666SAndrey A. Chernov #endif
55844731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
559835a82eeSMatthew Dillon 		goto done2;
560a08f4bf6SPeter Wemm 
561b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
562a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
563df8bae1dSRodney W. Grimes 	/*
564a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
565a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
566df8bae1dSRodney W. Grimes 	 */
5673f246666SAndrey A. Chernov 	if (
568a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
569b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5703f246666SAndrey A. Chernov #endif
57144731cabSJohn Baldwin 	    suser_cred(oldcred, PRISON_ROOT) == 0) /* we are using privs */
572a08f4bf6SPeter Wemm #endif
573a08f4bf6SPeter Wemm 	{
574a08f4bf6SPeter Wemm 		/*
575f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
576a08f4bf6SPeter Wemm 		 */
577b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
578b1fc0ec1SRobert Watson 			change_ruid(newcred, uid);
579f535380cSDon Lewis 			setsugid(p);
580d3cdb93dSAndrey A. Chernov 		}
581a08f4bf6SPeter Wemm 		/*
582a08f4bf6SPeter Wemm 		 * Set saved uid
583a08f4bf6SPeter Wemm 		 *
584a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
585a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
586a08f4bf6SPeter Wemm 		 * is important that we should do this.
587a08f4bf6SPeter Wemm 		 */
588b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
589b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
590d5f81602SSean Eric Fagan 			setsugid(p);
591a08f4bf6SPeter Wemm 		}
592a08f4bf6SPeter Wemm 	}
593a08f4bf6SPeter Wemm 
594a08f4bf6SPeter Wemm 	/*
595a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
596a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
597a08f4bf6SPeter Wemm 	 */
598b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
599b1fc0ec1SRobert Watson 		change_euid(newcred, uid);
600d5f81602SSean Eric Fagan 		setsugid(p);
601a08f4bf6SPeter Wemm 	}
602b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
603b1fc0ec1SRobert Watson 	crfree(oldcred);
604835a82eeSMatthew Dillon done2:
605835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
606835a82eeSMatthew Dillon 	return (error);
607df8bae1dSRodney W. Grimes }
608df8bae1dSRodney W. Grimes 
609d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
610df8bae1dSRodney W. Grimes struct seteuid_args {
611df8bae1dSRodney W. Grimes 	uid_t	euid;
612df8bae1dSRodney W. Grimes };
613d2d3e875SBruce Evans #endif
614835a82eeSMatthew Dillon /*
615835a82eeSMatthew Dillon  * MPSAFE
616835a82eeSMatthew Dillon  */
617df8bae1dSRodney W. Grimes /* ARGSUSED */
61826f9a767SRodney W. Grimes int
6194c44ad8eSJohn Baldwin seteuid(struct thread *td, struct seteuid_args *uap)
620df8bae1dSRodney W. Grimes {
621b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
622b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
623b1fc0ec1SRobert Watson 	uid_t euid;
624eb725b4eSRobert Watson 	int error;
625df8bae1dSRodney W. Grimes 
626df8bae1dSRodney W. Grimes 	euid = uap->euid;
627835a82eeSMatthew Dillon 	mtx_lock(&Giant);
628eb725b4eSRobert Watson 	error = 0;
629b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
630b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
631b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
63244731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
633835a82eeSMatthew Dillon 		goto done2;
634df8bae1dSRodney W. Grimes 	/*
635df8bae1dSRodney W. Grimes 	 * Everything's okay, do it.  Copy credentials so other references do
636df8bae1dSRodney W. Grimes 	 * not see our changes.
637df8bae1dSRodney W. Grimes 	 */
638b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
639b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
640b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
641d5f81602SSean Eric Fagan 		setsugid(p);
642229a15f0SPeter Wemm 	}
643b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
644b1fc0ec1SRobert Watson 	crfree(oldcred);
645835a82eeSMatthew Dillon done2:
646835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
647835a82eeSMatthew Dillon 	return (error);
648df8bae1dSRodney W. Grimes }
649df8bae1dSRodney W. Grimes 
650d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
651df8bae1dSRodney W. Grimes struct setgid_args {
652df8bae1dSRodney W. Grimes 	gid_t	gid;
653df8bae1dSRodney W. Grimes };
654d2d3e875SBruce Evans #endif
655835a82eeSMatthew Dillon /*
656835a82eeSMatthew Dillon  * MPSAFE
657835a82eeSMatthew Dillon  */
658df8bae1dSRodney W. Grimes /* ARGSUSED */
65926f9a767SRodney W. Grimes int
6604c44ad8eSJohn Baldwin setgid(struct thread *td, struct setgid_args *uap)
661df8bae1dSRodney W. Grimes {
662b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
663b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
664b1fc0ec1SRobert Watson 	gid_t gid;
665eb725b4eSRobert Watson 	int error;
666df8bae1dSRodney W. Grimes 
667b1fc0ec1SRobert Watson 	gid = uap->gid;
668835a82eeSMatthew Dillon 	mtx_lock(&Giant);
669eb725b4eSRobert Watson 	error = 0;
670b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
6715a92ee3cSRobert Watson 
672a08f4bf6SPeter Wemm 	/*
673a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
674a08f4bf6SPeter Wemm 	 *
675a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
676a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
6772fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
678a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
679a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
680a08f4bf6SPeter Wemm 	 *
681a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
682a08f4bf6SPeter Wemm 	 */
683b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
6843f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
685b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
686a08f4bf6SPeter Wemm #endif
687a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
688b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
6893f246666SAndrey A. Chernov #endif
69044731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
691835a82eeSMatthew Dillon 		goto done2;
692a08f4bf6SPeter Wemm 
693b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
694a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
695a08f4bf6SPeter Wemm 	/*
696a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
697a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
698a08f4bf6SPeter Wemm 	 */
699a08f4bf6SPeter Wemm 	if (
700a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
701b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
702a08f4bf6SPeter Wemm #endif
70344731cabSJohn Baldwin 	    suser_cred(oldcred, PRISON_ROOT) == 0) /* we are using privs */
704a08f4bf6SPeter Wemm #endif
705a08f4bf6SPeter Wemm 	{
706a08f4bf6SPeter Wemm 		/*
707a08f4bf6SPeter Wemm 		 * Set real gid
708a08f4bf6SPeter Wemm 		 */
709b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
710b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
711d5f81602SSean Eric Fagan 			setsugid(p);
712a08f4bf6SPeter Wemm 		}
713a08f4bf6SPeter Wemm 		/*
714a08f4bf6SPeter Wemm 		 * Set saved gid
715a08f4bf6SPeter Wemm 		 *
716a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
717a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
718a08f4bf6SPeter Wemm 		 * is important that we should do this.
719a08f4bf6SPeter Wemm 		 */
720b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
721b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
722d5f81602SSean Eric Fagan 			setsugid(p);
723a08f4bf6SPeter Wemm 		}
724a08f4bf6SPeter Wemm 	}
725a08f4bf6SPeter Wemm 	/*
726a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
727a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
728a08f4bf6SPeter Wemm 	 */
729b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
730b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
731d5f81602SSean Eric Fagan 		setsugid(p);
732a08f4bf6SPeter Wemm 	}
733b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
734b1fc0ec1SRobert Watson 	crfree(oldcred);
735835a82eeSMatthew Dillon done2:
736835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
737835a82eeSMatthew Dillon 	return (error);
738df8bae1dSRodney W. Grimes }
739df8bae1dSRodney W. Grimes 
740d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
741df8bae1dSRodney W. Grimes struct setegid_args {
742df8bae1dSRodney W. Grimes 	gid_t	egid;
743df8bae1dSRodney W. Grimes };
744d2d3e875SBruce Evans #endif
745835a82eeSMatthew Dillon /*
746835a82eeSMatthew Dillon  * MPSAFE
747835a82eeSMatthew Dillon  */
748df8bae1dSRodney W. Grimes /* ARGSUSED */
74926f9a767SRodney W. Grimes int
7504c44ad8eSJohn Baldwin setegid(struct thread *td, struct setegid_args *uap)
751df8bae1dSRodney W. Grimes {
752b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
753b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
754b1fc0ec1SRobert Watson 	gid_t egid;
755eb725b4eSRobert Watson 	int error;
756df8bae1dSRodney W. Grimes 
757df8bae1dSRodney W. Grimes 	egid = uap->egid;
758835a82eeSMatthew Dillon 	mtx_lock(&Giant);
759eb725b4eSRobert Watson 	error = 0;
760b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
761b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
762b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
76344731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
764835a82eeSMatthew Dillon 		goto done2;
765b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
766b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
767b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
768d5f81602SSean Eric Fagan 		setsugid(p);
769229a15f0SPeter Wemm 	}
770b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
771b1fc0ec1SRobert Watson 	crfree(oldcred);
772835a82eeSMatthew Dillon done2:
773835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
774835a82eeSMatthew Dillon 	return (error);
775df8bae1dSRodney W. Grimes }
776df8bae1dSRodney W. Grimes 
777d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
778df8bae1dSRodney W. Grimes struct setgroups_args {
779df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
780df8bae1dSRodney W. Grimes 	gid_t	*gidset;
781df8bae1dSRodney W. Grimes };
782d2d3e875SBruce Evans #endif
783835a82eeSMatthew Dillon /*
784835a82eeSMatthew Dillon  * MPSAFE
785835a82eeSMatthew Dillon  */
786df8bae1dSRodney W. Grimes /* ARGSUSED */
78726f9a767SRodney W. Grimes int
7884c44ad8eSJohn Baldwin setgroups(struct thread *td, struct setgroups_args *uap)
789df8bae1dSRodney W. Grimes {
790b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
791b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
792b1fc0ec1SRobert Watson 	u_int ngrp;
793df8bae1dSRodney W. Grimes 	int error;
794df8bae1dSRodney W. Grimes 
7953956a170SDavid Greenman 	ngrp = uap->gidsetsize;
7964f5a4612SRobert Watson 	mtx_lock(&Giant);
797b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
79844731cabSJohn Baldwin 	if ((error = suser_cred(oldcred, PRISON_ROOT)) != 0)
799835a82eeSMatthew Dillon 		goto done2;
800835a82eeSMatthew Dillon 	if (ngrp > NGROUPS) {
801835a82eeSMatthew Dillon 		error = EINVAL;
802835a82eeSMatthew Dillon 		goto done2;
803835a82eeSMatthew Dillon 	}
8048a5d815aSPeter Wemm 	/*
8058a5d815aSPeter Wemm 	 * XXX A little bit lazy here.  We could test if anything has
8068a5d815aSPeter Wemm 	 * changed before crcopy() and setting P_SUGID.
8078a5d815aSPeter Wemm 	 */
808b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
8098a5d815aSPeter Wemm 	if (ngrp < 1) {
8108a5d815aSPeter Wemm 		/*
8118a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
8128a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
8138a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
8148a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
8158a5d815aSPeter Wemm 		 */
816b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
8178a5d815aSPeter Wemm 	} else {
818bb56ec4aSPoul-Henning Kamp 		if ((error = copyin((caddr_t)uap->gidset,
819b1fc0ec1SRobert Watson 		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
820b1fc0ec1SRobert Watson 			crfree(newcred);
821835a82eeSMatthew Dillon 			goto done2;
822b1fc0ec1SRobert Watson 		}
823b1fc0ec1SRobert Watson 		newcred->cr_ngroups = ngrp;
8248a5d815aSPeter Wemm 	}
825d5f81602SSean Eric Fagan 	setsugid(p);
826b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
827b1fc0ec1SRobert Watson 	crfree(oldcred);
828835a82eeSMatthew Dillon done2:
829835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
830835a82eeSMatthew Dillon 	return (error);
831df8bae1dSRodney W. Grimes }
832df8bae1dSRodney W. Grimes 
833d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
834df8bae1dSRodney W. Grimes struct setreuid_args {
83500999cd6SAndrey A. Chernov 	uid_t	ruid;
83600999cd6SAndrey A. Chernov 	uid_t	euid;
837df8bae1dSRodney W. Grimes };
838d2d3e875SBruce Evans #endif
839835a82eeSMatthew Dillon /*
840835a82eeSMatthew Dillon  * MPSAFE
841835a82eeSMatthew Dillon  */
842df8bae1dSRodney W. Grimes /* ARGSUSED */
84326f9a767SRodney W. Grimes int
8444c44ad8eSJohn Baldwin setreuid(register struct thread *td, struct setreuid_args *uap)
845df8bae1dSRodney W. Grimes {
846b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
847b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
848eb725b4eSRobert Watson 	uid_t euid, ruid;
849eb725b4eSRobert Watson 	int error;
850df8bae1dSRodney W. Grimes 
85100999cd6SAndrey A. Chernov 	euid = uap->euid;
852eb725b4eSRobert Watson 	ruid = uap->ruid;
853835a82eeSMatthew Dillon 	mtx_lock(&Giant);
854eb725b4eSRobert Watson 	error = 0;
855b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
856b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
857b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
858b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
859b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
86044731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
861835a82eeSMatthew Dillon 		goto done2;
862b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
863b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
864b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
865d5f81602SSean Eric Fagan 		setsugid(p);
866a89a5370SPeter Wemm 	}
867b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
868b1fc0ec1SRobert Watson 		change_ruid(newcred, ruid);
869d5f81602SSean Eric Fagan 		setsugid(p);
87000999cd6SAndrey A. Chernov 	}
871b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
872b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
873b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
874d5f81602SSean Eric Fagan 		setsugid(p);
875a89a5370SPeter Wemm 	}
876b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
877b1fc0ec1SRobert Watson 	crfree(oldcred);
878835a82eeSMatthew Dillon done2:
879835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
880835a82eeSMatthew Dillon 	return (error);
881df8bae1dSRodney W. Grimes }
882df8bae1dSRodney W. Grimes 
883d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
884df8bae1dSRodney W. Grimes struct setregid_args {
88500999cd6SAndrey A. Chernov 	gid_t	rgid;
88600999cd6SAndrey A. Chernov 	gid_t	egid;
887df8bae1dSRodney W. Grimes };
888d2d3e875SBruce Evans #endif
889835a82eeSMatthew Dillon /*
890835a82eeSMatthew Dillon  * MPSAFE
891835a82eeSMatthew Dillon  */
892df8bae1dSRodney W. Grimes /* ARGSUSED */
89326f9a767SRodney W. Grimes int
8944c44ad8eSJohn Baldwin setregid(register struct thread *td, struct setregid_args *uap)
895df8bae1dSRodney W. Grimes {
896b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
897b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
898eb725b4eSRobert Watson 	gid_t egid, rgid;
899eb725b4eSRobert Watson 	int error;
900df8bae1dSRodney W. Grimes 
90100999cd6SAndrey A. Chernov 	egid = uap->egid;
902eb725b4eSRobert Watson 	rgid = uap->rgid;
903835a82eeSMatthew Dillon 	mtx_lock(&Giant);
904eb725b4eSRobert Watson 	error = 0;
905b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
906b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
907b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
908b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
909b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
91044731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
911835a82eeSMatthew Dillon 		goto done2;
912b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
913b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
914b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
915d5f81602SSean Eric Fagan 		setsugid(p);
916a89a5370SPeter Wemm 	}
917b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
918b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
919d5f81602SSean Eric Fagan 		setsugid(p);
920a89a5370SPeter Wemm 	}
921b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
922b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
923b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
924d5f81602SSean Eric Fagan 		setsugid(p);
925a89a5370SPeter Wemm 	}
9264589be70SRuslan Ermilov 	p->p_ucred = newcred;
9274589be70SRuslan Ermilov 	crfree(oldcred);
928835a82eeSMatthew Dillon done2:
929835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
930835a82eeSMatthew Dillon 	return (error);
931df8bae1dSRodney W. Grimes }
932df8bae1dSRodney W. Grimes 
9338ccd6334SPeter Wemm /*
9348ccd6334SPeter Wemm  * setresuid(ruid, euid, suid) is like setreuid except control over the
9358ccd6334SPeter Wemm  * saved uid is explicit.
9368ccd6334SPeter Wemm  */
9378ccd6334SPeter Wemm 
9388ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
9398ccd6334SPeter Wemm struct setresuid_args {
9408ccd6334SPeter Wemm 	uid_t	ruid;
9418ccd6334SPeter Wemm 	uid_t	euid;
9428ccd6334SPeter Wemm 	uid_t	suid;
9438ccd6334SPeter Wemm };
9448ccd6334SPeter Wemm #endif
945835a82eeSMatthew Dillon /*
946835a82eeSMatthew Dillon  * MPSAFE
947835a82eeSMatthew Dillon  */
9488ccd6334SPeter Wemm /* ARGSUSED */
9498ccd6334SPeter Wemm int
9504c44ad8eSJohn Baldwin setresuid(register struct thread *td, struct setresuid_args *uap)
9518ccd6334SPeter Wemm {
952b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
953b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
954eb725b4eSRobert Watson 	uid_t euid, ruid, suid;
9558ccd6334SPeter Wemm 	int error;
9568ccd6334SPeter Wemm 
9578ccd6334SPeter Wemm 	euid = uap->euid;
958eb725b4eSRobert Watson 	ruid = uap->ruid;
9598ccd6334SPeter Wemm 	suid = uap->suid;
960835a82eeSMatthew Dillon 	mtx_lock(&Giant);
961b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
962b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
963b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
964b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
965b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
966b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
967b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
968b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
969b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
970b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
97144731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
972835a82eeSMatthew Dillon 		goto done2;
973b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
974b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
975b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
9768ccd6334SPeter Wemm 		setsugid(p);
9778ccd6334SPeter Wemm 	}
978b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
979b1fc0ec1SRobert Watson 		change_ruid(newcred, ruid);
9808ccd6334SPeter Wemm 		setsugid(p);
9818ccd6334SPeter Wemm 	}
982b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
983b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
9848ccd6334SPeter Wemm 		setsugid(p);
9858ccd6334SPeter Wemm 	}
986b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
987b1fc0ec1SRobert Watson 	crfree(oldcred);
988835a82eeSMatthew Dillon 	error = 0;
989835a82eeSMatthew Dillon done2:
990835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
991835a82eeSMatthew Dillon 	return (error);
9928ccd6334SPeter Wemm }
9938ccd6334SPeter Wemm 
9948ccd6334SPeter Wemm /*
9958ccd6334SPeter Wemm  * setresgid(rgid, egid, sgid) is like setregid except control over the
9968ccd6334SPeter Wemm  * saved gid is explicit.
9978ccd6334SPeter Wemm  */
9988ccd6334SPeter Wemm 
9998ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10008ccd6334SPeter Wemm struct setresgid_args {
10018ccd6334SPeter Wemm 	gid_t	rgid;
10028ccd6334SPeter Wemm 	gid_t	egid;
10038ccd6334SPeter Wemm 	gid_t	sgid;
10048ccd6334SPeter Wemm };
10058ccd6334SPeter Wemm #endif
1006835a82eeSMatthew Dillon /*
1007835a82eeSMatthew Dillon  * MPSAFE
1008835a82eeSMatthew Dillon  */
10098ccd6334SPeter Wemm /* ARGSUSED */
10108ccd6334SPeter Wemm int
10114c44ad8eSJohn Baldwin setresgid(register struct thread *td, struct setresgid_args *uap)
10128ccd6334SPeter Wemm {
1013b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1014b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1015eb725b4eSRobert Watson 	gid_t egid, rgid, sgid;
10168ccd6334SPeter Wemm 	int error;
10178ccd6334SPeter Wemm 
10188ccd6334SPeter Wemm 	egid = uap->egid;
1019eb725b4eSRobert Watson 	rgid = uap->rgid;
10208ccd6334SPeter Wemm 	sgid = uap->sgid;
1021835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1022b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
1023b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1024b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1025b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1026b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1027b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1028b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1029b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1030b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1031b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
103244731cabSJohn Baldwin 	    (error = suser_cred(oldcred, PRISON_ROOT)) != 0)
1033835a82eeSMatthew Dillon 		goto done2;
1034b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
1035b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1036b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
10378ccd6334SPeter Wemm 		setsugid(p);
10388ccd6334SPeter Wemm 	}
1039b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1040b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
10418ccd6334SPeter Wemm 		setsugid(p);
10428ccd6334SPeter Wemm 	}
1043b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1044b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
10458ccd6334SPeter Wemm 		setsugid(p);
10468ccd6334SPeter Wemm 	}
1047b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
1048b1fc0ec1SRobert Watson 	crfree(oldcred);
1049835a82eeSMatthew Dillon 	error = 0;
1050835a82eeSMatthew Dillon done2:
1051835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1052835a82eeSMatthew Dillon 	return (error);
10538ccd6334SPeter Wemm }
10548ccd6334SPeter Wemm 
10558ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10568ccd6334SPeter Wemm struct getresuid_args {
10578ccd6334SPeter Wemm 	uid_t	*ruid;
10588ccd6334SPeter Wemm 	uid_t	*euid;
10598ccd6334SPeter Wemm 	uid_t	*suid;
10608ccd6334SPeter Wemm };
10618ccd6334SPeter Wemm #endif
1062835a82eeSMatthew Dillon /*
1063835a82eeSMatthew Dillon  * MPSAFE
1064835a82eeSMatthew Dillon  */
10658ccd6334SPeter Wemm /* ARGSUSED */
10668ccd6334SPeter Wemm int
10674c44ad8eSJohn Baldwin getresuid(register struct thread *td, struct getresuid_args *uap)
10688ccd6334SPeter Wemm {
1069835a82eeSMatthew Dillon 	struct ucred *cred;
10708ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
10718ccd6334SPeter Wemm 
1072d74ac681SMatthew Dillon 	cred = td->td_ucred;
10738ccd6334SPeter Wemm 	if (uap->ruid)
1074b1fc0ec1SRobert Watson 		error1 = copyout((caddr_t)&cred->cr_ruid,
1075b1fc0ec1SRobert Watson 		    (caddr_t)uap->ruid, sizeof(cred->cr_ruid));
10768ccd6334SPeter Wemm 	if (uap->euid)
1077b1fc0ec1SRobert Watson 		error2 = copyout((caddr_t)&cred->cr_uid,
1078b1fc0ec1SRobert Watson 		    (caddr_t)uap->euid, sizeof(cred->cr_uid));
10798ccd6334SPeter Wemm 	if (uap->suid)
1080b1fc0ec1SRobert Watson 		error3 = copyout((caddr_t)&cred->cr_svuid,
1081b1fc0ec1SRobert Watson 		    (caddr_t)uap->suid, sizeof(cred->cr_svuid));
1082eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
10838ccd6334SPeter Wemm }
10848ccd6334SPeter Wemm 
10858ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10868ccd6334SPeter Wemm struct getresgid_args {
10878ccd6334SPeter Wemm 	gid_t	*rgid;
10888ccd6334SPeter Wemm 	gid_t	*egid;
10898ccd6334SPeter Wemm 	gid_t	*sgid;
10908ccd6334SPeter Wemm };
10918ccd6334SPeter Wemm #endif
1092835a82eeSMatthew Dillon /*
1093835a82eeSMatthew Dillon  * MPSAFE
1094835a82eeSMatthew Dillon  */
10958ccd6334SPeter Wemm /* ARGSUSED */
10968ccd6334SPeter Wemm int
10974c44ad8eSJohn Baldwin getresgid(register struct thread *td, struct getresgid_args *uap)
10988ccd6334SPeter Wemm {
1099835a82eeSMatthew Dillon 	struct ucred *cred;
11008ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11018ccd6334SPeter Wemm 
1102d74ac681SMatthew Dillon 	cred = td->td_ucred;
11038ccd6334SPeter Wemm 	if (uap->rgid)
1104b1fc0ec1SRobert Watson 		error1 = copyout((caddr_t)&cred->cr_rgid,
1105b1fc0ec1SRobert Watson 		    (caddr_t)uap->rgid, sizeof(cred->cr_rgid));
11068ccd6334SPeter Wemm 	if (uap->egid)
1107b1fc0ec1SRobert Watson 		error2 = copyout((caddr_t)&cred->cr_groups[0],
1108b1fc0ec1SRobert Watson 		    (caddr_t)uap->egid, sizeof(cred->cr_groups[0]));
11098ccd6334SPeter Wemm 	if (uap->sgid)
1110b1fc0ec1SRobert Watson 		error3 = copyout((caddr_t)&cred->cr_svgid,
1111b1fc0ec1SRobert Watson 		    (caddr_t)uap->sgid, sizeof(cred->cr_svgid));
1112eb725b4eSRobert Watson 	return (error1 ? error1 : error2 ? error2 : error3);
11138ccd6334SPeter Wemm }
11148ccd6334SPeter Wemm 
1115b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1116b67cbc65SPeter Wemm struct issetugid_args {
1117b67cbc65SPeter Wemm 	int dummy;
1118b67cbc65SPeter Wemm };
1119b67cbc65SPeter Wemm #endif
1120eb725b4eSRobert Watson /*
1121eb725b4eSRobert Watson  * NOT MPSAFE?
1122eb725b4eSRobert Watson  */
1123b67cbc65SPeter Wemm /* ARGSUSED */
1124b67cbc65SPeter Wemm int
11254c44ad8eSJohn Baldwin issetugid(register struct thread *td, struct issetugid_args *uap)
1126b67cbc65SPeter Wemm {
1127b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1128b40ce416SJulian Elischer 
1129b67cbc65SPeter Wemm 	/*
1130b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1131b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1132b67cbc65SPeter Wemm 	 * "tainting" as well.
1133b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1134b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1135b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1136b67cbc65SPeter Wemm 	 */
1137f591779bSSeigo Tanimura 	PROC_LOCK(p);
1138b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1139f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
1140b67cbc65SPeter Wemm 	return (0);
1141b67cbc65SPeter Wemm }
1142b67cbc65SPeter Wemm 
1143835a82eeSMatthew Dillon /*
1144835a82eeSMatthew Dillon  * MPSAFE
1145835a82eeSMatthew Dillon  */
1146130d0157SRobert Watson int
11474c44ad8eSJohn Baldwin __setugid(struct thread *td, struct __setugid_args *uap)
1148130d0157SRobert Watson {
1149130d0157SRobert Watson #ifdef REGRESSION
1150eb725b4eSRobert Watson 	int error;
1151835a82eeSMatthew Dillon 
1152835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1153eb725b4eSRobert Watson 	error = 0;
1154130d0157SRobert Watson 	switch (uap->flag) {
1155130d0157SRobert Watson 	case 0:
1156f591779bSSeigo Tanimura 		PROC_LOCK(td->td_proc);
1157b40ce416SJulian Elischer 		td->td_proc->p_flag &= ~P_SUGID;
1158f591779bSSeigo Tanimura 		PROC_UNLOCK(td->td_proc);
1159835a82eeSMatthew Dillon 		break;
1160130d0157SRobert Watson 	case 1:
1161f591779bSSeigo Tanimura 		PROC_LOCK(td->td_proc);
1162b40ce416SJulian Elischer 		td->td_proc->p_flag |= P_SUGID;
1163f591779bSSeigo Tanimura 		PROC_UNLOCK(td->td_proc);
1164835a82eeSMatthew Dillon 		break;
1165130d0157SRobert Watson 	default:
1166835a82eeSMatthew Dillon 		error = EINVAL;
1167835a82eeSMatthew Dillon 		break;
1168130d0157SRobert Watson 	}
1169835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1170835a82eeSMatthew Dillon 	return (error);
1171130d0157SRobert Watson #else /* !REGRESSION */
1172eb725b4eSRobert Watson 
1173130d0157SRobert Watson 	return (ENOSYS);
1174eb725b4eSRobert Watson #endif /* REGRESSION */
1175130d0157SRobert Watson }
1176130d0157SRobert Watson 
1177df8bae1dSRodney W. Grimes /*
1178df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
1179d74ac681SMatthew Dillon  *
1180d74ac681SMatthew Dillon  * MPSAFE (cred must be held)
1181df8bae1dSRodney W. Grimes  */
118226f9a767SRodney W. Grimes int
11834c44ad8eSJohn Baldwin groupmember(gid_t gid, struct ucred *cred)
1184df8bae1dSRodney W. Grimes {
1185df8bae1dSRodney W. Grimes 	register gid_t *gp;
1186df8bae1dSRodney W. Grimes 	gid_t *egp;
1187df8bae1dSRodney W. Grimes 
1188df8bae1dSRodney W. Grimes 	egp = &(cred->cr_groups[cred->cr_ngroups]);
1189df8bae1dSRodney W. Grimes 	for (gp = cred->cr_groups; gp < egp; gp++)
1190df8bae1dSRodney W. Grimes 		if (*gp == gid)
1191df8bae1dSRodney W. Grimes 			return (1);
1192df8bae1dSRodney W. Grimes 	return (0);
1193df8bae1dSRodney W. Grimes }
1194df8bae1dSRodney W. Grimes 
11953b243b72SRobert Watson /*
1196d0615c64SAndrew R. Reiter  * `suser_enabled' (which can be set by the security.suser_enabled
11977fd6a959SRobert Watson  * sysctl) determines whether the system 'super-user' policy is in effect.
11987fd6a959SRobert Watson  * If it is nonzero, an effective uid of 0 connotes special privilege,
11997fd6a959SRobert Watson  * overriding many mandatory and discretionary protections.  If it is zero,
12007fd6a959SRobert Watson  * uid 0 is offered no special privilege in the kernel security policy.
12017fd6a959SRobert Watson  * Setting it to zero may seriously impact the functionality of many
12027fd6a959SRobert Watson  * existing userland programs, and should not be done without careful
12037fd6a959SRobert Watson  * consideration of the consequences.
12043b243b72SRobert Watson  */
120593f4fd1cSRobert Watson int	suser_enabled = 1;
1206d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW,
120793f4fd1cSRobert Watson     &suser_enabled, 0, "processes with uid 0 have privilege");
1208d0615c64SAndrew R. Reiter TUNABLE_INT("security.bsd.suser_enabled", &suser_enabled);
1209579f4eb4SRobert Watson 
1210df8bae1dSRodney W. Grimes /*
12117fd6a959SRobert Watson  * Test whether the specified credentials imply "super-user" privilege.
121244731cabSJohn Baldwin  * Return 0 or EPERM.  The flag argument is currently used only to
121344731cabSJohn Baldwin  * specify jail interaction.
1214df8bae1dSRodney W. Grimes  */
121526f9a767SRodney W. Grimes int
121644731cabSJohn Baldwin suser_cred(struct ucred *cred, int flag)
1217f711d546SPoul-Henning Kamp {
1218eb725b4eSRobert Watson 
121993f4fd1cSRobert Watson 	if (!suser_enabled)
122003095547SRobert Watson 		return (EPERM);
122175c13541SPoul-Henning Kamp 	if (cred->cr_uid != 0)
122275c13541SPoul-Henning Kamp 		return (EPERM);
122391421ba2SRobert Watson 	if (jailed(cred) && !(flag & PRISON_ROOT))
122475c13541SPoul-Henning Kamp 		return (EPERM);
122575c13541SPoul-Henning Kamp 	return (0);
122675c13541SPoul-Henning Kamp }
1227df8bae1dSRodney W. Grimes 
12283ca719f1SRobert Watson /*
122944731cabSJohn Baldwin  * Shortcut to hide contents of struct td and struct proc from the
123044731cabSJohn Baldwin  * caller, promoting binary compatibility.
123144731cabSJohn Baldwin  */
123244731cabSJohn Baldwin int
123344731cabSJohn Baldwin suser(struct thread *td)
123444731cabSJohn Baldwin {
123544731cabSJohn Baldwin 
123644731cabSJohn Baldwin 	return (suser_cred(td->td_ucred, 0));
123744731cabSJohn Baldwin }
123844731cabSJohn Baldwin 
123944731cabSJohn Baldwin /*
1240eb725b4eSRobert Watson  * Test the active securelevel against a given level.  securelevel_gt()
1241eb725b4eSRobert Watson  * implements (securelevel > level).  securelevel_ge() implements
1242eb725b4eSRobert Watson  * (securelevel >= level).  Note that the logic is inverted -- these
1243eb725b4eSRobert Watson  * functions return EPERM on "success" and 0 on "failure".
12443ca719f1SRobert Watson  *
1245d74ac681SMatthew Dillon  * MPSAFE
12463ca719f1SRobert Watson  */
12473ca719f1SRobert Watson int
12483ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
12493ca719f1SRobert Watson {
1250eb725b4eSRobert Watson 	int active_securelevel;
12513ca719f1SRobert Watson 
1252eb725b4eSRobert Watson 	active_securelevel = securelevel;
125370499328SJohn Baldwin 	KASSERT(cr != NULL, ("securelevel_gt: null cr"));
125401137630SRobert Watson 	if (cr->cr_prison != NULL) {
125501137630SRobert Watson 		mtx_lock(&cr->cr_prison->pr_mtx);
1256eb725b4eSRobert Watson 		active_securelevel = imax(cr->cr_prison->pr_securelevel,
1257eb725b4eSRobert Watson 		    active_securelevel);
125801137630SRobert Watson 		mtx_unlock(&cr->cr_prison->pr_mtx);
125901137630SRobert Watson 	}
1260eb725b4eSRobert Watson 	return (active_securelevel > level ? EPERM : 0);
12613ca719f1SRobert Watson }
12623ca719f1SRobert Watson 
12633ca719f1SRobert Watson int
12643ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
12653ca719f1SRobert Watson {
1266eb725b4eSRobert Watson 	int active_securelevel;
12673ca719f1SRobert Watson 
1268eb725b4eSRobert Watson 	active_securelevel = securelevel;
126970499328SJohn Baldwin 	KASSERT(cr != NULL, ("securelevel_ge: null cr"));
127001137630SRobert Watson 	if (cr->cr_prison != NULL) {
127101137630SRobert Watson 		mtx_lock(&cr->cr_prison->pr_mtx);
1272eb725b4eSRobert Watson 		active_securelevel = imax(cr->cr_prison->pr_securelevel,
1273eb725b4eSRobert Watson 		    active_securelevel);
127401137630SRobert Watson 		mtx_unlock(&cr->cr_prison->pr_mtx);
127501137630SRobert Watson 	}
1276eb725b4eSRobert Watson 	return (active_securelevel >= level ? EPERM : 0);
12773ca719f1SRobert Watson }
12783ca719f1SRobert Watson 
12798a7d8cc6SRobert Watson /*
1280e409590dSRobert Watson  * 'see_other_uids' determines whether or not visibility of processes
1281eb725b4eSRobert Watson  * and sockets with credentials holding different real uids is possible
128248713bdcSRobert Watson  * using a variety of system MIBs.
1283eb725b4eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
12848a7d8cc6SRobert Watson  */
1285e409590dSRobert Watson static int	see_other_uids = 1;
1286d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
1287eb725b4eSRobert Watson     &see_other_uids, 0,
12888a7d8cc6SRobert Watson     "Unprivileged processes may see subjects/objects with different real uid");
12898a7d8cc6SRobert Watson 
12907fd6a959SRobert Watson /*-
12911b350b45SRobert Watson  * Determine if u1 "can see" the subject specified by u2, according to the
12921b350b45SRobert Watson  * 'see_other_uids' policy.
12931b350b45SRobert Watson  * Returns: 0 for permitted, ESRCH otherwise
12941b350b45SRobert Watson  * Locks: none
12951b350b45SRobert Watson  * References: *u1 and *u2 must not change during the call
12961b350b45SRobert Watson  *             u1 may equal u2, in which case only one reference is required
12971b350b45SRobert Watson  */
12981b350b45SRobert Watson static int
12991b350b45SRobert Watson cr_seeotheruids(struct ucred *u1, struct ucred *u2)
13001b350b45SRobert Watson {
13011b350b45SRobert Watson 
13021b350b45SRobert Watson 	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
130344731cabSJohn Baldwin 		if (suser_cred(u1, PRISON_ROOT) != 0)
13041b350b45SRobert Watson 			return (ESRCH);
13051b350b45SRobert Watson 	}
13061b350b45SRobert Watson 	return (0);
13071b350b45SRobert Watson }
13081b350b45SRobert Watson 
13091b350b45SRobert Watson /*-
13107fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1311ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1312ed639720SRobert Watson  * Locks: none
1313eb725b4eSRobert Watson  * References: *u1 and *u2 must not change during the call
1314ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1315ed639720SRobert Watson  */
1316ed639720SRobert Watson int
131794088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1318a9e0361bSPoul-Henning Kamp {
131991421ba2SRobert Watson 	int error;
1320a9e0361bSPoul-Henning Kamp 
1321ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
132291421ba2SRobert Watson 		return (error);
13231b350b45SRobert Watson 	if ((error = cr_seeotheruids(u1, u2)))
13241b350b45SRobert Watson 		return (error);
1325387d2c03SRobert Watson 	return (0);
1326387d2c03SRobert Watson }
1327387d2c03SRobert Watson 
13287fd6a959SRobert Watson /*-
13297fd6a959SRobert Watson  * Determine if p1 "can see" the subject specified by p2.
13303b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
13317fd6a959SRobert Watson  * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must
13323b243b72SRobert Watson  *        be held.  Normally, p1 will be curproc, and a lock must be held
13333b243b72SRobert Watson  *        for p2.
13343b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
13353b243b72SRobert Watson  */
1336a0f75161SRobert Watson int
1337a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2)
1338ed639720SRobert Watson {
1339ed639720SRobert Watson 
134094088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
134194088977SRobert Watson 	return (cr_cansee(p1->p_ucred, p2->p_ucred));
1342ed639720SRobert Watson }
1343ed639720SRobert Watson 
13447fd6a959SRobert Watson /*-
1345c83f8015SRobert Watson  * Determine whether cred may deliver the specified signal to proc.
1346c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise.
1347c83f8015SRobert Watson  * Locks: A lock must be held for proc.
1348c83f8015SRobert Watson  * References: cred and proc must be valid for the lifetime of the call.
13494c5eb9c3SRobert Watson  */
13504c5eb9c3SRobert Watson int
1351c83f8015SRobert Watson cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
1352387d2c03SRobert Watson {
135391421ba2SRobert Watson 	int error;
1354387d2c03SRobert Watson 
13554c5eb9c3SRobert Watson 	/*
1356c83f8015SRobert Watson 	 * Jail semantics limit the scope of signalling to proc in the
1357c83f8015SRobert Watson 	 * same jail as cred, if cred is in jail.
13584c5eb9c3SRobert Watson 	 */
1359c83f8015SRobert Watson 	error = prison_check(cred, proc->p_ucred);
1360c83f8015SRobert Watson 	if (error)
136191421ba2SRobert Watson 		return (error);
13621b350b45SRobert Watson 	error = cr_seeotheruids(cred, proc->p_ucred);
13631b350b45SRobert Watson 	if (error)
13641b350b45SRobert Watson 		return (error);
1365387d2c03SRobert Watson 
1366387d2c03SRobert Watson 	/*
13673b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
13683b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
13693b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
13704c5eb9c3SRobert Watson 	 */
1371c83f8015SRobert Watson 	if (proc->p_flag & P_SUGID) {
13724c5eb9c3SRobert Watson 		switch (signum) {
13734c5eb9c3SRobert Watson 		case 0:
13744c5eb9c3SRobert Watson 		case SIGKILL:
13754c5eb9c3SRobert Watson 		case SIGINT:
13764c5eb9c3SRobert Watson 		case SIGTERM:
13774c5eb9c3SRobert Watson 		case SIGSTOP:
13784c5eb9c3SRobert Watson 		case SIGTTIN:
13794c5eb9c3SRobert Watson 		case SIGTTOU:
13804c5eb9c3SRobert Watson 		case SIGTSTP:
13814c5eb9c3SRobert Watson 		case SIGHUP:
13824c5eb9c3SRobert Watson 		case SIGUSR1:
13834c5eb9c3SRobert Watson 		case SIGUSR2:
13847fd6a959SRobert Watson 			/*
13857fd6a959SRobert Watson 			 * Generally, permit job and terminal control
13867fd6a959SRobert Watson 			 * signals.
13877fd6a959SRobert Watson 			 */
13884c5eb9c3SRobert Watson 			break;
13894c5eb9c3SRobert Watson 		default:
1390c83f8015SRobert Watson 			/* Not permitted without privilege. */
139144731cabSJohn Baldwin 			error = suser_cred(cred, PRISON_ROOT);
13924c5eb9c3SRobert Watson 			if (error)
13934c5eb9c3SRobert Watson 				return (error);
13944c5eb9c3SRobert Watson 		}
1395e9e7ff5bSRobert Watson 	}
1396e9e7ff5bSRobert Watson 
13974c5eb9c3SRobert Watson 	/*
13983b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1399e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
14004c5eb9c3SRobert Watson 	 */
1401c83f8015SRobert Watson 	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
1402c83f8015SRobert Watson 	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
1403c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_ruid &&
1404c83f8015SRobert Watson 	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1405c83f8015SRobert Watson 		/* Not permitted without privilege. */
140644731cabSJohn Baldwin 		error = suser_cred(cred, PRISON_ROOT);
14074c5eb9c3SRobert Watson 		if (error)
14084c5eb9c3SRobert Watson 			return (error);
14094c5eb9c3SRobert Watson 	}
1410387d2c03SRobert Watson 
1411387d2c03SRobert Watson 	return (0);
1412387d2c03SRobert Watson }
1413a9e0361bSPoul-Henning Kamp 
1414c83f8015SRobert Watson 
1415c83f8015SRobert Watson /*-
1416c83f8015SRobert Watson  * Determine whether p1 may deliver the specified signal to p2.
1417c83f8015SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1418c83f8015SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
1419c83f8015SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
1420c83f8015SRobert Watson  *        be held for p2.
1421c83f8015SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
1422c83f8015SRobert Watson  */
1423c83f8015SRobert Watson int
1424c83f8015SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum)
1425c83f8015SRobert Watson {
1426c83f8015SRobert Watson 
1427c83f8015SRobert Watson 	if (p1 == p2)
1428c83f8015SRobert Watson 		return (0);
1429c83f8015SRobert Watson 
1430c83f8015SRobert Watson 	/*
1431c83f8015SRobert Watson 	 * UNIX signalling semantics require that processes in the same
1432c83f8015SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
1433c83f8015SRobert Watson 	 * overriding the remaining protections.
1434c83f8015SRobert Watson 	 */
1435c83f8015SRobert Watson 	if (signum == SIGCONT && p1->p_session == p2->p_session)
1436c83f8015SRobert Watson 		return (0);
1437c83f8015SRobert Watson 
1438c83f8015SRobert Watson 	return (cr_cansignal(p1->p_ucred, p2, signum));
1439c83f8015SRobert Watson }
1440c83f8015SRobert Watson 
14417fd6a959SRobert Watson /*-
1442eb725b4eSRobert Watson  * Determine whether p1 may reschedule p2.
14437fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
14443b243b72SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
14453b243b72SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
14467fd6a959SRobert Watson  *        be held for p2.
14473b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
14483b243b72SRobert Watson  */
1449a0f75161SRobert Watson int
1450a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2)
1451387d2c03SRobert Watson {
145291421ba2SRobert Watson 	int error;
1453387d2c03SRobert Watson 
1454387d2c03SRobert Watson 	if (p1 == p2)
1455387d2c03SRobert Watson 		return (0);
145691421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
145791421ba2SRobert Watson 		return (error);
14581b350b45SRobert Watson 	if ((error = cr_seeotheruids(p1->p_ucred, p2->p_ucred)))
14591b350b45SRobert Watson 		return (error);
1460b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid)
1461387d2c03SRobert Watson 		return (0);
1462b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid)
1463387d2c03SRobert Watson 		return (0);
146444731cabSJohn Baldwin 	if (suser_cred(p1->p_ucred, PRISON_ROOT) == 0)
1465387d2c03SRobert Watson 		return (0);
1466387d2c03SRobert Watson 
1467387d2c03SRobert Watson #ifdef CAPABILITIES
14684df571b1SRobert Watson 	if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT))
1469387d2c03SRobert Watson 		return (0);
1470387d2c03SRobert Watson #endif
1471387d2c03SRobert Watson 
1472387d2c03SRobert Watson 	return (EPERM);
1473387d2c03SRobert Watson }
1474387d2c03SRobert Watson 
14753b243b72SRobert Watson /*
14765d476e73SRobert Watson  * The 'unprivileged_proc_debug' flag may be used to disable a variety of
14775d476e73SRobert Watson  * unprivileged inter-process debugging services, including some procfs
14785d476e73SRobert Watson  * functionality, ptrace(), and ktrace().  In the past, inter-process
14795d476e73SRobert Watson  * debugging has been involved in a variety of security problems, and sites
14805d476e73SRobert Watson  * not requiring the service might choose to disable it when hardening
14815d476e73SRobert Watson  * systems.
14823b243b72SRobert Watson  *
14833b243b72SRobert Watson  * XXX: Should modifying and reading this variable require locking?
1484eb725b4eSRobert Watson  * XXX: data declarations should be together near the beginning of the file.
14853b243b72SRobert Watson  */
1486e409590dSRobert Watson static int	unprivileged_proc_debug = 1;
1487d0615c64SAndrew R. Reiter SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
1488eb725b4eSRobert Watson     &unprivileged_proc_debug, 0,
14890ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
14900ef5652eSRobert Watson 
14917fd6a959SRobert Watson /*-
14927fd6a959SRobert Watson  * Determine whether p1 may debug p2.
14937fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
14947fd6a959SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
14957fd6a959SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
14967fd6a959SRobert Watson  *        be held for p2.
14973b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
14983b243b72SRobert Watson  */
1499a0f75161SRobert Watson int
1500a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2)
1501387d2c03SRobert Watson {
1502eb725b4eSRobert Watson 	int credentialchanged, error, grpsubset, i, uidsubset;
1503387d2c03SRobert Watson 
1504e409590dSRobert Watson 	if (!unprivileged_proc_debug) {
150544731cabSJohn Baldwin 		error = suser_cred(p1->p_ucred, PRISON_ROOT);
150632d18604SRobert Watson 		if (error)
150732d18604SRobert Watson 			return (error);
150832d18604SRobert Watson 	}
150923fad5b6SDag-Erling Smørgrav 	if (p1 == p2)
151023fad5b6SDag-Erling Smørgrav 		return (0);
151191421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
151291421ba2SRobert Watson 		return (error);
15131b350b45SRobert Watson 	if ((error = cr_seeotheruids(p1->p_ucred, p2->p_ucred)))
15141b350b45SRobert Watson 		return (error);
1515387d2c03SRobert Watson 
15167fd6a959SRobert Watson 	/*
1517db42a33dSRobert Watson 	 * Is p2's group set a subset of p1's effective group set?  This
1518db42a33dSRobert Watson 	 * includes p2's egid, group access list, rgid, and svgid.
15197fd6a959SRobert Watson 	 */
1520db42a33dSRobert Watson 	grpsubset = 1;
1521db42a33dSRobert Watson 	for (i = 0; i < p2->p_ucred->cr_ngroups; i++) {
1522db42a33dSRobert Watson 		if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) {
1523db42a33dSRobert Watson 			grpsubset = 0;
1524db42a33dSRobert Watson 			break;
1525db42a33dSRobert Watson 		}
1526db42a33dSRobert Watson 	}
1527db42a33dSRobert Watson 	grpsubset = grpsubset &&
1528db42a33dSRobert Watson 	    groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) &&
1529db42a33dSRobert Watson 	    groupmember(p2->p_ucred->cr_svgid, p1->p_ucred);
1530db42a33dSRobert Watson 
1531db42a33dSRobert Watson 	/*
1532db42a33dSRobert Watson 	 * Are the uids present in p2's credential equal to p1's
1533db42a33dSRobert Watson 	 * effective uid?  This includes p2's euid, svuid, and ruid.
1534db42a33dSRobert Watson 	 */
1535db42a33dSRobert Watson 	uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid &&
1536db42a33dSRobert Watson 	    p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid &&
1537db42a33dSRobert Watson 	    p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid);
1538db42a33dSRobert Watson 
1539db42a33dSRobert Watson 	/*
1540db42a33dSRobert Watson 	 * Has the credential of the process changed since the last exec()?
1541db42a33dSRobert Watson 	 */
1542db42a33dSRobert Watson 	credentialchanged = (p2->p_flag & P_SUGID);
1543db42a33dSRobert Watson 
1544db42a33dSRobert Watson 	/*
1545db42a33dSRobert Watson 	 * If p2's gids aren't a subset, or the uids aren't a subset,
1546db42a33dSRobert Watson 	 * or the credential has changed, require appropriate privilege
1547db42a33dSRobert Watson 	 * for p1 to debug p2.  For POSIX.1e capabilities, this will
1548db42a33dSRobert Watson 	 * require CAP_SYS_PTRACE.
1549db42a33dSRobert Watson 	 */
1550db42a33dSRobert Watson 	if (!grpsubset || !uidsubset || credentialchanged) {
155144731cabSJohn Baldwin 		error = suser_cred(p1->p_ucred, PRISON_ROOT);
155232d18604SRobert Watson 		if (error)
1553387d2c03SRobert Watson 			return (error);
15547fd6a959SRobert Watson 	}
1555387d2c03SRobert Watson 
1556eb725b4eSRobert Watson 	/* Can't trace init when securelevel > 0. */
1557eb725b4eSRobert Watson 	if (p2 == initproc) {
15583ca719f1SRobert Watson 		error = securelevel_gt(p1->p_ucred, 0);
15593ca719f1SRobert Watson 		if (error)
15603ca719f1SRobert Watson 			return (error);
15613ca719f1SRobert Watson 	}
1562387d2c03SRobert Watson 
15635fab7614SRobert Watson 	/*
15645fab7614SRobert Watson 	 * Can't trace a process that's currently exec'ing.
15655fab7614SRobert Watson 	 * XXX: Note, this is not a security policy decision, it's a
15665fab7614SRobert Watson 	 * basic correctness/functionality decision.  Therefore, this check
15675fab7614SRobert Watson 	 * should be moved to the caller's of p_candebug().
15685fab7614SRobert Watson 	 */
15699ca45e81SDag-Erling Smørgrav 	if ((p2->p_flag & P_INEXEC) != 0)
15709ca45e81SDag-Erling Smørgrav 		return (EAGAIN);
15719ca45e81SDag-Erling Smørgrav 
1572387d2c03SRobert Watson 	return (0);
1573387d2c03SRobert Watson }
1574387d2c03SRobert Watson 
157529dc1288SRobert Watson /*-
157629dc1288SRobert Watson  * Determine whether the subject represented by cred can "see" a socket.
157729dc1288SRobert Watson  * Returns: 0 for permitted, ENOENT otherwise.
157829dc1288SRobert Watson  */
157929dc1288SRobert Watson int
158029dc1288SRobert Watson cr_canseesocket(struct ucred *cred, struct socket *so)
158129dc1288SRobert Watson {
158229dc1288SRobert Watson 	int error;
158329dc1288SRobert Watson 
158429dc1288SRobert Watson 	error = prison_check(cred, so->so_cred);
158529dc1288SRobert Watson 	if (error)
158629dc1288SRobert Watson 		return (ENOENT);
158729dc1288SRobert Watson 	if (cr_seeotheruids(cred, so->so_cred))
158829dc1288SRobert Watson 		return (ENOENT);
158929dc1288SRobert Watson #ifdef MAC
159029dc1288SRobert Watson 	/* XXX: error = mac_cred_check_seesocket() here. */
159129dc1288SRobert Watson #endif
159229dc1288SRobert Watson 
159329dc1288SRobert Watson 	return (0);
159429dc1288SRobert Watson }
159529dc1288SRobert Watson 
1596a9e0361bSPoul-Henning Kamp /*
1597df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1598df8bae1dSRodney W. Grimes  */
1599df8bae1dSRodney W. Grimes struct ucred *
16004c44ad8eSJohn Baldwin crget(void)
1601df8bae1dSRodney W. Grimes {
1602df8bae1dSRodney W. Grimes 	register struct ucred *cr;
1603df8bae1dSRodney W. Grimes 
16041e5d626aSAlfred Perlstein 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1605df8bae1dSRodney W. Grimes 	cr->cr_ref = 1;
1606e1bca29fSMatthew Dillon 	cr->cr_mtxp = mtx_pool_find(cr);
1607df8bae1dSRodney W. Grimes 	return (cr);
1608df8bae1dSRodney W. Grimes }
1609df8bae1dSRodney W. Grimes 
1610df8bae1dSRodney W. Grimes /*
16117fd6a959SRobert Watson  * Claim another reference to a ucred structure.
16125c3f70d7SAlfred Perlstein  */
1613bd78ceceSJohn Baldwin struct ucred *
16144c44ad8eSJohn Baldwin crhold(struct ucred *cr)
16155c3f70d7SAlfred Perlstein {
16165c3f70d7SAlfred Perlstein 
1617e1bca29fSMatthew Dillon 	mtx_lock(cr->cr_mtxp);
16185c3f70d7SAlfred Perlstein 	cr->cr_ref++;
1619e1bca29fSMatthew Dillon 	mtx_unlock(cr->cr_mtxp);
1620bd78ceceSJohn Baldwin 	return (cr);
16215c3f70d7SAlfred Perlstein }
16225c3f70d7SAlfred Perlstein 
16235c3f70d7SAlfred Perlstein /*
1624df8bae1dSRodney W. Grimes  * Free a cred structure.
1625df8bae1dSRodney W. Grimes  * Throws away space when ref count gets to 0.
1626df8bae1dSRodney W. Grimes  */
162726f9a767SRodney W. Grimes void
16284c44ad8eSJohn Baldwin crfree(struct ucred *cr)
1629df8bae1dSRodney W. Grimes {
1630e1bca29fSMatthew Dillon 	struct mtx *mtxp = cr->cr_mtxp;
16311e5d626aSAlfred Perlstein 
1632e1bca29fSMatthew Dillon 	mtx_lock(mtxp);
1633e04670b7SAlfred Perlstein 	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1634f535380cSDon Lewis 	if (--cr->cr_ref == 0) {
1635f535380cSDon Lewis 		/*
1636f535380cSDon Lewis 		 * Some callers of crget(), such as nfs_statfs(),
1637f535380cSDon Lewis 		 * allocate a temporary credential, but don't
1638f535380cSDon Lewis 		 * allocate a uidinfo structure.
1639f535380cSDon Lewis 		 */
1640e1bca29fSMatthew Dillon 		mtx_unlock(mtxp);
1641c1a513c9SJohn Baldwin 		mtx_lock(&Giant);
1642f535380cSDon Lewis 		if (cr->cr_uidinfo != NULL)
1643f535380cSDon Lewis 			uifree(cr->cr_uidinfo);
1644823c224eSRobert Watson 		if (cr->cr_ruidinfo != NULL)
1645823c224eSRobert Watson 			uifree(cr->cr_ruidinfo);
164691421ba2SRobert Watson 		/*
164791421ba2SRobert Watson 		 * Free a prison, if any.
164891421ba2SRobert Watson 		 */
164991421ba2SRobert Watson 		if (jailed(cr))
165091421ba2SRobert Watson 			prison_free(cr->cr_prison);
1651df8bae1dSRodney W. Grimes 		FREE((caddr_t)cr, M_CRED);
1652c1a513c9SJohn Baldwin 		mtx_unlock(&Giant);
1653e1bca29fSMatthew Dillon 	} else {
1654e1bca29fSMatthew Dillon 		mtx_unlock(mtxp);
1655e1bca29fSMatthew Dillon 	}
1656df8bae1dSRodney W. Grimes }
1657df8bae1dSRodney W. Grimes 
1658df8bae1dSRodney W. Grimes /*
1659bd78ceceSJohn Baldwin  * Check to see if this ucred is shared.
1660df8bae1dSRodney W. Grimes  */
1661bd78ceceSJohn Baldwin int
16624c44ad8eSJohn Baldwin crshared(struct ucred *cr)
1663df8bae1dSRodney W. Grimes {
1664bd78ceceSJohn Baldwin 	int shared;
1665df8bae1dSRodney W. Grimes 
1666e1bca29fSMatthew Dillon 	mtx_lock(cr->cr_mtxp);
1667bd78ceceSJohn Baldwin 	shared = (cr->cr_ref > 1);
1668e1bca29fSMatthew Dillon 	mtx_unlock(cr->cr_mtxp);
1669bd78ceceSJohn Baldwin 	return (shared);
16701e5d626aSAlfred Perlstein }
1671bd78ceceSJohn Baldwin 
1672bd78ceceSJohn Baldwin /*
1673bd78ceceSJohn Baldwin  * Copy a ucred's contents from a template.  Does not block.
1674bd78ceceSJohn Baldwin  */
1675bd78ceceSJohn Baldwin void
16764c44ad8eSJohn Baldwin crcopy(struct ucred *dest, struct ucred *src)
1677bd78ceceSJohn Baldwin {
1678bd78ceceSJohn Baldwin 
1679bd78ceceSJohn Baldwin 	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
1680bd78ceceSJohn Baldwin 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
1681bd78ceceSJohn Baldwin 	    (unsigned)((caddr_t)&src->cr_endcopy -
1682bd78ceceSJohn Baldwin 		(caddr_t)&src->cr_startcopy));
1683bd78ceceSJohn Baldwin 	uihold(dest->cr_uidinfo);
1684bd78ceceSJohn Baldwin 	uihold(dest->cr_ruidinfo);
1685bd78ceceSJohn Baldwin 	if (jailed(dest))
1686bd78ceceSJohn Baldwin 		prison_hold(dest->cr_prison);
1687df8bae1dSRodney W. Grimes }
1688df8bae1dSRodney W. Grimes 
1689df8bae1dSRodney W. Grimes /*
1690df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
1691df8bae1dSRodney W. Grimes  */
1692df8bae1dSRodney W. Grimes struct ucred *
16934c44ad8eSJohn Baldwin crdup(struct ucred *cr)
1694df8bae1dSRodney W. Grimes {
1695df8bae1dSRodney W. Grimes 	struct ucred *newcr;
1696df8bae1dSRodney W. Grimes 
1697bd78ceceSJohn Baldwin 	newcr = crget();
1698bd78ceceSJohn Baldwin 	crcopy(newcr, cr);
1699df8bae1dSRodney W. Grimes 	return (newcr);
1700df8bae1dSRodney W. Grimes }
1701df8bae1dSRodney W. Grimes 
1702c1a513c9SJohn Baldwin #ifdef DIAGNOSTIC
1703c1a513c9SJohn Baldwin void
1704c1a513c9SJohn Baldwin cred_free_thread(struct thread *td)
1705c1a513c9SJohn Baldwin {
1706c1a513c9SJohn Baldwin 	struct ucred *cred;
1707c1a513c9SJohn Baldwin 
1708c1a513c9SJohn Baldwin 	cred = td->td_ucred;
1709c1a513c9SJohn Baldwin 	td->td_ucred = NULL;
1710c1a513c9SJohn Baldwin 	if (cred != NULL)
1711c1a513c9SJohn Baldwin 		crfree(cred);
1712c1a513c9SJohn Baldwin }
1713c1a513c9SJohn Baldwin #endif
1714c1a513c9SJohn Baldwin 
1715df8bae1dSRodney W. Grimes /*
171676183f34SDima Dorfman  * Fill in a struct xucred based on a struct ucred.
171776183f34SDima Dorfman  */
171876183f34SDima Dorfman void
17194c44ad8eSJohn Baldwin cru2x(struct ucred *cr, struct xucred *xcr)
172076183f34SDima Dorfman {
172176183f34SDima Dorfman 
172276183f34SDima Dorfman 	bzero(xcr, sizeof(*xcr));
172376183f34SDima Dorfman 	xcr->cr_version = XUCRED_VERSION;
172476183f34SDima Dorfman 	xcr->cr_uid = cr->cr_uid;
172576183f34SDima Dorfman 	xcr->cr_ngroups = cr->cr_ngroups;
172676183f34SDima Dorfman 	bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
172776183f34SDima Dorfman }
172876183f34SDima Dorfman 
172976183f34SDima Dorfman /*
17302eb927e2SJulian Elischer  * small routine to swap a thread's current ucred for the correct one
17312eb927e2SJulian Elischer  * taken from the process.
17322eb927e2SJulian Elischer  */
17332eb927e2SJulian Elischer void
17342eb927e2SJulian Elischer cred_update_thread(struct thread *td)
17352eb927e2SJulian Elischer {
17362eb927e2SJulian Elischer 	struct proc *p;
173765e3406dSJohn Baldwin 	struct ucred *cred;
17382eb927e2SJulian Elischer 
17392eb927e2SJulian Elischer 	p = td->td_proc;
174065e3406dSJohn Baldwin 	cred = td->td_ucred;
17412eb927e2SJulian Elischer 	mtx_lock(&Giant);
17422eb927e2SJulian Elischer 	PROC_LOCK(p);
17432eb927e2SJulian Elischer 	td->td_ucred = crhold(p->p_ucred);
17442eb927e2SJulian Elischer 	PROC_UNLOCK(p);
174565e3406dSJohn Baldwin 	if (cred != NULL)
174665e3406dSJohn Baldwin 		crfree(cred);
174765e3406dSJohn Baldwin 	mtx_unlock(&Giant);
17482eb927e2SJulian Elischer }
17492eb927e2SJulian Elischer 
17502eb927e2SJulian Elischer /*
1751df8bae1dSRodney W. Grimes  * Get login name, if available.
1752df8bae1dSRodney W. Grimes  */
1753d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1754df8bae1dSRodney W. Grimes struct getlogin_args {
1755df8bae1dSRodney W. Grimes 	char	*namebuf;
1756df8bae1dSRodney W. Grimes 	u_int	namelen;
1757df8bae1dSRodney W. Grimes };
1758d2d3e875SBruce Evans #endif
1759835a82eeSMatthew Dillon /*
1760835a82eeSMatthew Dillon  * MPSAFE
1761835a82eeSMatthew Dillon  */
1762df8bae1dSRodney W. Grimes /* ARGSUSED */
176326f9a767SRodney W. Grimes int
17644c44ad8eSJohn Baldwin getlogin(struct thread *td, struct getlogin_args *uap)
1765df8bae1dSRodney W. Grimes {
1766835a82eeSMatthew Dillon 	int error;
1767f591779bSSeigo Tanimura 	char login[MAXLOGNAME];
1768b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1769df8bae1dSRodney W. Grimes 
1770835a82eeSMatthew Dillon 	mtx_lock(&Giant);
177130cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
177253490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
1773f591779bSSeigo Tanimura 	PROC_LOCK(p);
1774f591779bSSeigo Tanimura 	SESS_LOCK(p->p_session);
1775f591779bSSeigo Tanimura 	bcopy(p->p_session->s_login, login, uap->namelen);
1776f591779bSSeigo Tanimura 	SESS_UNLOCK(p->p_session);
1777f591779bSSeigo Tanimura 	PROC_UNLOCK(p);
1778f591779bSSeigo Tanimura 	error = copyout((caddr_t) login, (caddr_t) uap->namebuf, uap->namelen);
1779835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1780835a82eeSMatthew Dillon 	return(error);
1781df8bae1dSRodney W. Grimes }
1782df8bae1dSRodney W. Grimes 
1783df8bae1dSRodney W. Grimes /*
1784df8bae1dSRodney W. Grimes  * Set login name.
1785df8bae1dSRodney W. Grimes  */
1786d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1787df8bae1dSRodney W. Grimes struct setlogin_args {
1788df8bae1dSRodney W. Grimes 	char	*namebuf;
1789df8bae1dSRodney W. Grimes };
1790d2d3e875SBruce Evans #endif
1791835a82eeSMatthew Dillon /*
1792835a82eeSMatthew Dillon  * MPSAFE
1793835a82eeSMatthew Dillon  */
1794df8bae1dSRodney W. Grimes /* ARGSUSED */
179526f9a767SRodney W. Grimes int
17964c44ad8eSJohn Baldwin setlogin(struct thread *td, struct setlogin_args *uap)
1797df8bae1dSRodney W. Grimes {
1798b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1799df8bae1dSRodney W. Grimes 	int error;
1800964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
1801df8bae1dSRodney W. Grimes 
1802835a82eeSMatthew Dillon 	mtx_lock(&Giant);
180344731cabSJohn Baldwin 	if ((error = suser_cred(td->td_ucred, PRISON_ROOT)) != 0)
1804835a82eeSMatthew Dillon 		goto done2;
1805184989c2SDavid Nugent 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
180610d4743fSDoug Rabson 	    sizeof(logintmp), (size_t *)0);
1807eb725b4eSRobert Watson 	if (error == ENAMETOOLONG)
1808df8bae1dSRodney W. Grimes 		error = EINVAL;
1809f591779bSSeigo Tanimura 	else if (!error) {
1810f591779bSSeigo Tanimura 		PROC_LOCK(p);
1811f591779bSSeigo Tanimura 		SESS_LOCK(p->p_session);
1812f591779bSSeigo Tanimura 		(void) memcpy(p->p_session->s_login, logintmp,
1813964ca0caSAndrey A. Chernov 		    sizeof(logintmp));
1814f591779bSSeigo Tanimura 		SESS_UNLOCK(p->p_session);
1815f591779bSSeigo Tanimura 		PROC_UNLOCK(p);
1816f591779bSSeigo Tanimura 	}
1817835a82eeSMatthew Dillon done2:
1818835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1819df8bae1dSRodney W. Grimes 	return (error);
1820df8bae1dSRodney W. Grimes }
1821d5f81602SSean Eric Fagan 
1822d5f81602SSean Eric Fagan void
18234c44ad8eSJohn Baldwin setsugid(struct proc *p)
1824d5f81602SSean Eric Fagan {
1825d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
182689361835SSean Eric Fagan 	if (!(p->p_pfsflags & PF_ISUGID))
1827d5f81602SSean Eric Fagan 		p->p_stops = 0;
1828d5f81602SSean Eric Fagan }
1829f535380cSDon Lewis 
18307fd6a959SRobert Watson /*-
18317fd6a959SRobert Watson  * Change a process's effective uid.
1832b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
1833b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1834b1fc0ec1SRobert Watson  *             duration of the call.
1835f535380cSDon Lewis  */
1836f535380cSDon Lewis void
18374c44ad8eSJohn Baldwin change_euid(struct ucred *newcred, uid_t euid)
1838f535380cSDon Lewis {
1839f535380cSDon Lewis 
1840b1fc0ec1SRobert Watson 	newcred->cr_uid = euid;
1841b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
1842b1fc0ec1SRobert Watson 	newcred->cr_uidinfo = uifind(euid);
1843f535380cSDon Lewis }
1844f535380cSDon Lewis 
18457fd6a959SRobert Watson /*-
18467fd6a959SRobert Watson  * Change a process's effective gid.
1847b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
1848b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1849b1fc0ec1SRobert Watson  *             duration of the call.
1850f535380cSDon Lewis  */
1851810bfc8eSAndrew Gallatin void
18524c44ad8eSJohn Baldwin change_egid(struct ucred *newcred, gid_t egid)
1853b1fc0ec1SRobert Watson {
1854b1fc0ec1SRobert Watson 
1855b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
1856b1fc0ec1SRobert Watson }
1857b1fc0ec1SRobert Watson 
18587fd6a959SRobert Watson /*-
18597fd6a959SRobert Watson  * Change a process's real uid.
1860b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
1861b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
1862b1fc0ec1SRobert Watson  *               counts will be updated.
1863b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1864b1fc0ec1SRobert Watson  *             duration of the call.
1865b1fc0ec1SRobert Watson  */
1866b1fc0ec1SRobert Watson void
18674c44ad8eSJohn Baldwin change_ruid(struct ucred *newcred, uid_t ruid)
1868f535380cSDon Lewis {
1869f535380cSDon Lewis 
1870b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
1871b1fc0ec1SRobert Watson 	newcred->cr_ruid = ruid;
1872b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
1873b1fc0ec1SRobert Watson 	newcred->cr_ruidinfo = uifind(ruid);
1874b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
1875b1fc0ec1SRobert Watson }
1876b1fc0ec1SRobert Watson 
18777fd6a959SRobert Watson /*-
18787fd6a959SRobert Watson  * Change a process's real gid.
1879b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
1880b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1881b1fc0ec1SRobert Watson  *             duration of the call.
1882b1fc0ec1SRobert Watson  */
1883b1fc0ec1SRobert Watson void
18844c44ad8eSJohn Baldwin change_rgid(struct ucred *newcred, gid_t rgid)
1885b1fc0ec1SRobert Watson {
1886b1fc0ec1SRobert Watson 
1887b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
1888b1fc0ec1SRobert Watson }
1889b1fc0ec1SRobert Watson 
18907fd6a959SRobert Watson /*-
18917fd6a959SRobert Watson  * Change a process's saved uid.
1892b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
1893b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1894b1fc0ec1SRobert Watson  *             duration of the call.
1895b1fc0ec1SRobert Watson  */
1896b1fc0ec1SRobert Watson void
18974c44ad8eSJohn Baldwin change_svuid(struct ucred *newcred, uid_t svuid)
1898b1fc0ec1SRobert Watson {
1899b1fc0ec1SRobert Watson 
1900b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
1901b1fc0ec1SRobert Watson }
1902b1fc0ec1SRobert Watson 
19037fd6a959SRobert Watson /*-
19047fd6a959SRobert Watson  * Change a process's saved gid.
1905b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
1906b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1907b1fc0ec1SRobert Watson  *             duration of the call.
1908b1fc0ec1SRobert Watson  */
1909b1fc0ec1SRobert Watson void
19104c44ad8eSJohn Baldwin change_svgid(struct ucred *newcred, gid_t svgid)
1911b1fc0ec1SRobert Watson {
1912b1fc0ec1SRobert Watson 
1913b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
1914f535380cSDon Lewis }
1915