xref: /freebsd/sys/kern/kern_prot.c (revision 5b29d6e9065503829735e5d07a827ef64743c929)
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.
4db42a33dSRobert Watson  * Copyright (c) 2000-2001 Robert N. M. Watson.  All rights reserved.
5df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
6db42a33dSRobert Watson  *
7df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
8df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
9df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
11df8bae1dSRodney W. Grimes  *
12df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
13df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
14df8bae1dSRodney W. Grimes  * are met:
15df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
16df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
17df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
18df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
19df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
20df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
21df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
22df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
23df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
24df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
25df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
26df8bae1dSRodney W. Grimes  *    without specific prior written permission.
27df8bae1dSRodney W. Grimes  *
28df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
39df8bae1dSRodney W. Grimes  *
40df8bae1dSRodney W. Grimes  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
41c3aac50fSPeter Wemm  * $FreeBSD$
42df8bae1dSRodney W. Grimes  */
43df8bae1dSRodney W. Grimes 
44df8bae1dSRodney W. Grimes /*
45df8bae1dSRodney W. Grimes  * System calls related to processes and protection
46df8bae1dSRodney W. Grimes  */
47df8bae1dSRodney W. Grimes 
485591b823SEivind Eklund #include "opt_compat.h"
49130d0157SRobert Watson #include "opt_global.h"
505591b823SEivind Eklund 
51df8bae1dSRodney W. Grimes #include <sys/param.h>
52df8bae1dSRodney W. Grimes #include <sys/systm.h>
53fb919e4dSMark Murray #include <sys/acct.h>
541c5bb3eaSPeter Wemm #include <sys/kernel.h>
5598f03f90SJake Burkholder #include <sys/lock.h>
56fb919e4dSMark Murray #include <sys/mutex.h>
57df8bae1dSRodney W. Grimes #include <sys/proc.h>
585b29d6e9SJohn Baldwin #include <sys/sx.h>
59fb919e4dSMark Murray #include <sys/sysproto.h>
60df8bae1dSRodney W. Grimes #include <sys/malloc.h>
61d5f81602SSean Eric Fagan #include <sys/pioctl.h>
62f535380cSDon Lewis #include <sys/resourcevar.h>
63579f4eb4SRobert Watson #include <sys/sysctl.h>
6491421ba2SRobert Watson #include <sys/jail.h>
65df8bae1dSRodney W. Grimes 
66a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
67a1c995b6SPoul-Henning Kamp 
680ef5652eSRobert Watson SYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0,
690ef5652eSRobert Watson     "Kernel security policy");
700ef5652eSRobert Watson 
71d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
72ad7507e2SSteven Wallace struct getpid_args {
73df8bae1dSRodney W. Grimes 	int	dummy;
74df8bae1dSRodney W. Grimes };
75d2d3e875SBruce Evans #endif
76df8bae1dSRodney W. Grimes 
7736e9f877SMatthew Dillon /*
78835a82eeSMatthew Dillon  * getpid
7936e9f877SMatthew Dillon  */
8098f03f90SJake Burkholder 
81835a82eeSMatthew Dillon /*
82835a82eeSMatthew Dillon  * MPSAFE
83835a82eeSMatthew Dillon  */
84df8bae1dSRodney W. Grimes /* ARGSUSED */
8526f9a767SRodney W. Grimes int
86b40ce416SJulian Elischer getpid(td, uap)
87b40ce416SJulian Elischer 	struct thread *td;
88ad7507e2SSteven Wallace 	struct getpid_args *uap;
89df8bae1dSRodney W. Grimes {
90b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
91d23f5958SMatthew Dillon 	int s;
92df8bae1dSRodney W. Grimes 
93d23f5958SMatthew Dillon 	s = mtx_lock_giant(kern_giant_proc);
94b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pid;
95df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
96bae3a80bSJohn Baldwin 	PROC_LOCK(p);
97b40ce416SJulian Elischer 	td->td_retval[1] = p->p_pptr->p_pid;
98bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
99df8bae1dSRodney W. Grimes #endif
100d23f5958SMatthew Dillon 	mtx_unlock_giant(s);
101df8bae1dSRodney W. Grimes 	return (0);
102df8bae1dSRodney W. Grimes }
103df8bae1dSRodney W. Grimes 
10498f03f90SJake Burkholder /*
105835a82eeSMatthew Dillon  * getppid
10698f03f90SJake Burkholder  */
10798f03f90SJake Burkholder 
108d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
109ad7507e2SSteven Wallace struct getppid_args {
110ad7507e2SSteven Wallace         int     dummy;
111ad7507e2SSteven Wallace };
112d2d3e875SBruce Evans #endif
113835a82eeSMatthew Dillon /*
114835a82eeSMatthew Dillon  * MPSAFE
115835a82eeSMatthew Dillon  */
116df8bae1dSRodney W. Grimes /* ARGSUSED */
11726f9a767SRodney W. Grimes int
118b40ce416SJulian Elischer getppid(td, uap)
119b40ce416SJulian Elischer 	struct thread *td;
120ad7507e2SSteven Wallace 	struct getppid_args *uap;
121df8bae1dSRodney W. Grimes {
122b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
123d23f5958SMatthew Dillon 	int s;
124df8bae1dSRodney W. Grimes 
125d23f5958SMatthew Dillon 	s = mtx_lock_giant(kern_giant_proc);
126bae3a80bSJohn Baldwin 	PROC_LOCK(p);
127b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pptr->p_pid;
128bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
129d23f5958SMatthew Dillon 	mtx_unlock_giant(s);
130df8bae1dSRodney W. Grimes 	return (0);
131df8bae1dSRodney W. Grimes }
132df8bae1dSRodney W. Grimes 
13336e9f877SMatthew Dillon /*
13436e9f877SMatthew Dillon  * Get process group ID; note that POSIX getpgrp takes no parameter
13536e9f877SMatthew Dillon  *
13636e9f877SMatthew Dillon  * MP SAFE
13736e9f877SMatthew Dillon  */
138d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
139ad7507e2SSteven Wallace struct getpgrp_args {
140ad7507e2SSteven Wallace         int     dummy;
141ad7507e2SSteven Wallace };
142d2d3e875SBruce Evans #endif
143835a82eeSMatthew Dillon /*
144835a82eeSMatthew Dillon  * MPSAFE
145835a82eeSMatthew Dillon  */
14626f9a767SRodney W. Grimes int
147b40ce416SJulian Elischer getpgrp(td, uap)
148b40ce416SJulian Elischer 	struct thread *td;
149ad7507e2SSteven Wallace 	struct getpgrp_args *uap;
150df8bae1dSRodney W. Grimes {
151b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
152df8bae1dSRodney W. Grimes 
153835a82eeSMatthew Dillon 	mtx_lock(&Giant);
154b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
155835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
156df8bae1dSRodney W. Grimes 	return (0);
157df8bae1dSRodney W. Grimes }
158df8bae1dSRodney W. Grimes 
1591a5018a0SPeter Wemm /* Get an arbitary pid's process group id */
1601a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1611a5018a0SPeter Wemm struct getpgid_args {
1621a5018a0SPeter Wemm 	pid_t	pid;
1631a5018a0SPeter Wemm };
1641a5018a0SPeter Wemm #endif
1651a5018a0SPeter Wemm 
166835a82eeSMatthew Dillon /*
167835a82eeSMatthew Dillon  * MPSAFE
168835a82eeSMatthew Dillon  */
1691a5018a0SPeter Wemm int
170b40ce416SJulian Elischer getpgid(td, uap)
171b40ce416SJulian Elischer 	struct thread *td;
1721a5018a0SPeter Wemm 	struct getpgid_args *uap;
1731a5018a0SPeter Wemm {
174b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
17565de0c7aSDon Lewis 	struct proc *pt;
176835a82eeSMatthew Dillon 	int error = 0;
177d23f5958SMatthew Dillon 	int s;
17865de0c7aSDon Lewis 
179d23f5958SMatthew Dillon 	s = mtx_lock_giant(kern_giant_proc);
1801a5018a0SPeter Wemm 	if (uap->pid == 0)
181b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pgrp->pg_id;
1826a90c862SJohn Baldwin 	else if ((pt = pfind(uap->pid)) == NULL)
183835a82eeSMatthew Dillon 		error = ESRCH;
1846a90c862SJohn Baldwin 	else {
1856a90c862SJohn Baldwin 		error = p_cansee(p, pt);
1866a90c862SJohn Baldwin 		if (error == 0)
187b40ce416SJulian Elischer 			td->td_retval[0] = pt->p_pgrp->pg_id;
18833a9ed9dSJohn Baldwin 		PROC_UNLOCK(pt);
18933a9ed9dSJohn Baldwin 	}
190d23f5958SMatthew Dillon 	mtx_unlock_giant(s);
191835a82eeSMatthew Dillon 	return (error);
1921a5018a0SPeter Wemm }
1931a5018a0SPeter Wemm 
1941a5018a0SPeter Wemm /*
1951a5018a0SPeter Wemm  * Get an arbitary pid's session id.
1961a5018a0SPeter Wemm  */
1971a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1981a5018a0SPeter Wemm struct getsid_args {
1991a5018a0SPeter Wemm 	pid_t	pid;
2001a5018a0SPeter Wemm };
2011a5018a0SPeter Wemm #endif
2021a5018a0SPeter Wemm 
203835a82eeSMatthew Dillon /*
204835a82eeSMatthew Dillon  * MPSAFE
205835a82eeSMatthew Dillon  */
2061a5018a0SPeter Wemm int
207b40ce416SJulian Elischer getsid(td, uap)
208b40ce416SJulian Elischer 	struct thread *td;
2091a5018a0SPeter Wemm 	struct getsid_args *uap;
2101a5018a0SPeter Wemm {
211b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
21265de0c7aSDon Lewis 	struct proc *pt;
213835a82eeSMatthew Dillon 	int error = 0;
21465de0c7aSDon Lewis 
215835a82eeSMatthew Dillon 	mtx_lock(&Giant);
2166a90c862SJohn Baldwin 	if (uap->pid == 0)
217b40ce416SJulian Elischer 		td->td_retval[0] = p->p_session->s_sid;
2186a90c862SJohn Baldwin 	else if ((pt = pfind(uap->pid)) == NULL)
219835a82eeSMatthew Dillon 		error = ESRCH;
2206a90c862SJohn Baldwin 	else {
2216a90c862SJohn Baldwin 		error = p_cansee(p, pt);
2226a90c862SJohn Baldwin 		if (error == 0)
223b40ce416SJulian Elischer 			td->td_retval[0] = pt->p_session->s_sid;
22433a9ed9dSJohn Baldwin 		PROC_UNLOCK(pt);
22533a9ed9dSJohn Baldwin 	}
226835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
227835a82eeSMatthew Dillon 	return (error);
2281a5018a0SPeter Wemm }
2291a5018a0SPeter Wemm 
2301a5018a0SPeter Wemm 
2317c8fdcbdSMatthew Dillon /*
2327c8fdcbdSMatthew Dillon  * getuid() - MP SAFE
2337c8fdcbdSMatthew Dillon  */
234d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
235ad7507e2SSteven Wallace struct getuid_args {
236ad7507e2SSteven Wallace         int     dummy;
237ad7507e2SSteven Wallace };
238d2d3e875SBruce Evans #endif
239ad7507e2SSteven Wallace 
240835a82eeSMatthew Dillon /*
241835a82eeSMatthew Dillon  * MPSAFE
242835a82eeSMatthew Dillon  */
243df8bae1dSRodney W. Grimes /* ARGSUSED */
24426f9a767SRodney W. Grimes int
245b40ce416SJulian Elischer getuid(td, uap)
246b40ce416SJulian Elischer 	struct thread *td;
247ad7507e2SSteven Wallace 	struct getuid_args *uap;
248df8bae1dSRodney W. Grimes {
249b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
250df8bae1dSRodney W. Grimes 
251835a82eeSMatthew Dillon 	mtx_lock(&Giant);
252b40ce416SJulian Elischer 	td->td_retval[0] = p->p_ucred->cr_ruid;
253df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
254b40ce416SJulian Elischer 	td->td_retval[1] = p->p_ucred->cr_uid;
255df8bae1dSRodney W. Grimes #endif
256835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
257df8bae1dSRodney W. Grimes 	return (0);
258df8bae1dSRodney W. Grimes }
259df8bae1dSRodney W. Grimes 
2607c8fdcbdSMatthew Dillon /*
2617c8fdcbdSMatthew Dillon  * geteuid() - MP SAFE
2627c8fdcbdSMatthew Dillon  */
263d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
264ad7507e2SSteven Wallace struct geteuid_args {
265ad7507e2SSteven Wallace         int     dummy;
266ad7507e2SSteven Wallace };
267d2d3e875SBruce Evans #endif
268ad7507e2SSteven Wallace 
269df8bae1dSRodney W. Grimes /* ARGSUSED */
27026f9a767SRodney W. Grimes int
271b40ce416SJulian Elischer geteuid(td, uap)
272b40ce416SJulian Elischer 	struct thread *td;
273ad7507e2SSteven Wallace 	struct geteuid_args *uap;
274df8bae1dSRodney W. Grimes {
275835a82eeSMatthew Dillon 	mtx_lock(&Giant);
276b40ce416SJulian Elischer 	td->td_retval[0] = td->td_proc->p_ucred->cr_uid;
277835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
278df8bae1dSRodney W. Grimes 	return (0);
279df8bae1dSRodney W. Grimes }
280df8bae1dSRodney W. Grimes 
2817c8fdcbdSMatthew Dillon /*
2827c8fdcbdSMatthew Dillon  * getgid() - MP SAFE
2837c8fdcbdSMatthew Dillon  */
284d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
285ad7507e2SSteven Wallace struct getgid_args {
286ad7507e2SSteven Wallace         int     dummy;
287ad7507e2SSteven Wallace };
288d2d3e875SBruce Evans #endif
289ad7507e2SSteven Wallace 
290835a82eeSMatthew Dillon /*
291835a82eeSMatthew Dillon  * MPSAFE
292835a82eeSMatthew Dillon  */
293df8bae1dSRodney W. Grimes /* ARGSUSED */
29426f9a767SRodney W. Grimes int
295b40ce416SJulian Elischer getgid(td, uap)
296b40ce416SJulian Elischer 	struct thread *td;
297ad7507e2SSteven Wallace 	struct getgid_args *uap;
298df8bae1dSRodney W. Grimes {
299b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
300df8bae1dSRodney W. Grimes 
301835a82eeSMatthew Dillon 	mtx_lock(&Giant);
302b40ce416SJulian Elischer 	td->td_retval[0] = p->p_ucred->cr_rgid;
303df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
304b40ce416SJulian Elischer 	td->td_retval[1] = p->p_ucred->cr_groups[0];
305df8bae1dSRodney W. Grimes #endif
306835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
307df8bae1dSRodney W. Grimes 	return (0);
308df8bae1dSRodney W. Grimes }
309df8bae1dSRodney W. Grimes 
310df8bae1dSRodney W. Grimes /*
311df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
312df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
313df8bae1dSRodney W. Grimes  * correctly in a library function.
314df8bae1dSRodney W. Grimes  */
315d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
316ad7507e2SSteven Wallace struct getegid_args {
317ad7507e2SSteven Wallace         int     dummy;
318ad7507e2SSteven Wallace };
319d2d3e875SBruce Evans #endif
320ad7507e2SSteven Wallace 
321835a82eeSMatthew Dillon /*
322835a82eeSMatthew Dillon  * MPSAFE
323835a82eeSMatthew Dillon  */
324df8bae1dSRodney W. Grimes /* ARGSUSED */
32526f9a767SRodney W. Grimes int
326b40ce416SJulian Elischer getegid(td, uap)
327b40ce416SJulian Elischer 	struct thread *td;
328ad7507e2SSteven Wallace 	struct getegid_args *uap;
329df8bae1dSRodney W. Grimes {
330b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
331df8bae1dSRodney W. Grimes 
332835a82eeSMatthew Dillon 	mtx_lock(&Giant);
333b40ce416SJulian Elischer 	td->td_retval[0] = p->p_ucred->cr_groups[0];
334835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
335df8bae1dSRodney W. Grimes 	return (0);
336df8bae1dSRodney W. Grimes }
337df8bae1dSRodney W. Grimes 
338d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
339df8bae1dSRodney W. Grimes struct getgroups_args {
340df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
341df8bae1dSRodney W. Grimes 	gid_t	*gidset;
342df8bae1dSRodney W. Grimes };
343d2d3e875SBruce Evans #endif
344835a82eeSMatthew Dillon /*
345835a82eeSMatthew Dillon  * MPSAFE
346835a82eeSMatthew Dillon  */
34726f9a767SRodney W. Grimes int
348b40ce416SJulian Elischer getgroups(td, uap)
349b40ce416SJulian Elischer 	struct thread *td;
350df8bae1dSRodney W. Grimes 	register struct	getgroups_args *uap;
351df8bae1dSRodney W. Grimes {
352835a82eeSMatthew Dillon 	struct ucred *cred;
353b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
354b1fc0ec1SRobert Watson 	u_int ngrp;
355835a82eeSMatthew Dillon 	int error = 0;
356df8bae1dSRodney W. Grimes 
357835a82eeSMatthew Dillon 	mtx_lock(&Giant);
358835a82eeSMatthew Dillon 	cred = p->p_ucred;
359df8bae1dSRodney W. Grimes 	if ((ngrp = uap->gidsetsize) == 0) {
360b40ce416SJulian Elischer 		td->td_retval[0] = cred->cr_ngroups;
361835a82eeSMatthew Dillon 		error = 0;
362835a82eeSMatthew Dillon 		goto done2;
363df8bae1dSRodney W. Grimes 	}
364835a82eeSMatthew Dillon 	if (ngrp < cred->cr_ngroups) {
365835a82eeSMatthew Dillon 		error = EINVAL;
366835a82eeSMatthew Dillon 		goto done2;
367835a82eeSMatthew Dillon 	}
368b1fc0ec1SRobert Watson 	ngrp = cred->cr_ngroups;
369b1fc0ec1SRobert Watson 	if ((error = copyout((caddr_t)cred->cr_groups,
370835a82eeSMatthew Dillon 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) {
371835a82eeSMatthew Dillon 		goto done2;
372835a82eeSMatthew Dillon 	}
373b40ce416SJulian Elischer 	td->td_retval[0] = ngrp;
374835a82eeSMatthew Dillon done2:
375835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
376835a82eeSMatthew Dillon 	return (error);
377df8bae1dSRodney W. Grimes }
378df8bae1dSRodney W. Grimes 
379d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
38082970b81SBruce Evans struct setsid_args {
381ad7507e2SSteven Wallace         int     dummy;
382ad7507e2SSteven Wallace };
383d2d3e875SBruce Evans #endif
384ad7507e2SSteven Wallace 
385835a82eeSMatthew Dillon /*
386835a82eeSMatthew Dillon  * MPSAFE
387835a82eeSMatthew Dillon  */
388df8bae1dSRodney W. Grimes /* ARGSUSED */
38926f9a767SRodney W. Grimes int
390b40ce416SJulian Elischer setsid(td, uap)
391b40ce416SJulian Elischer 	register struct thread *td;
39282970b81SBruce Evans 	struct setsid_args *uap;
393df8bae1dSRodney W. Grimes {
394835a82eeSMatthew Dillon 	int error;
395b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
396df8bae1dSRodney W. Grimes 
397835a82eeSMatthew Dillon 	mtx_lock(&Giant);
398df8bae1dSRodney W. Grimes 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
399835a82eeSMatthew Dillon 		error = EPERM;
400df8bae1dSRodney W. Grimes 	} else {
401df8bae1dSRodney W. Grimes 		(void)enterpgrp(p, p->p_pid, 1);
402b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
403835a82eeSMatthew Dillon 		error = 0;
404df8bae1dSRodney W. Grimes 	}
405835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
406835a82eeSMatthew Dillon 	return (error);
407df8bae1dSRodney W. Grimes }
408df8bae1dSRodney W. Grimes 
409df8bae1dSRodney W. Grimes /*
410df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
411df8bae1dSRodney W. Grimes  *
412df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
413df8bae1dSRodney W. Grimes  *
414df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
415df8bae1dSRodney W. Grimes  * if a child
416df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
417df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
418df8bae1dSRodney W. Grimes  * if pgid != pid
419df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
420df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
421df8bae1dSRodney W. Grimes  */
422d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
423df8bae1dSRodney W. Grimes struct setpgid_args {
424df8bae1dSRodney W. Grimes 	int	pid;	/* target process id */
425df8bae1dSRodney W. Grimes 	int	pgid;	/* target pgrp id */
426df8bae1dSRodney W. Grimes };
427d2d3e875SBruce Evans #endif
428835a82eeSMatthew Dillon /*
429835a82eeSMatthew Dillon  * MPSAFE
430835a82eeSMatthew Dillon  */
431df8bae1dSRodney W. Grimes /* ARGSUSED */
43226f9a767SRodney W. Grimes int
433b40ce416SJulian Elischer setpgid(td, uap)
434b40ce416SJulian Elischer 	struct thread *td;
435df8bae1dSRodney W. Grimes 	register struct setpgid_args *uap;
436df8bae1dSRodney W. Grimes {
437b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
438df8bae1dSRodney W. Grimes 	register struct proc *targp;		/* target process */
439df8bae1dSRodney W. Grimes 	register struct pgrp *pgrp;		/* target pgrp */
440eb9e5c1dSRobert Watson 	int error;
441df8bae1dSRodney W. Grimes 
44278f64bccSBruce Evans 	if (uap->pgid < 0)
44378f64bccSBruce Evans 		return (EINVAL);
444835a82eeSMatthew Dillon 
445835a82eeSMatthew Dillon 	mtx_lock(&Giant);
446835a82eeSMatthew Dillon 
4475b29d6e9SJohn Baldwin 	sx_slock(&proctree_lock);
448df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
44933a9ed9dSJohn Baldwin 		if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
45033a9ed9dSJohn Baldwin 			if (targp)
45133a9ed9dSJohn Baldwin 				PROC_UNLOCK(targp);
452835a82eeSMatthew Dillon 			error = ESRCH;
453835a82eeSMatthew Dillon 			goto done2;
45433a9ed9dSJohn Baldwin 		}
455a0f75161SRobert Watson 		if ((error = p_cansee(curproc, targp))) {
45633a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
457835a82eeSMatthew Dillon 			goto done2;
45833a9ed9dSJohn Baldwin 		}
45933a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
46033a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
46133a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
462835a82eeSMatthew Dillon 			error = EPERM;
463835a82eeSMatthew Dillon 			goto done2;
46433a9ed9dSJohn Baldwin 		}
46533a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
46633a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
467835a82eeSMatthew Dillon 			error = EACCES;
468835a82eeSMatthew Dillon 			goto done2;
46933a9ed9dSJohn Baldwin 		}
47033a9ed9dSJohn Baldwin 	} else {
471df8bae1dSRodney W. Grimes 		targp = curp;
47233a9ed9dSJohn Baldwin 		PROC_LOCK(curp);	/* XXX: not needed */
47333a9ed9dSJohn Baldwin 	}
47433a9ed9dSJohn Baldwin 	if (SESS_LEADER(targp)) {
47533a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
476835a82eeSMatthew Dillon 		error = EPERM;
477835a82eeSMatthew Dillon 		goto done2;
47833a9ed9dSJohn Baldwin 	}
479835a82eeSMatthew Dillon 	if (uap->pgid == 0) {
480df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
481835a82eeSMatthew Dillon 	} else if (uap->pgid != targp->p_pid) {
482df8bae1dSRodney W. Grimes 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
48333a9ed9dSJohn Baldwin 	            pgrp->pg_session != curp->p_session) {
48433a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
485835a82eeSMatthew Dillon 			error = EPERM;
486835a82eeSMatthew Dillon 			goto done2;
487835a82eeSMatthew Dillon 		}
48833a9ed9dSJohn Baldwin 	}
48933a9ed9dSJohn Baldwin 	/* XXX: We should probably hold the lock across enterpgrp. */
49033a9ed9dSJohn Baldwin 	PROC_UNLOCK(targp);
491835a82eeSMatthew Dillon 	error = enterpgrp(targp, uap->pgid, 0);
492835a82eeSMatthew Dillon done2:
4935b29d6e9SJohn Baldwin 	sx_sunlock(&proctree_lock);
494835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
495835a82eeSMatthew Dillon 	return (error);
496df8bae1dSRodney W. Grimes }
497df8bae1dSRodney W. Grimes 
498a08f4bf6SPeter Wemm /*
499a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
5002fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
501a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
502a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
503a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
504a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
505a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
506a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
507a08f4bf6SPeter Wemm  */
508a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
509a08f4bf6SPeter Wemm 
510d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
511df8bae1dSRodney W. Grimes struct setuid_args {
512df8bae1dSRodney W. Grimes 	uid_t	uid;
513df8bae1dSRodney W. Grimes };
514d2d3e875SBruce Evans #endif
515835a82eeSMatthew Dillon /*
516835a82eeSMatthew Dillon  * MPSAFE
517835a82eeSMatthew Dillon  */
518df8bae1dSRodney W. Grimes /* ARGSUSED */
51926f9a767SRodney W. Grimes int
520b40ce416SJulian Elischer setuid(td, uap)
521b40ce416SJulian Elischer 	struct thread *td;
522df8bae1dSRodney W. Grimes 	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;
527835a82eeSMatthew Dillon 	int error = 0;
528df8bae1dSRodney W. Grimes 
529b1fc0ec1SRobert Watson 	uid = uap->uid;
530b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
531835a82eeSMatthew Dillon 	mtx_lock(&Giant);
532835a82eeSMatthew Dillon 
533a08f4bf6SPeter Wemm 	/*
534a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
535a08f4bf6SPeter Wemm 	 *
536a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
537a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5382fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
539a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
540a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
541a08f4bf6SPeter Wemm 	 *
542a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
543a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
544a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
545a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
546a08f4bf6SPeter Wemm 	 * 2: We determine if the real and/or saved uid's are going to
547a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
548a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
549a08f4bf6SPeter Wemm 	 */
550b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5513f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
552b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
553a08f4bf6SPeter Wemm #endif
554a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
555b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5563f246666SAndrey A. Chernov #endif
557b1fc0ec1SRobert Watson 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
558835a82eeSMatthew Dillon 		goto done2;
559a08f4bf6SPeter Wemm 
560b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
561a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
562df8bae1dSRodney W. Grimes 	/*
563a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
564a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
565df8bae1dSRodney W. Grimes 	 */
5663f246666SAndrey A. Chernov 	if (
567a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
568b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5693f246666SAndrey A. Chernov #endif
570b1fc0ec1SRobert Watson 	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
571a08f4bf6SPeter Wemm #endif
572a08f4bf6SPeter Wemm 	{
573a08f4bf6SPeter Wemm 		/*
574f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
575a08f4bf6SPeter Wemm 		 */
576b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
577b1fc0ec1SRobert Watson 			change_ruid(newcred, uid);
578f535380cSDon Lewis 			setsugid(p);
579d3cdb93dSAndrey A. Chernov 		}
580a08f4bf6SPeter Wemm 		/*
581a08f4bf6SPeter Wemm 		 * Set saved uid
582a08f4bf6SPeter Wemm 		 *
583a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
584a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
585a08f4bf6SPeter Wemm 		 * is important that we should do this.
586a08f4bf6SPeter Wemm 		 */
587b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
588b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
589d5f81602SSean Eric Fagan 			setsugid(p);
590a08f4bf6SPeter Wemm 		}
591a08f4bf6SPeter Wemm 	}
592a08f4bf6SPeter Wemm 
593a08f4bf6SPeter Wemm 	/*
594a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
595a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
596a08f4bf6SPeter Wemm 	 */
597b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
598b1fc0ec1SRobert Watson 		change_euid(newcred, uid);
599d5f81602SSean Eric Fagan 		setsugid(p);
600a08f4bf6SPeter Wemm 	}
601b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
602b1fc0ec1SRobert Watson 	crfree(oldcred);
603835a82eeSMatthew Dillon done2:
604835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
605835a82eeSMatthew Dillon 	return (error);
606df8bae1dSRodney W. Grimes }
607df8bae1dSRodney W. Grimes 
608d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
609df8bae1dSRodney W. Grimes struct seteuid_args {
610df8bae1dSRodney W. Grimes 	uid_t	euid;
611df8bae1dSRodney W. Grimes };
612d2d3e875SBruce Evans #endif
613835a82eeSMatthew Dillon /*
614835a82eeSMatthew Dillon  * MPSAFE
615835a82eeSMatthew Dillon  */
616df8bae1dSRodney W. Grimes /* ARGSUSED */
61726f9a767SRodney W. Grimes int
618b40ce416SJulian Elischer seteuid(td, uap)
619b40ce416SJulian Elischer 	struct thread *td;
620df8bae1dSRodney W. Grimes 	struct seteuid_args *uap;
621df8bae1dSRodney W. Grimes {
622b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
623b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
624b1fc0ec1SRobert Watson 	uid_t euid;
625835a82eeSMatthew Dillon 	int error = 0;
626df8bae1dSRodney W. Grimes 
627df8bae1dSRodney W. Grimes 	euid = uap->euid;
628835a82eeSMatthew Dillon 
629835a82eeSMatthew Dillon 	mtx_lock(&Giant);
630b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
631b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
632b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
633835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) {
634835a82eeSMatthew Dillon 		goto done2;
635835a82eeSMatthew Dillon 	}
636df8bae1dSRodney W. Grimes 	/*
637df8bae1dSRodney W. Grimes 	 * Everything's okay, do it.  Copy credentials so other references do
638df8bae1dSRodney W. Grimes 	 * not see our changes.
639df8bae1dSRodney W. Grimes 	 */
640b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
641b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
642b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
643d5f81602SSean Eric Fagan 		setsugid(p);
644229a15f0SPeter Wemm 	}
645b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
646b1fc0ec1SRobert Watson 	crfree(oldcred);
647835a82eeSMatthew Dillon done2:
648835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
649835a82eeSMatthew Dillon 	return (error);
650df8bae1dSRodney W. Grimes }
651df8bae1dSRodney W. Grimes 
652d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
653df8bae1dSRodney W. Grimes struct setgid_args {
654df8bae1dSRodney W. Grimes 	gid_t	gid;
655df8bae1dSRodney W. Grimes };
656d2d3e875SBruce Evans #endif
657835a82eeSMatthew Dillon /*
658835a82eeSMatthew Dillon  * MPSAFE
659835a82eeSMatthew Dillon  */
660df8bae1dSRodney W. Grimes /* ARGSUSED */
66126f9a767SRodney W. Grimes int
662b40ce416SJulian Elischer setgid(td, uap)
663b40ce416SJulian Elischer 	struct thread *td;
664df8bae1dSRodney W. Grimes 	struct setgid_args *uap;
665df8bae1dSRodney W. Grimes {
666b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
667b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
668b1fc0ec1SRobert Watson 	gid_t gid;
669835a82eeSMatthew Dillon 	int error = 0;
670df8bae1dSRodney W. Grimes 
671b1fc0ec1SRobert Watson 	gid = uap->gid;
672835a82eeSMatthew Dillon 
673835a82eeSMatthew Dillon 	mtx_lock(&Giant);
674b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
675a08f4bf6SPeter Wemm 	/*
676a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
677a08f4bf6SPeter Wemm 	 *
678a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
679a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
6802fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
681a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
682a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
683a08f4bf6SPeter Wemm 	 *
684a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
685a08f4bf6SPeter Wemm 	 */
686b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
6873f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
688b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
689a08f4bf6SPeter Wemm #endif
690a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
691b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
6923f246666SAndrey A. Chernov #endif
693835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) {
694835a82eeSMatthew Dillon 		goto done2;
695835a82eeSMatthew Dillon 	}
696a08f4bf6SPeter Wemm 
697b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
698a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
699a08f4bf6SPeter Wemm 	/*
700a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
701a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
702a08f4bf6SPeter Wemm 	 */
703a08f4bf6SPeter Wemm 	if (
704a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
705b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
706a08f4bf6SPeter Wemm #endif
707b1fc0ec1SRobert Watson 	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
708a08f4bf6SPeter Wemm #endif
709a08f4bf6SPeter Wemm 	{
710a08f4bf6SPeter Wemm 		/*
711a08f4bf6SPeter Wemm 		 * Set real gid
712a08f4bf6SPeter Wemm 		 */
713b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
714b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
715d5f81602SSean Eric Fagan 			setsugid(p);
716a08f4bf6SPeter Wemm 		}
717a08f4bf6SPeter Wemm 		/*
718a08f4bf6SPeter Wemm 		 * Set saved gid
719a08f4bf6SPeter Wemm 		 *
720a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
721a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
722a08f4bf6SPeter Wemm 		 * is important that we should do this.
723a08f4bf6SPeter Wemm 		 */
724b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
725b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
726d5f81602SSean Eric Fagan 			setsugid(p);
727a08f4bf6SPeter Wemm 		}
728a08f4bf6SPeter Wemm 	}
729a08f4bf6SPeter Wemm 	/*
730a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
731a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
732a08f4bf6SPeter Wemm 	 */
733b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
734b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
735d5f81602SSean Eric Fagan 		setsugid(p);
736a08f4bf6SPeter Wemm 	}
737b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
738b1fc0ec1SRobert Watson 	crfree(oldcred);
739835a82eeSMatthew Dillon done2:
740835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
741835a82eeSMatthew Dillon 	return (error);
742df8bae1dSRodney W. Grimes }
743df8bae1dSRodney W. Grimes 
744d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
745df8bae1dSRodney W. Grimes struct setegid_args {
746df8bae1dSRodney W. Grimes 	gid_t	egid;
747df8bae1dSRodney W. Grimes };
748d2d3e875SBruce Evans #endif
749835a82eeSMatthew Dillon /*
750835a82eeSMatthew Dillon  * MPSAFE
751835a82eeSMatthew Dillon  */
752df8bae1dSRodney W. Grimes /* ARGSUSED */
75326f9a767SRodney W. Grimes int
754b40ce416SJulian Elischer setegid(td, uap)
755b40ce416SJulian Elischer 	struct thread *td;
756df8bae1dSRodney W. Grimes 	struct setegid_args *uap;
757df8bae1dSRodney W. Grimes {
758b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
759b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
760b1fc0ec1SRobert Watson 	gid_t egid;
761835a82eeSMatthew Dillon 	int error = 0;
762df8bae1dSRodney W. Grimes 
763df8bae1dSRodney W. Grimes 	egid = uap->egid;
764835a82eeSMatthew Dillon 
765835a82eeSMatthew Dillon 	mtx_lock(&Giant);
766b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
767b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
768b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
769835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) {
770835a82eeSMatthew Dillon 		goto done2;
771835a82eeSMatthew Dillon 	}
772b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
773b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
774b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
775d5f81602SSean Eric Fagan 		setsugid(p);
776229a15f0SPeter Wemm 	}
777b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
778b1fc0ec1SRobert Watson 	crfree(oldcred);
779835a82eeSMatthew Dillon done2:
780835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
781835a82eeSMatthew Dillon 	return (error);
782df8bae1dSRodney W. Grimes }
783df8bae1dSRodney W. Grimes 
784d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
785df8bae1dSRodney W. Grimes struct setgroups_args {
786df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
787df8bae1dSRodney W. Grimes 	gid_t	*gidset;
788df8bae1dSRodney W. Grimes };
789d2d3e875SBruce Evans #endif
790835a82eeSMatthew Dillon /*
791835a82eeSMatthew Dillon  * MPSAFE
792835a82eeSMatthew Dillon  */
793df8bae1dSRodney W. Grimes /* ARGSUSED */
79426f9a767SRodney W. Grimes int
795b40ce416SJulian Elischer setgroups(td, uap)
796b40ce416SJulian Elischer 	struct thread *td;
797df8bae1dSRodney W. Grimes 	struct setgroups_args *uap;
798df8bae1dSRodney W. Grimes {
799b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
800b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
801b1fc0ec1SRobert Watson 	u_int ngrp;
802df8bae1dSRodney W. Grimes 	int error;
803df8bae1dSRodney W. Grimes 
804835a82eeSMatthew Dillon 	mtx_lock(&Giant);
805835a82eeSMatthew Dillon 
8063956a170SDavid Greenman 	ngrp = uap->gidsetsize;
807b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
808b1fc0ec1SRobert Watson 	if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
809835a82eeSMatthew Dillon 		goto done2;
810835a82eeSMatthew Dillon 	if (ngrp > NGROUPS) {
811835a82eeSMatthew Dillon 		error = EINVAL;
812835a82eeSMatthew Dillon 		goto done2;
813835a82eeSMatthew Dillon 	}
8148a5d815aSPeter Wemm 	/*
8158a5d815aSPeter Wemm 	 * XXX A little bit lazy here.  We could test if anything has
8168a5d815aSPeter Wemm 	 * changed before crcopy() and setting P_SUGID.
8178a5d815aSPeter Wemm 	 */
818b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
8198a5d815aSPeter Wemm 	if (ngrp < 1) {
8208a5d815aSPeter Wemm 		/*
8218a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
8228a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
8238a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
8248a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
8258a5d815aSPeter Wemm 		 */
826b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
8278a5d815aSPeter Wemm 	} else {
828bb56ec4aSPoul-Henning Kamp 		if ((error = copyin((caddr_t)uap->gidset,
829b1fc0ec1SRobert Watson 		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
830b1fc0ec1SRobert Watson 			crfree(newcred);
831835a82eeSMatthew Dillon 			goto done2;
832b1fc0ec1SRobert Watson 		}
833b1fc0ec1SRobert Watson 		newcred->cr_ngroups = ngrp;
8348a5d815aSPeter Wemm 	}
835d5f81602SSean Eric Fagan 	setsugid(p);
836b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
837b1fc0ec1SRobert Watson 	crfree(oldcred);
838835a82eeSMatthew Dillon done2:
839835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
840835a82eeSMatthew Dillon 	return (error);
841df8bae1dSRodney W. Grimes }
842df8bae1dSRodney W. Grimes 
843d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
844df8bae1dSRodney W. Grimes struct setreuid_args {
84500999cd6SAndrey A. Chernov 	uid_t	ruid;
84600999cd6SAndrey A. Chernov 	uid_t	euid;
847df8bae1dSRodney W. Grimes };
848d2d3e875SBruce Evans #endif
849835a82eeSMatthew Dillon /*
850835a82eeSMatthew Dillon  * MPSAFE
851835a82eeSMatthew Dillon  */
852df8bae1dSRodney W. Grimes /* ARGSUSED */
85326f9a767SRodney W. Grimes int
854b40ce416SJulian Elischer setreuid(td, uap)
855b40ce416SJulian Elischer 	register struct thread *td;
856df8bae1dSRodney W. Grimes 	struct setreuid_args *uap;
857df8bae1dSRodney W. Grimes {
858b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
859b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
860b1fc0ec1SRobert Watson 	uid_t ruid, euid;
861835a82eeSMatthew Dillon 	int error = 0;
862df8bae1dSRodney W. Grimes 
86300999cd6SAndrey A. Chernov 	ruid = uap->ruid;
86400999cd6SAndrey A. Chernov 	euid = uap->euid;
865835a82eeSMatthew Dillon 
866835a82eeSMatthew Dillon 	mtx_lock(&Giant);
867835a82eeSMatthew Dillon 
868b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
869b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
870b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
871b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
872b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
873835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
874835a82eeSMatthew Dillon 		goto done2;
875835a82eeSMatthew Dillon 	}
876b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
877b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
878b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
879d5f81602SSean Eric Fagan 		setsugid(p);
880a89a5370SPeter Wemm 	}
881b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
882b1fc0ec1SRobert Watson 		change_ruid(newcred, ruid);
883d5f81602SSean Eric Fagan 		setsugid(p);
88400999cd6SAndrey A. Chernov 	}
885b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
886b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
887b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
888d5f81602SSean Eric Fagan 		setsugid(p);
889a89a5370SPeter Wemm 	}
890b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
891b1fc0ec1SRobert Watson 	crfree(oldcred);
892835a82eeSMatthew Dillon done2:
893835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
894835a82eeSMatthew Dillon 	return (error);
895df8bae1dSRodney W. Grimes }
896df8bae1dSRodney W. Grimes 
897d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
898df8bae1dSRodney W. Grimes struct setregid_args {
89900999cd6SAndrey A. Chernov 	gid_t	rgid;
90000999cd6SAndrey A. Chernov 	gid_t	egid;
901df8bae1dSRodney W. Grimes };
902d2d3e875SBruce Evans #endif
903835a82eeSMatthew Dillon /*
904835a82eeSMatthew Dillon  * MPSAFE
905835a82eeSMatthew Dillon  */
906df8bae1dSRodney W. Grimes /* ARGSUSED */
90726f9a767SRodney W. Grimes int
908b40ce416SJulian Elischer setregid(td, uap)
909b40ce416SJulian Elischer 	register struct thread *td;
910df8bae1dSRodney W. Grimes 	struct setregid_args *uap;
911df8bae1dSRodney W. Grimes {
912b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
913b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
914b1fc0ec1SRobert Watson 	gid_t rgid, egid;
915835a82eeSMatthew Dillon 	int error = 0;
916df8bae1dSRodney W. Grimes 
91700999cd6SAndrey A. Chernov 	rgid = uap->rgid;
91800999cd6SAndrey A. Chernov 	egid = uap->egid;
919835a82eeSMatthew Dillon 
920835a82eeSMatthew Dillon 	mtx_lock(&Giant);
921835a82eeSMatthew Dillon 
922b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
923b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
924b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
925b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
926b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
927835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
928835a82eeSMatthew Dillon 		goto done2;
929835a82eeSMatthew Dillon 	}
93000999cd6SAndrey A. Chernov 
931b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
932b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
933b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
934d5f81602SSean Eric Fagan 		setsugid(p);
935a89a5370SPeter Wemm 	}
936b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
937b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
938d5f81602SSean Eric Fagan 		setsugid(p);
939a89a5370SPeter Wemm 	}
940b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
941b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
942b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
943d5f81602SSean Eric Fagan 		setsugid(p);
944a89a5370SPeter Wemm 	}
9454589be70SRuslan Ermilov 	p->p_ucred = newcred;
9464589be70SRuslan Ermilov 	crfree(oldcred);
947835a82eeSMatthew Dillon done2:
948835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
949835a82eeSMatthew Dillon 	return (error);
950df8bae1dSRodney W. Grimes }
951df8bae1dSRodney W. Grimes 
9528ccd6334SPeter Wemm /*
9538ccd6334SPeter Wemm  * setresuid(ruid, euid, suid) is like setreuid except control over the
9548ccd6334SPeter Wemm  * saved uid is explicit.
9558ccd6334SPeter Wemm  */
9568ccd6334SPeter Wemm 
9578ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
9588ccd6334SPeter Wemm struct setresuid_args {
9598ccd6334SPeter Wemm 	uid_t	ruid;
9608ccd6334SPeter Wemm 	uid_t	euid;
9618ccd6334SPeter Wemm 	uid_t	suid;
9628ccd6334SPeter Wemm };
9638ccd6334SPeter Wemm #endif
964835a82eeSMatthew Dillon /*
965835a82eeSMatthew Dillon  * MPSAFE
966835a82eeSMatthew Dillon  */
9678ccd6334SPeter Wemm /* ARGSUSED */
9688ccd6334SPeter Wemm int
969b40ce416SJulian Elischer setresuid(td, uap)
970b40ce416SJulian Elischer 	register struct thread *td;
9718ccd6334SPeter Wemm 	struct setresuid_args *uap;
9728ccd6334SPeter Wemm {
973b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
974b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
975b1fc0ec1SRobert Watson 	uid_t ruid, euid, suid;
9768ccd6334SPeter Wemm 	int error;
9778ccd6334SPeter Wemm 
9788ccd6334SPeter Wemm 	ruid = uap->ruid;
9798ccd6334SPeter Wemm 	euid = uap->euid;
9808ccd6334SPeter Wemm 	suid = uap->suid;
981835a82eeSMatthew Dillon 
982835a82eeSMatthew Dillon 	mtx_lock(&Giant);
983b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
984b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
985b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
986b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
987b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
988b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
989b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
990b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
991b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
992b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
993835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
994835a82eeSMatthew Dillon 		goto done2;
995835a82eeSMatthew Dillon 	}
996b1fc0ec1SRobert Watson 
997b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
998b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
999b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
10008ccd6334SPeter Wemm 		setsugid(p);
10018ccd6334SPeter Wemm 	}
1002b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
1003b1fc0ec1SRobert Watson 		change_ruid(newcred, ruid);
10048ccd6334SPeter Wemm 		setsugid(p);
10058ccd6334SPeter Wemm 	}
1006b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1007b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
10088ccd6334SPeter Wemm 		setsugid(p);
10098ccd6334SPeter Wemm 	}
1010b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
1011b1fc0ec1SRobert Watson 	crfree(oldcred);
1012835a82eeSMatthew Dillon 	error = 0;
1013835a82eeSMatthew Dillon done2:
1014835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1015835a82eeSMatthew Dillon 	return (error);
10168ccd6334SPeter Wemm }
10178ccd6334SPeter Wemm 
10188ccd6334SPeter Wemm /*
10198ccd6334SPeter Wemm  * setresgid(rgid, egid, sgid) is like setregid except control over the
10208ccd6334SPeter Wemm  * saved gid is explicit.
10218ccd6334SPeter Wemm  */
10228ccd6334SPeter Wemm 
10238ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10248ccd6334SPeter Wemm struct setresgid_args {
10258ccd6334SPeter Wemm 	gid_t	rgid;
10268ccd6334SPeter Wemm 	gid_t	egid;
10278ccd6334SPeter Wemm 	gid_t	sgid;
10288ccd6334SPeter Wemm };
10298ccd6334SPeter Wemm #endif
1030835a82eeSMatthew Dillon /*
1031835a82eeSMatthew Dillon  * MPSAFE
1032835a82eeSMatthew Dillon  */
10338ccd6334SPeter Wemm /* ARGSUSED */
10348ccd6334SPeter Wemm int
1035b40ce416SJulian Elischer setresgid(td, uap)
1036b40ce416SJulian Elischer 	register struct thread *td;
10378ccd6334SPeter Wemm 	struct setresgid_args *uap;
10388ccd6334SPeter Wemm {
1039b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1040b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1041b1fc0ec1SRobert Watson 	gid_t rgid, egid, sgid;
10428ccd6334SPeter Wemm 	int error;
10438ccd6334SPeter Wemm 
10448ccd6334SPeter Wemm 	rgid = uap->rgid;
10458ccd6334SPeter Wemm 	egid = uap->egid;
10468ccd6334SPeter Wemm 	sgid = uap->sgid;
1047835a82eeSMatthew Dillon 
1048835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1049b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
1050b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1051b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1052b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1053b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1054b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1055b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1056b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1057b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1058b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
1059835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
1060835a82eeSMatthew Dillon 		goto done2;
1061835a82eeSMatthew Dillon 	}
1062b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
1063b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1064b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
10658ccd6334SPeter Wemm 		setsugid(p);
10668ccd6334SPeter Wemm 	}
1067b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1068b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
10698ccd6334SPeter Wemm 		setsugid(p);
10708ccd6334SPeter Wemm 	}
1071b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1072b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
10738ccd6334SPeter Wemm 		setsugid(p);
10748ccd6334SPeter Wemm 	}
1075b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
1076b1fc0ec1SRobert Watson 	crfree(oldcred);
1077835a82eeSMatthew Dillon 	error = 0;
1078835a82eeSMatthew Dillon done2:
1079835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1080835a82eeSMatthew Dillon 	return (error);
10818ccd6334SPeter Wemm }
10828ccd6334SPeter Wemm 
10838ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10848ccd6334SPeter Wemm struct getresuid_args {
10858ccd6334SPeter Wemm 	uid_t	*ruid;
10868ccd6334SPeter Wemm 	uid_t	*euid;
10878ccd6334SPeter Wemm 	uid_t	*suid;
10888ccd6334SPeter Wemm };
10898ccd6334SPeter Wemm #endif
1090835a82eeSMatthew Dillon /*
1091835a82eeSMatthew Dillon  * MPSAFE
1092835a82eeSMatthew Dillon  */
10938ccd6334SPeter Wemm /* ARGSUSED */
10948ccd6334SPeter Wemm int
1095b40ce416SJulian Elischer getresuid(td, uap)
1096b40ce416SJulian Elischer 	register struct thread *td;
10978ccd6334SPeter Wemm 	struct getresuid_args *uap;
10988ccd6334SPeter Wemm {
1099835a82eeSMatthew Dillon 	struct ucred *cred;
1100b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
11018ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11028ccd6334SPeter Wemm 
1103835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1104835a82eeSMatthew Dillon 	cred = p->p_ucred;
1105835a82eeSMatthew Dillon 
11068ccd6334SPeter Wemm 	if (uap->ruid)
1107b1fc0ec1SRobert Watson 		error1 = copyout((caddr_t)&cred->cr_ruid,
1108b1fc0ec1SRobert Watson 		    (caddr_t)uap->ruid, sizeof(cred->cr_ruid));
11098ccd6334SPeter Wemm 	if (uap->euid)
1110b1fc0ec1SRobert Watson 		error2 = copyout((caddr_t)&cred->cr_uid,
1111b1fc0ec1SRobert Watson 		    (caddr_t)uap->euid, sizeof(cred->cr_uid));
11128ccd6334SPeter Wemm 	if (uap->suid)
1113b1fc0ec1SRobert Watson 		error3 = copyout((caddr_t)&cred->cr_svuid,
1114b1fc0ec1SRobert Watson 		    (caddr_t)uap->suid, sizeof(cred->cr_svuid));
1115835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
11168ccd6334SPeter Wemm 	return error1 ? error1 : (error2 ? error2 : error3);
11178ccd6334SPeter Wemm }
11188ccd6334SPeter Wemm 
11198ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11208ccd6334SPeter Wemm struct getresgid_args {
11218ccd6334SPeter Wemm 	gid_t	*rgid;
11228ccd6334SPeter Wemm 	gid_t	*egid;
11238ccd6334SPeter Wemm 	gid_t	*sgid;
11248ccd6334SPeter Wemm };
11258ccd6334SPeter Wemm #endif
1126835a82eeSMatthew Dillon /*
1127835a82eeSMatthew Dillon  * MPSAFE
1128835a82eeSMatthew Dillon  */
11298ccd6334SPeter Wemm /* ARGSUSED */
11308ccd6334SPeter Wemm int
1131b40ce416SJulian Elischer getresgid(td, uap)
1132b40ce416SJulian Elischer 	register struct thread *td;
11338ccd6334SPeter Wemm 	struct getresgid_args *uap;
11348ccd6334SPeter Wemm {
1135835a82eeSMatthew Dillon 	struct ucred *cred;
1136b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
11378ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11388ccd6334SPeter Wemm 
1139835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1140835a82eeSMatthew Dillon 	cred = p->p_ucred;
1141835a82eeSMatthew Dillon 
11428ccd6334SPeter Wemm 	if (uap->rgid)
1143b1fc0ec1SRobert Watson 		error1 = copyout((caddr_t)&cred->cr_rgid,
1144b1fc0ec1SRobert Watson 		    (caddr_t)uap->rgid, sizeof(cred->cr_rgid));
11458ccd6334SPeter Wemm 	if (uap->egid)
1146b1fc0ec1SRobert Watson 		error2 = copyout((caddr_t)&cred->cr_groups[0],
1147b1fc0ec1SRobert Watson 		    (caddr_t)uap->egid, sizeof(cred->cr_groups[0]));
11488ccd6334SPeter Wemm 	if (uap->sgid)
1149b1fc0ec1SRobert Watson 		error3 = copyout((caddr_t)&cred->cr_svgid,
1150b1fc0ec1SRobert Watson 		    (caddr_t)uap->sgid, sizeof(cred->cr_svgid));
1151835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
11528ccd6334SPeter Wemm 	return error1 ? error1 : (error2 ? error2 : error3);
11538ccd6334SPeter Wemm }
11548ccd6334SPeter Wemm 
11558ccd6334SPeter Wemm 
1156b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1157b67cbc65SPeter Wemm struct issetugid_args {
1158b67cbc65SPeter Wemm 	int dummy;
1159b67cbc65SPeter Wemm };
1160b67cbc65SPeter Wemm #endif
1161b67cbc65SPeter Wemm /* ARGSUSED */
1162b67cbc65SPeter Wemm int
1163b40ce416SJulian Elischer issetugid(td, uap)
1164b40ce416SJulian Elischer 	register struct thread *td;
1165b67cbc65SPeter Wemm 	struct issetugid_args *uap;
1166b67cbc65SPeter Wemm {
1167b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1168b40ce416SJulian Elischer 
1169b67cbc65SPeter Wemm 	/*
1170b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1171b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1172b67cbc65SPeter Wemm 	 * "tainting" as well.
1173b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1174b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1175b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1176b67cbc65SPeter Wemm 	 */
1177b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1178b67cbc65SPeter Wemm 	return (0);
1179b67cbc65SPeter Wemm }
1180b67cbc65SPeter Wemm 
1181835a82eeSMatthew Dillon /*
1182835a82eeSMatthew Dillon  * MPSAFE
1183835a82eeSMatthew Dillon  */
1184130d0157SRobert Watson int
1185b40ce416SJulian Elischer __setugid(td, uap)
1186b40ce416SJulian Elischer 	struct thread *td;
1187130d0157SRobert Watson 	struct __setugid_args *uap;
1188130d0157SRobert Watson {
1189130d0157SRobert Watson #ifdef REGRESSION
1190835a82eeSMatthew Dillon 	int error = 0;
1191835a82eeSMatthew Dillon 
1192835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1193130d0157SRobert Watson 	switch (uap->flag) {
1194130d0157SRobert Watson 	case 0:
1195b40ce416SJulian Elischer 		td->td_proc->p_flag &= ~P_SUGID;
1196835a82eeSMatthew Dillon 		break;
1197130d0157SRobert Watson 	case 1:
1198b40ce416SJulian Elischer 		td->td_proc->p_flag |= P_SUGID;
1199835a82eeSMatthew Dillon 		break;
1200130d0157SRobert Watson 	default:
1201835a82eeSMatthew Dillon 		error = EINVAL;
1202835a82eeSMatthew Dillon 		break;
1203130d0157SRobert Watson 	}
1204835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1205835a82eeSMatthew Dillon 	return (error);
1206130d0157SRobert Watson #else /* !REGRESSION */
1207130d0157SRobert Watson 	return (ENOSYS);
1208130d0157SRobert Watson #endif /* !REGRESSION */
1209130d0157SRobert Watson }
1210130d0157SRobert Watson 
1211df8bae1dSRodney W. Grimes /*
1212df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
1213df8bae1dSRodney W. Grimes  */
121426f9a767SRodney W. Grimes int
1215df8bae1dSRodney W. Grimes groupmember(gid, cred)
1216df8bae1dSRodney W. Grimes 	gid_t gid;
1217b1fc0ec1SRobert Watson 	struct ucred *cred;
1218df8bae1dSRodney W. Grimes {
1219df8bae1dSRodney W. Grimes 	register gid_t *gp;
1220df8bae1dSRodney W. Grimes 	gid_t *egp;
1221df8bae1dSRodney W. Grimes 
1222df8bae1dSRodney W. Grimes 	egp = &(cred->cr_groups[cred->cr_ngroups]);
1223df8bae1dSRodney W. Grimes 	for (gp = cred->cr_groups; gp < egp; gp++)
1224df8bae1dSRodney W. Grimes 		if (*gp == gid)
1225df8bae1dSRodney W. Grimes 			return (1);
1226df8bae1dSRodney W. Grimes 	return (0);
1227df8bae1dSRodney W. Grimes }
1228df8bae1dSRodney W. Grimes 
12293b243b72SRobert Watson /*
123093f4fd1cSRobert Watson  * `suser_enabled' (which can be set by the kern.security.suser_enabled
12317fd6a959SRobert Watson  * sysctl) determines whether the system 'super-user' policy is in effect.
12327fd6a959SRobert Watson  * If it is nonzero, an effective uid of 0 connotes special privilege,
12337fd6a959SRobert Watson  * overriding many mandatory and discretionary protections.  If it is zero,
12347fd6a959SRobert Watson  * uid 0 is offered no special privilege in the kernel security policy.
12357fd6a959SRobert Watson  * Setting it to zero may seriously impact the functionality of many
12367fd6a959SRobert Watson  * existing userland programs, and should not be done without careful
12377fd6a959SRobert Watson  * consideration of the consequences.
12383b243b72SRobert Watson  */
123993f4fd1cSRobert Watson int	suser_enabled = 1;
124093f4fd1cSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, suser_enabled, CTLFLAG_RW,
124193f4fd1cSRobert Watson     &suser_enabled, 0, "processes with uid 0 have privilege");
1242579f4eb4SRobert Watson 
1243df8bae1dSRodney W. Grimes /*
12447fd6a959SRobert Watson  * Test whether the specified credentials imply "super-user" privilege.
12457fd6a959SRobert Watson  * Return 0 or EPERM.
1246df8bae1dSRodney W. Grimes  */
124726f9a767SRodney W. Grimes int
1248f711d546SPoul-Henning Kamp suser(p)
124991421ba2SRobert Watson 	struct proc *p;
1250f711d546SPoul-Henning Kamp {
125175c13541SPoul-Henning Kamp 	return suser_xxx(0, p, 0);
1252f711d546SPoul-Henning Kamp }
1253f711d546SPoul-Henning Kamp 
1254b40ce416SJulian Elischer /*
1255b40ce416SJulian Elischer  * version for when the thread pointer is available and not the proc.
1256b40ce416SJulian Elischer  * (saves having to include proc.h into every file that needs to do the change.)
1257b40ce416SJulian Elischer  */
1258b40ce416SJulian Elischer int
1259b40ce416SJulian Elischer suser_td(td)
1260b40ce416SJulian Elischer 
1261b40ce416SJulian Elischer 	struct thread *td;
1262b40ce416SJulian Elischer {
1263b40ce416SJulian Elischer 	return suser_xxx(0, td->td_proc, 0);
1264b40ce416SJulian Elischer }
1265b40ce416SJulian Elischer 
1266b40ce416SJulian Elischer /*
1267b40ce416SJulian Elischer  * wrapper to use if you have the thread on hand but not the proc.
1268b40ce416SJulian Elischer  */
1269b40ce416SJulian Elischer int
1270b40ce416SJulian Elischer suser_xxx_td(cred, td, flag)
1271b40ce416SJulian Elischer 	struct ucred *cred;
1272b40ce416SJulian Elischer 	struct thread *td;
1273b40ce416SJulian Elischer 	int flag;
1274b40ce416SJulian Elischer {
1275b40ce416SJulian Elischer 	return(suser_xxx(cred, td->td_proc, flag));
1276b40ce416SJulian Elischer }
1277b40ce416SJulian Elischer 
1278f711d546SPoul-Henning Kamp int
127975c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag)
128091421ba2SRobert Watson 	struct ucred *cred;
128191421ba2SRobert Watson 	struct proc *proc;
128275c13541SPoul-Henning Kamp 	int flag;
1283df8bae1dSRodney W. Grimes {
128493f4fd1cSRobert Watson 	if (!suser_enabled)
128503095547SRobert Watson 		return (EPERM);
128675c13541SPoul-Henning Kamp 	if (!cred && !proc) {
128775c13541SPoul-Henning Kamp 		printf("suser_xxx(): THINK!\n");
1288df8bae1dSRodney W. Grimes 		return (EPERM);
1289df8bae1dSRodney W. Grimes 	}
129075c13541SPoul-Henning Kamp 	if (!cred)
129175c13541SPoul-Henning Kamp 		cred = proc->p_ucred;
129275c13541SPoul-Henning Kamp 	if (cred->cr_uid != 0)
129375c13541SPoul-Henning Kamp 		return (EPERM);
129491421ba2SRobert Watson 	if (jailed(cred) && !(flag & PRISON_ROOT))
129575c13541SPoul-Henning Kamp 		return (EPERM);
129675c13541SPoul-Henning Kamp 	return (0);
129775c13541SPoul-Henning Kamp }
1298df8bae1dSRodney W. Grimes 
12993ca719f1SRobert Watson /*
130087fce2bbSRobert Watson  * Test (local, globale) securelevel values against passed required
130187fce2bbSRobert Watson  * securelevel.  _gt implements (level > securelevel), and _ge implements
130275bc5b3fSRobert Watson  * (level >= securelevel).  Returns 0 oer EPERM.
13033ca719f1SRobert Watson  *
13043ca719f1SRobert Watson  * cr is permitted to be NULL for the time being, as there were some
13053ca719f1SRobert Watson  * existing securelevel checks that occurred without a process/credential
13063ca719f1SRobert Watson  * context.  In the future this will be disallowed, so a kernel
13073ca719f1SRobert Watson  * message is displayed.
13083ca719f1SRobert Watson  */
13093ca719f1SRobert Watson int
13103ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
13113ca719f1SRobert Watson {
13123ca719f1SRobert Watson 
13133ca719f1SRobert Watson 	if (cr == NULL) {
13143ca719f1SRobert Watson 		printf("securelevel_gt: cr is NULL\n");
131575bc5b3fSRobert Watson 		if (level > securelevel)
13163ca719f1SRobert Watson 			return (0);
13173ca719f1SRobert Watson 		else
13183ca719f1SRobert Watson 			return (EPERM);
131987fce2bbSRobert Watson 	} else if (cr->cr_prison == NULL) {
132075bc5b3fSRobert Watson 		if (level > securelevel)
13213ca719f1SRobert Watson 			return (0);
13223ca719f1SRobert Watson 		else
13233ca719f1SRobert Watson 			return (EPERM);
132487fce2bbSRobert Watson 	} else {
132587fce2bbSRobert Watson 		if (level > imax(cr->cr_prison->pr_securelevel, securelevel))
132687fce2bbSRobert Watson 			return (0);
132787fce2bbSRobert Watson 		else
132887fce2bbSRobert Watson 			return (EPERM);
13293ca719f1SRobert Watson 	}
133087fce2bbSRobert Watson 
13313ca719f1SRobert Watson }
13323ca719f1SRobert Watson 
13333ca719f1SRobert Watson int
13343ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
13353ca719f1SRobert Watson {
13363ca719f1SRobert Watson 
13373ca719f1SRobert Watson 	if (cr == NULL) {
13383ca719f1SRobert Watson 		printf("securelevel_ge: cr is NULL\n");
133975bc5b3fSRobert Watson 		if (level >= securelevel)
13403ca719f1SRobert Watson 			return (0);
13413ca719f1SRobert Watson 		else
13423ca719f1SRobert Watson 			return (EPERM);
134387fce2bbSRobert Watson 	} if (cr->cr_prison == NULL) {
134475bc5b3fSRobert Watson 		if (level >= securelevel)
13453ca719f1SRobert Watson 			return (0);
13463ca719f1SRobert Watson 		else
13473ca719f1SRobert Watson 			return (EPERM);
134887fce2bbSRobert Watson 	} else {
134987fce2bbSRobert Watson 		if (level >= imax(cr->cr_prison->pr_securelevel, securelevel))
135087fce2bbSRobert Watson 			return (0);
135187fce2bbSRobert Watson 		else
135287fce2bbSRobert Watson 			return (EPERM);
13533ca719f1SRobert Watson 	}
13543ca719f1SRobert Watson }
13553ca719f1SRobert Watson 
13568a7d8cc6SRobert Watson /*
13578a7d8cc6SRobert Watson  * kern_security_seeotheruids_permitted determines whether or not visibility
13588a7d8cc6SRobert Watson  * of processes and sockets with credentials holding different real uid's
13598a7d8cc6SRobert Watson  * is possible using a variety of system MIBs.
13608a7d8cc6SRobert Watson  */
13618a7d8cc6SRobert Watson static int	kern_security_seeotheruids_permitted = 1;
13628a7d8cc6SRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, seeotheruids_permitted,
13638a7d8cc6SRobert Watson     CTLFLAG_RW, &kern_security_seeotheruids_permitted, 0,
13648a7d8cc6SRobert Watson     "Unprivileged processes may see subjects/objects with different real uid");
13658a7d8cc6SRobert Watson 
13667fd6a959SRobert Watson /*-
13677fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1368ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1369ed639720SRobert Watson  * Locks: none
13707fd6a959SRobert Watson  * References: u1 and u2 must be immutable credentials
13717fd6a959SRobert Watson  *             u1 and u2 must be valid for the lifetime of the call
1372ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1373ed639720SRobert Watson  */
1374ed639720SRobert Watson int
137594088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1376a9e0361bSPoul-Henning Kamp {
137791421ba2SRobert Watson 	int error;
1378a9e0361bSPoul-Henning Kamp 
1379ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
138091421ba2SRobert Watson 		return (error);
13818a7d8cc6SRobert Watson 	if (!kern_security_seeotheruids_permitted &&
13828a7d8cc6SRobert Watson 	    u1->cr_ruid != u2->cr_ruid) {
1383f8e6ab29SRobert Watson 		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
1384387d2c03SRobert Watson 			return (ESRCH);
1385c52396e3SRobert Watson 	}
1386387d2c03SRobert Watson 	return (0);
1387387d2c03SRobert Watson }
1388387d2c03SRobert Watson 
13897fd6a959SRobert Watson /*-
13907fd6a959SRobert Watson  * Determine if p1 "can see" the subject specified by p2.
13913b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
13927fd6a959SRobert Watson  * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must
13933b243b72SRobert Watson  *        be held.  Normally, p1 will be curproc, and a lock must be held
13943b243b72SRobert Watson  *        for p2.
13953b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
13963b243b72SRobert Watson  */
1397a0f75161SRobert Watson int
1398a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2)
1399ed639720SRobert Watson {
1400ed639720SRobert Watson 
140194088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
140294088977SRobert Watson 	return (cr_cansee(p1->p_ucred, p2->p_ucred));
1403ed639720SRobert Watson }
1404ed639720SRobert Watson 
14057fd6a959SRobert Watson /*-
14067fd6a959SRobert Watson  * Determine whether p1 may deliver the specified signal to p2.
14077fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
14087fd6a959SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
14097fd6a959SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
14107fd6a959SRobert Watson  *        be held for p2.
14113b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
14124c5eb9c3SRobert Watson  */
14134c5eb9c3SRobert Watson int
14144c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum)
1415387d2c03SRobert Watson {
141691421ba2SRobert Watson 	int error;
1417387d2c03SRobert Watson 
1418a9e0361bSPoul-Henning Kamp 	if (p1 == p2)
1419a9e0361bSPoul-Henning Kamp 		return (0);
1420387d2c03SRobert Watson 
14214c5eb9c3SRobert Watson 	/*
14224c5eb9c3SRobert Watson 	 * Jail semantics limit the scope of signalling to p2 in the same
14234c5eb9c3SRobert Watson 	 * jail as p1, if p1 is in jail.
14244c5eb9c3SRobert Watson 	 */
142591421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
142691421ba2SRobert Watson 		return (error);
1427387d2c03SRobert Watson 
1428387d2c03SRobert Watson 	/*
14294c5eb9c3SRobert Watson 	 * UNIX signalling semantics require that processes in the same
14304c5eb9c3SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
14314c5eb9c3SRobert Watson 	 * overriding the remaining protections.
1432387d2c03SRobert Watson 	 */
14334c5eb9c3SRobert Watson 	if (signum == SIGCONT && p1->p_session == p2->p_session)
1434a9e0361bSPoul-Henning Kamp 		return (0);
1435387d2c03SRobert Watson 
14364c5eb9c3SRobert Watson 	/*
14373b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
14383b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
14393b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
14404c5eb9c3SRobert Watson 	 */
14414c5eb9c3SRobert Watson 	if (p2->p_flag & P_SUGID) {
14424c5eb9c3SRobert Watson 		switch (signum) {
14434c5eb9c3SRobert Watson 		case 0:
14444c5eb9c3SRobert Watson 		case SIGKILL:
14454c5eb9c3SRobert Watson 		case SIGINT:
14464c5eb9c3SRobert Watson 		case SIGTERM:
14474c5eb9c3SRobert Watson 		case SIGSTOP:
14484c5eb9c3SRobert Watson 		case SIGTTIN:
14494c5eb9c3SRobert Watson 		case SIGTTOU:
14504c5eb9c3SRobert Watson 		case SIGTSTP:
14514c5eb9c3SRobert Watson 		case SIGHUP:
14524c5eb9c3SRobert Watson 		case SIGUSR1:
14534c5eb9c3SRobert Watson 		case SIGUSR2:
14547fd6a959SRobert Watson 			/*
14557fd6a959SRobert Watson 			 * Generally, permit job and terminal control
14567fd6a959SRobert Watson 			 * signals.
14577fd6a959SRobert Watson 			 */
14584c5eb9c3SRobert Watson 			break;
14594c5eb9c3SRobert Watson 		default:
14603b243b72SRobert Watson 			/* Not permitted, privilege is required. */
14614c5eb9c3SRobert Watson 			error = suser_xxx(NULL, p1, PRISON_ROOT);
14624c5eb9c3SRobert Watson 			if (error)
14634c5eb9c3SRobert Watson 				return (error);
14644c5eb9c3SRobert Watson 		}
1465e9e7ff5bSRobert Watson 	}
1466e9e7ff5bSRobert Watson 
14674c5eb9c3SRobert Watson 	/*
14683b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1469e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
14704c5eb9c3SRobert Watson 	 */
1471b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid &&
1472b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid &&
1473b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid &&
1474b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) {
14754c5eb9c3SRobert Watson 		/* Not permitted, try privilege. */
14764c5eb9c3SRobert Watson 		error = suser_xxx(NULL, p1, PRISON_ROOT);
14774c5eb9c3SRobert Watson 		if (error)
14784c5eb9c3SRobert Watson 			return (error);
14794c5eb9c3SRobert Watson 	}
1480387d2c03SRobert Watson 
1481387d2c03SRobert Watson         return (0);
1482387d2c03SRobert Watson }
1483a9e0361bSPoul-Henning Kamp 
14847fd6a959SRobert Watson /*-
14857fd6a959SRobert Watson  * Determine whether p1 may reschedule p2
14867fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
14873b243b72SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
14883b243b72SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
14897fd6a959SRobert Watson  *        be held for p2.
14903b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
14913b243b72SRobert Watson  */
1492a0f75161SRobert Watson int
1493a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2)
1494387d2c03SRobert Watson {
149591421ba2SRobert Watson 	int error;
1496387d2c03SRobert Watson 
1497387d2c03SRobert Watson 	if (p1 == p2)
1498387d2c03SRobert Watson 		return (0);
149991421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
150091421ba2SRobert Watson 		return (error);
1501b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid)
1502387d2c03SRobert Watson 		return (0);
1503b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid)
1504387d2c03SRobert Watson 		return (0);
15057fd6a959SRobert Watson 	if (suser_xxx(0, p1, PRISON_ROOT) == 0)
1506387d2c03SRobert Watson 		return (0);
1507387d2c03SRobert Watson 
1508387d2c03SRobert Watson #ifdef CAPABILITIES
15094df571b1SRobert Watson 	if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT))
1510387d2c03SRobert Watson 		return (0);
1511387d2c03SRobert Watson #endif
1512387d2c03SRobert Watson 
1513387d2c03SRobert Watson 	return (EPERM);
1514387d2c03SRobert Watson }
1515387d2c03SRobert Watson 
15163b243b72SRobert Watson /*
15177fd6a959SRobert Watson  * The kern_unprivileged_procdebug_permitted flag may be used to disable
15183b243b72SRobert Watson  * a variety of unprivileged inter-process debugging services, including
15193b243b72SRobert Watson  * some procfs functionality, ptrace(), and ktrace().  In the past,
15203b243b72SRobert Watson  * inter-process debugging has been involved in a variety of security
15213b243b72SRobert Watson  * problems, and sites not requiring the service might choose to disable it
15223b243b72SRobert Watson  * when hardening systems.
15233b243b72SRobert Watson  *
15243b243b72SRobert Watson  * XXX: Should modifying and reading this variable require locking?
15253b243b72SRobert Watson  */
15260ef5652eSRobert Watson static int	kern_unprivileged_procdebug_permitted = 1;
15270ef5652eSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, unprivileged_procdebug_permitted,
15280ef5652eSRobert Watson     CTLFLAG_RW, &kern_unprivileged_procdebug_permitted, 0,
15290ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
15300ef5652eSRobert Watson 
15317fd6a959SRobert Watson /*-
15327fd6a959SRobert Watson  * Determine whether p1 may debug p2.
15337fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
15347fd6a959SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
15357fd6a959SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
15367fd6a959SRobert Watson  *        be held for p2.
15373b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
15383b243b72SRobert Watson  */
1539a0f75161SRobert Watson int
1540a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2)
1541387d2c03SRobert Watson {
1542db42a33dSRobert Watson 	int error, i, grpsubset, uidsubset, credentialchanged;
1543387d2c03SRobert Watson 
154432d18604SRobert Watson 	if (!kern_unprivileged_procdebug_permitted) {
154532d18604SRobert Watson 		error = suser_xxx(NULL, p1, PRISON_ROOT);
154632d18604SRobert Watson 		if (error)
154732d18604SRobert Watson 			return (error);
154832d18604SRobert Watson 	}
154932d18604SRobert Watson 
155023fad5b6SDag-Erling Smørgrav 	if (p1 == p2)
155123fad5b6SDag-Erling Smørgrav 		return (0);
155223fad5b6SDag-Erling Smørgrav 
155391421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
155491421ba2SRobert Watson 		return (error);
1555387d2c03SRobert Watson 
15567fd6a959SRobert Watson 	/*
1557db42a33dSRobert Watson 	 * Is p2's group set a subset of p1's effective group set?  This
1558db42a33dSRobert Watson 	 * includes p2's egid, group access list, rgid, and svgid.
15597fd6a959SRobert Watson 	 */
1560db42a33dSRobert Watson 	grpsubset = 1;
1561db42a33dSRobert Watson 	for (i = 0; i < p2->p_ucred->cr_ngroups; i++) {
1562db42a33dSRobert Watson 		if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) {
1563db42a33dSRobert Watson 			grpsubset = 0;
1564db42a33dSRobert Watson 			break;
1565db42a33dSRobert Watson 		}
1566db42a33dSRobert Watson 	}
1567db42a33dSRobert Watson 	grpsubset = grpsubset &&
1568db42a33dSRobert Watson 	    groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) &&
1569db42a33dSRobert Watson 	    groupmember(p2->p_ucred->cr_svgid, p1->p_ucred);
1570db42a33dSRobert Watson 
1571db42a33dSRobert Watson 	/*
1572db42a33dSRobert Watson 	 * Are the uids present in p2's credential equal to p1's
1573db42a33dSRobert Watson 	 * effective uid?  This includes p2's euid, svuid, and ruid.
1574db42a33dSRobert Watson 	 */
1575db42a33dSRobert Watson 	uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid &&
1576db42a33dSRobert Watson 	    p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid &&
1577db42a33dSRobert Watson 	    p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid);
1578db42a33dSRobert Watson 
1579db42a33dSRobert Watson 	/*
1580db42a33dSRobert Watson 	 * Has the credential of the process changed since the last exec()?
1581db42a33dSRobert Watson 	 */
1582db42a33dSRobert Watson 	credentialchanged = (p2->p_flag & P_SUGID);
1583db42a33dSRobert Watson 
1584db42a33dSRobert Watson 	/*
1585db42a33dSRobert Watson 	 * If p2's gids aren't a subset, or the uids aren't a subset,
1586db42a33dSRobert Watson 	 * or the credential has changed, require appropriate privilege
1587db42a33dSRobert Watson 	 * for p1 to debug p2.  For POSIX.1e capabilities, this will
1588db42a33dSRobert Watson 	 * require CAP_SYS_PTRACE.
1589db42a33dSRobert Watson 	 */
1590db42a33dSRobert Watson 	if (!grpsubset || !uidsubset || credentialchanged) {
159132d18604SRobert Watson 		error = suser_xxx(NULL, p1, PRISON_ROOT);
159232d18604SRobert Watson 		if (error)
1593387d2c03SRobert Watson 			return (error);
15947fd6a959SRobert Watson 	}
1595387d2c03SRobert Watson 
15963ca719f1SRobert Watson 	/* can't trace init when securelevel > 0 */
15973ca719f1SRobert Watson 	if (p2->p_pid == 1) {
15983ca719f1SRobert Watson 		error = securelevel_gt(p1->p_ucred, 0);
15993ca719f1SRobert Watson 		if (error)
16003ca719f1SRobert Watson 			return (error);
16013ca719f1SRobert Watson 	}
1602387d2c03SRobert Watson 
16035fab7614SRobert Watson 	/*
16045fab7614SRobert Watson 	 * Can't trace a process that's currently exec'ing.
16055fab7614SRobert Watson 	 * XXX: Note, this is not a security policy decision, it's a
16065fab7614SRobert Watson 	 * basic correctness/functionality decision.  Therefore, this check
16075fab7614SRobert Watson 	 * should be moved to the caller's of p_candebug().
16085fab7614SRobert Watson 	 */
16099ca45e81SDag-Erling Smørgrav 	if ((p2->p_flag & P_INEXEC) != 0)
16109ca45e81SDag-Erling Smørgrav 		return (EAGAIN);
16119ca45e81SDag-Erling Smørgrav 
1612387d2c03SRobert Watson 	return (0);
1613387d2c03SRobert Watson }
1614387d2c03SRobert Watson 
1615a9e0361bSPoul-Henning Kamp /*
1616df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1617df8bae1dSRodney W. Grimes  */
1618df8bae1dSRodney W. Grimes struct ucred *
1619df8bae1dSRodney W. Grimes crget()
1620df8bae1dSRodney W. Grimes {
1621df8bae1dSRodney W. Grimes 	register struct ucred *cr;
1622df8bae1dSRodney W. Grimes 
16231e5d626aSAlfred Perlstein 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1624df8bae1dSRodney W. Grimes 	cr->cr_ref = 1;
16251e5d626aSAlfred Perlstein 	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
1626df8bae1dSRodney W. Grimes 	return (cr);
1627df8bae1dSRodney W. Grimes }
1628df8bae1dSRodney W. Grimes 
1629df8bae1dSRodney W. Grimes /*
16307fd6a959SRobert Watson  * Claim another reference to a ucred structure.
16315c3f70d7SAlfred Perlstein  */
1632bd78ceceSJohn Baldwin struct ucred *
16335c3f70d7SAlfred Perlstein crhold(cr)
16345c3f70d7SAlfred Perlstein 	struct ucred *cr;
16355c3f70d7SAlfred Perlstein {
16365c3f70d7SAlfred Perlstein 
16379ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
16385c3f70d7SAlfred Perlstein 	cr->cr_ref++;
1639bd78ceceSJohn Baldwin 	mtx_unlock(&cr->cr_mtx);
1640bd78ceceSJohn Baldwin 	return (cr);
16415c3f70d7SAlfred Perlstein }
16425c3f70d7SAlfred Perlstein 
16435c3f70d7SAlfred Perlstein 
16445c3f70d7SAlfred Perlstein /*
1645df8bae1dSRodney W. Grimes  * Free a cred structure.
1646df8bae1dSRodney W. Grimes  * Throws away space when ref count gets to 0.
1647df8bae1dSRodney W. Grimes  */
164826f9a767SRodney W. Grimes void
1649df8bae1dSRodney W. Grimes crfree(cr)
1650df8bae1dSRodney W. Grimes 	struct ucred *cr;
1651df8bae1dSRodney W. Grimes {
16521e5d626aSAlfred Perlstein 
16539ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
1654e04670b7SAlfred Perlstein 	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1655f535380cSDon Lewis 	if (--cr->cr_ref == 0) {
16561e5d626aSAlfred Perlstein 		mtx_destroy(&cr->cr_mtx);
1657f535380cSDon Lewis 		/*
1658f535380cSDon Lewis 		 * Some callers of crget(), such as nfs_statfs(),
1659f535380cSDon Lewis 		 * allocate a temporary credential, but don't
1660f535380cSDon Lewis 		 * allocate a uidinfo structure.
1661f535380cSDon Lewis 		 */
1662f535380cSDon Lewis 		if (cr->cr_uidinfo != NULL)
1663f535380cSDon Lewis 			uifree(cr->cr_uidinfo);
1664823c224eSRobert Watson 		if (cr->cr_ruidinfo != NULL)
1665823c224eSRobert Watson 			uifree(cr->cr_ruidinfo);
166691421ba2SRobert Watson 		/*
166791421ba2SRobert Watson 		 * Free a prison, if any.
166891421ba2SRobert Watson 		 */
166991421ba2SRobert Watson 		if (jailed(cr))
167091421ba2SRobert Watson 			prison_free(cr->cr_prison);
1671df8bae1dSRodney W. Grimes 		FREE((caddr_t)cr, M_CRED);
16721e5d626aSAlfred Perlstein 	} else {
16739ed346baSBosko Milekic 		mtx_unlock(&cr->cr_mtx);
1674df8bae1dSRodney W. Grimes 	}
1675f535380cSDon Lewis }
1676df8bae1dSRodney W. Grimes 
1677df8bae1dSRodney W. Grimes /*
1678bd78ceceSJohn Baldwin  * Check to see if this ucred is shared.
1679df8bae1dSRodney W. Grimes  */
1680bd78ceceSJohn Baldwin int
1681bd78ceceSJohn Baldwin crshared(cr)
1682df8bae1dSRodney W. Grimes 	struct ucred *cr;
1683df8bae1dSRodney W. Grimes {
1684bd78ceceSJohn Baldwin 	int shared;
1685df8bae1dSRodney W. Grimes 
16869ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
1687bd78ceceSJohn Baldwin 	shared = (cr->cr_ref > 1);
16889ed346baSBosko Milekic 	mtx_unlock(&cr->cr_mtx);
1689bd78ceceSJohn Baldwin 	return (shared);
16901e5d626aSAlfred Perlstein }
1691bd78ceceSJohn Baldwin 
1692bd78ceceSJohn Baldwin /*
1693bd78ceceSJohn Baldwin  * Copy a ucred's contents from a template.  Does not block.
1694bd78ceceSJohn Baldwin  */
1695bd78ceceSJohn Baldwin void
1696bd78ceceSJohn Baldwin crcopy(dest, src)
1697bd78ceceSJohn Baldwin 	struct ucred *dest, *src;
1698bd78ceceSJohn Baldwin {
1699bd78ceceSJohn Baldwin 
1700bd78ceceSJohn Baldwin 	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
1701bd78ceceSJohn Baldwin 	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
1702bd78ceceSJohn Baldwin 	    (unsigned)((caddr_t)&src->cr_endcopy -
1703bd78ceceSJohn Baldwin 		(caddr_t)&src->cr_startcopy));
1704bd78ceceSJohn Baldwin 	uihold(dest->cr_uidinfo);
1705bd78ceceSJohn Baldwin 	uihold(dest->cr_ruidinfo);
1706bd78ceceSJohn Baldwin 	if (jailed(dest))
1707bd78ceceSJohn Baldwin 		prison_hold(dest->cr_prison);
1708df8bae1dSRodney W. Grimes }
1709df8bae1dSRodney W. Grimes 
1710df8bae1dSRodney W. Grimes /*
1711df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
1712df8bae1dSRodney W. Grimes  */
1713df8bae1dSRodney W. Grimes struct ucred *
1714df8bae1dSRodney W. Grimes crdup(cr)
1715df8bae1dSRodney W. Grimes 	struct ucred *cr;
1716df8bae1dSRodney W. Grimes {
1717df8bae1dSRodney W. Grimes 	struct ucred *newcr;
1718df8bae1dSRodney W. Grimes 
1719bd78ceceSJohn Baldwin 	newcr = crget();
1720bd78ceceSJohn Baldwin 	crcopy(newcr, cr);
1721df8bae1dSRodney W. Grimes 	return (newcr);
1722df8bae1dSRodney W. Grimes }
1723df8bae1dSRodney W. Grimes 
1724df8bae1dSRodney W. Grimes /*
1725df8bae1dSRodney W. Grimes  * Get login name, if available.
1726df8bae1dSRodney W. Grimes  */
1727d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1728df8bae1dSRodney W. Grimes struct getlogin_args {
1729df8bae1dSRodney W. Grimes 	char	*namebuf;
1730df8bae1dSRodney W. Grimes 	u_int	namelen;
1731df8bae1dSRodney W. Grimes };
1732d2d3e875SBruce Evans #endif
1733835a82eeSMatthew Dillon /*
1734835a82eeSMatthew Dillon  * MPSAFE
1735835a82eeSMatthew Dillon  */
1736df8bae1dSRodney W. Grimes /* ARGSUSED */
173726f9a767SRodney W. Grimes int
1738b40ce416SJulian Elischer getlogin(td, uap)
1739b40ce416SJulian Elischer 	struct thread *td;
1740df8bae1dSRodney W. Grimes 	struct getlogin_args *uap;
1741df8bae1dSRodney W. Grimes {
1742835a82eeSMatthew Dillon 	int error;
1743b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1744df8bae1dSRodney W. Grimes 
1745835a82eeSMatthew Dillon 	mtx_lock(&Giant);
174630cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
174753490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
1748835a82eeSMatthew Dillon 	error = copyout((caddr_t) p->p_pgrp->pg_session->s_login,
1749835a82eeSMatthew Dillon 	    (caddr_t) uap->namebuf, uap->namelen);
1750835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1751835a82eeSMatthew Dillon 	return(error);
1752df8bae1dSRodney W. Grimes }
1753df8bae1dSRodney W. Grimes 
1754df8bae1dSRodney W. Grimes /*
1755df8bae1dSRodney W. Grimes  * Set login name.
1756df8bae1dSRodney W. Grimes  */
1757d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1758df8bae1dSRodney W. Grimes struct setlogin_args {
1759df8bae1dSRodney W. Grimes 	char	*namebuf;
1760df8bae1dSRodney W. Grimes };
1761d2d3e875SBruce Evans #endif
1762835a82eeSMatthew Dillon /*
1763835a82eeSMatthew Dillon  * MPSAFE
1764835a82eeSMatthew Dillon  */
1765df8bae1dSRodney W. Grimes /* ARGSUSED */
176626f9a767SRodney W. Grimes int
1767b40ce416SJulian Elischer setlogin(td, uap)
1768b40ce416SJulian Elischer 	struct thread *td;
1769df8bae1dSRodney W. Grimes 	struct setlogin_args *uap;
1770df8bae1dSRodney W. Grimes {
1771b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1772df8bae1dSRodney W. Grimes 	int error;
1773964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
1774df8bae1dSRodney W. Grimes 
1775835a82eeSMatthew Dillon 	mtx_lock(&Giant);
177675c13541SPoul-Henning Kamp 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
1777835a82eeSMatthew Dillon 		goto done2;
1778184989c2SDavid Nugent 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
177910d4743fSDoug Rabson 	    sizeof(logintmp), (size_t *)0);
1780835a82eeSMatthew Dillon 	if (error == ENAMETOOLONG) {
1781df8bae1dSRodney W. Grimes 		error = EINVAL;
1782835a82eeSMatthew Dillon 	} else if (!error) {
1783184989c2SDavid Nugent 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
1784964ca0caSAndrey A. Chernov 		    sizeof(logintmp));
1785835a82eeSMatthew Dillon 	}
1786835a82eeSMatthew Dillon done2:
1787835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1788df8bae1dSRodney W. Grimes 	return (error);
1789df8bae1dSRodney W. Grimes }
1790d5f81602SSean Eric Fagan 
1791d5f81602SSean Eric Fagan void
1792d5f81602SSean Eric Fagan setsugid(p)
1793d5f81602SSean Eric Fagan 	struct proc *p;
1794d5f81602SSean Eric Fagan {
1795d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
179689361835SSean Eric Fagan 	if (!(p->p_pfsflags & PF_ISUGID))
1797d5f81602SSean Eric Fagan 		p->p_stops = 0;
1798d5f81602SSean Eric Fagan }
1799f535380cSDon Lewis 
18007fd6a959SRobert Watson /*-
18017fd6a959SRobert Watson  * Change a process's effective uid.
1802b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
1803b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1804b1fc0ec1SRobert Watson  *             duration of the call.
1805f535380cSDon Lewis  */
1806f535380cSDon Lewis void
1807b1fc0ec1SRobert Watson change_euid(newcred, euid)
1808b1fc0ec1SRobert Watson 	struct ucred *newcred;
1809f535380cSDon Lewis 	uid_t euid;
1810f535380cSDon Lewis {
1811f535380cSDon Lewis 
1812b1fc0ec1SRobert Watson 	newcred->cr_uid = euid;
1813b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
1814b1fc0ec1SRobert Watson 	newcred->cr_uidinfo = uifind(euid);
1815f535380cSDon Lewis }
1816f535380cSDon Lewis 
18177fd6a959SRobert Watson /*-
18187fd6a959SRobert Watson  * Change a process's effective gid.
1819b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
1820b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1821b1fc0ec1SRobert Watson  *             duration of the call.
1822f535380cSDon Lewis  */
1823810bfc8eSAndrew Gallatin void
1824b1fc0ec1SRobert Watson change_egid(newcred, egid)
1825b1fc0ec1SRobert Watson 	struct ucred *newcred;
1826b1fc0ec1SRobert Watson 	gid_t egid;
1827b1fc0ec1SRobert Watson {
1828b1fc0ec1SRobert Watson 
1829b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
1830b1fc0ec1SRobert Watson }
1831b1fc0ec1SRobert Watson 
18327fd6a959SRobert Watson /*-
18337fd6a959SRobert Watson  * Change a process's real uid.
1834b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
1835b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
1836b1fc0ec1SRobert Watson  *               counts will be updated.
1837b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1838b1fc0ec1SRobert Watson  *             duration of the call.
1839b1fc0ec1SRobert Watson  */
1840b1fc0ec1SRobert Watson void
1841b1fc0ec1SRobert Watson change_ruid(newcred, ruid)
1842b1fc0ec1SRobert Watson 	struct ucred *newcred;
1843f535380cSDon Lewis 	uid_t ruid;
1844f535380cSDon Lewis {
1845f535380cSDon Lewis 
1846b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
1847b1fc0ec1SRobert Watson 	newcred->cr_ruid = ruid;
1848b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
1849b1fc0ec1SRobert Watson 	newcred->cr_ruidinfo = uifind(ruid);
1850b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
1851b1fc0ec1SRobert Watson }
1852b1fc0ec1SRobert Watson 
18537fd6a959SRobert Watson /*-
18547fd6a959SRobert Watson  * Change a process's real gid.
1855b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
1856b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1857b1fc0ec1SRobert Watson  *             duration of the call.
1858b1fc0ec1SRobert Watson  */
1859b1fc0ec1SRobert Watson void
1860b1fc0ec1SRobert Watson change_rgid(newcred, rgid)
1861b1fc0ec1SRobert Watson 	struct ucred *newcred;
1862b1fc0ec1SRobert Watson 	gid_t rgid;
1863b1fc0ec1SRobert Watson {
1864b1fc0ec1SRobert Watson 
1865b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
1866b1fc0ec1SRobert Watson }
1867b1fc0ec1SRobert Watson 
18687fd6a959SRobert Watson /*-
18697fd6a959SRobert Watson  * Change a process's saved uid.
1870b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
1871b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1872b1fc0ec1SRobert Watson  *             duration of the call.
1873b1fc0ec1SRobert Watson  */
1874b1fc0ec1SRobert Watson void
1875b1fc0ec1SRobert Watson change_svuid(newcred, svuid)
1876b1fc0ec1SRobert Watson 	struct ucred *newcred;
1877b1fc0ec1SRobert Watson 	uid_t svuid;
1878b1fc0ec1SRobert Watson {
1879b1fc0ec1SRobert Watson 
1880b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
1881b1fc0ec1SRobert Watson }
1882b1fc0ec1SRobert Watson 
18837fd6a959SRobert Watson /*-
18847fd6a959SRobert Watson  * Change a process's saved gid.
1885b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
1886b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1887b1fc0ec1SRobert Watson  *             duration of the call.
1888b1fc0ec1SRobert Watson  */
1889b1fc0ec1SRobert Watson void
1890b1fc0ec1SRobert Watson change_svgid(newcred, svgid)
1891b1fc0ec1SRobert Watson 	struct ucred *newcred;
1892b1fc0ec1SRobert Watson 	gid_t svgid;
1893b1fc0ec1SRobert Watson {
1894b1fc0ec1SRobert Watson 
1895b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
1896f535380cSDon Lewis }
1897