xref: /freebsd/sys/kern/kern_prot.c (revision 87fce2bb963f92a6bcea1846cd3d5f0a07cde904)
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.
43b243b72SRobert Watson  * Copyright (c) 2000, 2001 Robert N. M. Watson.  All rights reserved.
5df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
6df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
7df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
8df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
9df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
10df8bae1dSRodney W. Grimes  *
11df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
12df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
13df8bae1dSRodney W. Grimes  * are met:
14df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
16df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
18df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
20df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
21df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
22df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
23df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
40c3aac50fSPeter Wemm  * $FreeBSD$
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes /*
44df8bae1dSRodney W. Grimes  * System calls related to processes and protection
45df8bae1dSRodney W. Grimes  */
46df8bae1dSRodney W. Grimes 
475591b823SEivind Eklund #include "opt_compat.h"
48130d0157SRobert Watson #include "opt_global.h"
495591b823SEivind Eklund 
50df8bae1dSRodney W. Grimes #include <sys/param.h>
51df8bae1dSRodney W. Grimes #include <sys/systm.h>
52fb919e4dSMark Murray #include <sys/acct.h>
531c5bb3eaSPeter Wemm #include <sys/kernel.h>
5498f03f90SJake Burkholder #include <sys/lock.h>
55fb919e4dSMark Murray #include <sys/mutex.h>
56df8bae1dSRodney W. Grimes #include <sys/proc.h>
57fb919e4dSMark Murray #include <sys/sysproto.h>
58df8bae1dSRodney W. Grimes #include <sys/malloc.h>
59d5f81602SSean Eric Fagan #include <sys/pioctl.h>
60f535380cSDon Lewis #include <sys/resourcevar.h>
61579f4eb4SRobert Watson #include <sys/sysctl.h>
6291421ba2SRobert Watson #include <sys/jail.h>
63df8bae1dSRodney W. Grimes 
64a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
65a1c995b6SPoul-Henning Kamp 
660ef5652eSRobert Watson SYSCTL_NODE(_kern, OID_AUTO, security, CTLFLAG_RW, 0,
670ef5652eSRobert Watson     "Kernel security policy");
680ef5652eSRobert Watson 
69d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
70ad7507e2SSteven Wallace struct getpid_args {
71df8bae1dSRodney W. Grimes 	int	dummy;
72df8bae1dSRodney W. Grimes };
73d2d3e875SBruce Evans #endif
74df8bae1dSRodney W. Grimes 
7536e9f877SMatthew Dillon /*
76835a82eeSMatthew Dillon  * getpid
7736e9f877SMatthew Dillon  */
7898f03f90SJake Burkholder 
79835a82eeSMatthew Dillon /*
80835a82eeSMatthew Dillon  * MPSAFE
81835a82eeSMatthew Dillon  */
82df8bae1dSRodney W. Grimes /* ARGSUSED */
8326f9a767SRodney W. Grimes int
84b40ce416SJulian Elischer getpid(td, uap)
85b40ce416SJulian Elischer 	struct thread *td;
86ad7507e2SSteven Wallace 	struct getpid_args *uap;
87df8bae1dSRodney W. Grimes {
88b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
89df8bae1dSRodney W. Grimes 
90835a82eeSMatthew Dillon 	mtx_lock(&Giant);
91b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pid;
92df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
93bae3a80bSJohn Baldwin 	PROC_LOCK(p);
94b40ce416SJulian Elischer 	td->td_retval[1] = p->p_pptr->p_pid;
95bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
96df8bae1dSRodney W. Grimes #endif
97835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
98df8bae1dSRodney W. Grimes 	return (0);
99df8bae1dSRodney W. Grimes }
100df8bae1dSRodney W. Grimes 
10198f03f90SJake Burkholder /*
102835a82eeSMatthew Dillon  * getppid
10398f03f90SJake Burkholder  */
10498f03f90SJake Burkholder 
105d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
106ad7507e2SSteven Wallace struct getppid_args {
107ad7507e2SSteven Wallace         int     dummy;
108ad7507e2SSteven Wallace };
109d2d3e875SBruce Evans #endif
110835a82eeSMatthew Dillon /*
111835a82eeSMatthew Dillon  * MPSAFE
112835a82eeSMatthew Dillon  */
113df8bae1dSRodney W. Grimes /* ARGSUSED */
11426f9a767SRodney W. Grimes int
115b40ce416SJulian Elischer getppid(td, uap)
116b40ce416SJulian Elischer 	struct thread *td;
117ad7507e2SSteven Wallace 	struct getppid_args *uap;
118df8bae1dSRodney W. Grimes {
119b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
120df8bae1dSRodney W. Grimes 
121835a82eeSMatthew Dillon 	mtx_lock(&Giant);
122bae3a80bSJohn Baldwin 	PROC_LOCK(p);
123b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pptr->p_pid;
124bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
125835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
126df8bae1dSRodney W. Grimes 	return (0);
127df8bae1dSRodney W. Grimes }
128df8bae1dSRodney W. Grimes 
12936e9f877SMatthew Dillon /*
13036e9f877SMatthew Dillon  * Get process group ID; note that POSIX getpgrp takes no parameter
13136e9f877SMatthew Dillon  *
13236e9f877SMatthew Dillon  * MP SAFE
13336e9f877SMatthew Dillon  */
134d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
135ad7507e2SSteven Wallace struct getpgrp_args {
136ad7507e2SSteven Wallace         int     dummy;
137ad7507e2SSteven Wallace };
138d2d3e875SBruce Evans #endif
139835a82eeSMatthew Dillon /*
140835a82eeSMatthew Dillon  * MPSAFE
141835a82eeSMatthew Dillon  */
14226f9a767SRodney W. Grimes int
143b40ce416SJulian Elischer getpgrp(td, uap)
144b40ce416SJulian Elischer 	struct thread *td;
145ad7507e2SSteven Wallace 	struct getpgrp_args *uap;
146df8bae1dSRodney W. Grimes {
147b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
148df8bae1dSRodney W. Grimes 
149835a82eeSMatthew Dillon 	mtx_lock(&Giant);
150b40ce416SJulian Elischer 	td->td_retval[0] = p->p_pgrp->pg_id;
151835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
152df8bae1dSRodney W. Grimes 	return (0);
153df8bae1dSRodney W. Grimes }
154df8bae1dSRodney W. Grimes 
1551a5018a0SPeter Wemm /* Get an arbitary pid's process group id */
1561a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1571a5018a0SPeter Wemm struct getpgid_args {
1581a5018a0SPeter Wemm 	pid_t	pid;
1591a5018a0SPeter Wemm };
1601a5018a0SPeter Wemm #endif
1611a5018a0SPeter Wemm 
162835a82eeSMatthew Dillon /*
163835a82eeSMatthew Dillon  * MPSAFE
164835a82eeSMatthew Dillon  */
1651a5018a0SPeter Wemm int
166b40ce416SJulian Elischer getpgid(td, uap)
167b40ce416SJulian Elischer 	struct thread *td;
1681a5018a0SPeter Wemm 	struct getpgid_args *uap;
1691a5018a0SPeter Wemm {
170b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
17165de0c7aSDon Lewis 	struct proc *pt;
172835a82eeSMatthew Dillon 	int error = 0;
17365de0c7aSDon Lewis 
174835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1751a5018a0SPeter Wemm 	if (uap->pid == 0)
176b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pgrp->pg_id;
17733a9ed9dSJohn Baldwin 	else {
178835a82eeSMatthew Dillon 		if ((pt = pfind(uap->pid)) == NULL) {
179835a82eeSMatthew Dillon 			error = ESRCH;
180835a82eeSMatthew Dillon 			goto done2;
181835a82eeSMatthew Dillon 		}
182a0f75161SRobert Watson 		if ((error = p_cansee(p, pt))) {
18333a9ed9dSJohn Baldwin 			PROC_UNLOCK(pt);
184835a82eeSMatthew Dillon 			goto done2;
18533a9ed9dSJohn Baldwin 		}
186b40ce416SJulian Elischer 		td->td_retval[0] = pt->p_pgrp->pg_id;
18733a9ed9dSJohn Baldwin 		PROC_UNLOCK(pt);
18833a9ed9dSJohn Baldwin 	}
189835a82eeSMatthew Dillon done2:
190835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
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);
216835a82eeSMatthew Dillon 	if (uap->pid == 0) {
217b40ce416SJulian Elischer 		td->td_retval[0] = p->p_session->s_sid;
218835a82eeSMatthew Dillon 	} else {
219835a82eeSMatthew Dillon 		if ((pt = pfind(uap->pid)) == NULL) {
220835a82eeSMatthew Dillon 			error = ESRCH;
221835a82eeSMatthew Dillon 			goto done2;
222835a82eeSMatthew Dillon 		}
223a0f75161SRobert Watson 		if ((error = p_cansee(p, pt))) {
22433a9ed9dSJohn Baldwin 			PROC_UNLOCK(pt);
225835a82eeSMatthew Dillon 			goto done2;
22633a9ed9dSJohn Baldwin 		}
227b40ce416SJulian Elischer 		td->td_retval[0] = pt->p_session->s_sid;
22833a9ed9dSJohn Baldwin 		PROC_UNLOCK(pt);
22933a9ed9dSJohn Baldwin 	}
230835a82eeSMatthew Dillon done2:
231835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
232835a82eeSMatthew Dillon 	return (error);
2331a5018a0SPeter Wemm }
2341a5018a0SPeter Wemm 
2351a5018a0SPeter Wemm 
2367c8fdcbdSMatthew Dillon /*
2377c8fdcbdSMatthew Dillon  * getuid() - MP SAFE
2387c8fdcbdSMatthew Dillon  */
239d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
240ad7507e2SSteven Wallace struct getuid_args {
241ad7507e2SSteven Wallace         int     dummy;
242ad7507e2SSteven Wallace };
243d2d3e875SBruce Evans #endif
244ad7507e2SSteven Wallace 
245835a82eeSMatthew Dillon /*
246835a82eeSMatthew Dillon  * MPSAFE
247835a82eeSMatthew Dillon  */
248df8bae1dSRodney W. Grimes /* ARGSUSED */
24926f9a767SRodney W. Grimes int
250b40ce416SJulian Elischer getuid(td, uap)
251b40ce416SJulian Elischer 	struct thread *td;
252ad7507e2SSteven Wallace 	struct getuid_args *uap;
253df8bae1dSRodney W. Grimes {
254b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
255df8bae1dSRodney W. Grimes 
256835a82eeSMatthew Dillon 	mtx_lock(&Giant);
257b40ce416SJulian Elischer 	td->td_retval[0] = p->p_ucred->cr_ruid;
258df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
259b40ce416SJulian Elischer 	td->td_retval[1] = p->p_ucred->cr_uid;
260df8bae1dSRodney W. Grimes #endif
261835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
262df8bae1dSRodney W. Grimes 	return (0);
263df8bae1dSRodney W. Grimes }
264df8bae1dSRodney W. Grimes 
2657c8fdcbdSMatthew Dillon /*
2667c8fdcbdSMatthew Dillon  * geteuid() - MP SAFE
2677c8fdcbdSMatthew Dillon  */
268d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
269ad7507e2SSteven Wallace struct geteuid_args {
270ad7507e2SSteven Wallace         int     dummy;
271ad7507e2SSteven Wallace };
272d2d3e875SBruce Evans #endif
273ad7507e2SSteven Wallace 
274df8bae1dSRodney W. Grimes /* ARGSUSED */
27526f9a767SRodney W. Grimes int
276b40ce416SJulian Elischer geteuid(td, uap)
277b40ce416SJulian Elischer 	struct thread *td;
278ad7507e2SSteven Wallace 	struct geteuid_args *uap;
279df8bae1dSRodney W. Grimes {
280835a82eeSMatthew Dillon 	mtx_lock(&Giant);
281b40ce416SJulian Elischer 	td->td_retval[0] = td->td_proc->p_ucred->cr_uid;
282835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
283df8bae1dSRodney W. Grimes 	return (0);
284df8bae1dSRodney W. Grimes }
285df8bae1dSRodney W. Grimes 
2867c8fdcbdSMatthew Dillon /*
2877c8fdcbdSMatthew Dillon  * getgid() - MP SAFE
2887c8fdcbdSMatthew Dillon  */
289d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
290ad7507e2SSteven Wallace struct getgid_args {
291ad7507e2SSteven Wallace         int     dummy;
292ad7507e2SSteven Wallace };
293d2d3e875SBruce Evans #endif
294ad7507e2SSteven Wallace 
295835a82eeSMatthew Dillon /*
296835a82eeSMatthew Dillon  * MPSAFE
297835a82eeSMatthew Dillon  */
298df8bae1dSRodney W. Grimes /* ARGSUSED */
29926f9a767SRodney W. Grimes int
300b40ce416SJulian Elischer getgid(td, uap)
301b40ce416SJulian Elischer 	struct thread *td;
302ad7507e2SSteven Wallace 	struct getgid_args *uap;
303df8bae1dSRodney W. Grimes {
304b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
305df8bae1dSRodney W. Grimes 
306835a82eeSMatthew Dillon 	mtx_lock(&Giant);
307b40ce416SJulian Elischer 	td->td_retval[0] = p->p_ucred->cr_rgid;
308df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
309b40ce416SJulian Elischer 	td->td_retval[1] = p->p_ucred->cr_groups[0];
310df8bae1dSRodney W. Grimes #endif
311835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
312df8bae1dSRodney W. Grimes 	return (0);
313df8bae1dSRodney W. Grimes }
314df8bae1dSRodney W. Grimes 
315df8bae1dSRodney W. Grimes /*
316df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
317df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
318df8bae1dSRodney W. Grimes  * correctly in a library function.
319df8bae1dSRodney W. Grimes  */
320d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
321ad7507e2SSteven Wallace struct getegid_args {
322ad7507e2SSteven Wallace         int     dummy;
323ad7507e2SSteven Wallace };
324d2d3e875SBruce Evans #endif
325ad7507e2SSteven Wallace 
326835a82eeSMatthew Dillon /*
327835a82eeSMatthew Dillon  * MPSAFE
328835a82eeSMatthew Dillon  */
329df8bae1dSRodney W. Grimes /* ARGSUSED */
33026f9a767SRodney W. Grimes int
331b40ce416SJulian Elischer getegid(td, uap)
332b40ce416SJulian Elischer 	struct thread *td;
333ad7507e2SSteven Wallace 	struct getegid_args *uap;
334df8bae1dSRodney W. Grimes {
335b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
336df8bae1dSRodney W. Grimes 
337835a82eeSMatthew Dillon 	mtx_lock(&Giant);
338b40ce416SJulian Elischer 	td->td_retval[0] = p->p_ucred->cr_groups[0];
339835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
340df8bae1dSRodney W. Grimes 	return (0);
341df8bae1dSRodney W. Grimes }
342df8bae1dSRodney W. Grimes 
343d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
344df8bae1dSRodney W. Grimes struct getgroups_args {
345df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
346df8bae1dSRodney W. Grimes 	gid_t	*gidset;
347df8bae1dSRodney W. Grimes };
348d2d3e875SBruce Evans #endif
349835a82eeSMatthew Dillon /*
350835a82eeSMatthew Dillon  * MPSAFE
351835a82eeSMatthew Dillon  */
35226f9a767SRodney W. Grimes int
353b40ce416SJulian Elischer getgroups(td, uap)
354b40ce416SJulian Elischer 	struct thread *td;
355df8bae1dSRodney W. Grimes 	register struct	getgroups_args *uap;
356df8bae1dSRodney W. Grimes {
357835a82eeSMatthew Dillon 	struct ucred *cred;
358b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
359b1fc0ec1SRobert Watson 	u_int ngrp;
360835a82eeSMatthew Dillon 	int error = 0;
361df8bae1dSRodney W. Grimes 
362835a82eeSMatthew Dillon 	mtx_lock(&Giant);
363835a82eeSMatthew Dillon 	cred = p->p_ucred;
364df8bae1dSRodney W. Grimes 	if ((ngrp = uap->gidsetsize) == 0) {
365b40ce416SJulian Elischer 		td->td_retval[0] = cred->cr_ngroups;
366835a82eeSMatthew Dillon 		error = 0;
367835a82eeSMatthew Dillon 		goto done2;
368df8bae1dSRodney W. Grimes 	}
369835a82eeSMatthew Dillon 	if (ngrp < cred->cr_ngroups) {
370835a82eeSMatthew Dillon 		error = EINVAL;
371835a82eeSMatthew Dillon 		goto done2;
372835a82eeSMatthew Dillon 	}
373b1fc0ec1SRobert Watson 	ngrp = cred->cr_ngroups;
374b1fc0ec1SRobert Watson 	if ((error = copyout((caddr_t)cred->cr_groups,
375835a82eeSMatthew Dillon 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) {
376835a82eeSMatthew Dillon 		goto done2;
377835a82eeSMatthew Dillon 	}
378b40ce416SJulian Elischer 	td->td_retval[0] = ngrp;
379835a82eeSMatthew Dillon done2:
380835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
381835a82eeSMatthew Dillon 	return (error);
382df8bae1dSRodney W. Grimes }
383df8bae1dSRodney W. Grimes 
384d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
38582970b81SBruce Evans struct setsid_args {
386ad7507e2SSteven Wallace         int     dummy;
387ad7507e2SSteven Wallace };
388d2d3e875SBruce Evans #endif
389ad7507e2SSteven Wallace 
390835a82eeSMatthew Dillon /*
391835a82eeSMatthew Dillon  * MPSAFE
392835a82eeSMatthew Dillon  */
393df8bae1dSRodney W. Grimes /* ARGSUSED */
39426f9a767SRodney W. Grimes int
395b40ce416SJulian Elischer setsid(td, uap)
396b40ce416SJulian Elischer 	register struct thread *td;
39782970b81SBruce Evans 	struct setsid_args *uap;
398df8bae1dSRodney W. Grimes {
399835a82eeSMatthew Dillon 	int error;
400b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
401df8bae1dSRodney W. Grimes 
402835a82eeSMatthew Dillon 	mtx_lock(&Giant);
403df8bae1dSRodney W. Grimes 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
404835a82eeSMatthew Dillon 		error = EPERM;
405df8bae1dSRodney W. Grimes 	} else {
406df8bae1dSRodney W. Grimes 		(void)enterpgrp(p, p->p_pid, 1);
407b40ce416SJulian Elischer 		td->td_retval[0] = p->p_pid;
408835a82eeSMatthew Dillon 		error = 0;
409df8bae1dSRodney W. Grimes 	}
410835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
411835a82eeSMatthew Dillon 	return (error);
412df8bae1dSRodney W. Grimes }
413df8bae1dSRodney W. Grimes 
414df8bae1dSRodney W. Grimes /*
415df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
416df8bae1dSRodney W. Grimes  *
417df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
418df8bae1dSRodney W. Grimes  *
419df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
420df8bae1dSRodney W. Grimes  * if a child
421df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
422df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
423df8bae1dSRodney W. Grimes  * if pgid != pid
424df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
425df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
426df8bae1dSRodney W. Grimes  */
427d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
428df8bae1dSRodney W. Grimes struct setpgid_args {
429df8bae1dSRodney W. Grimes 	int	pid;	/* target process id */
430df8bae1dSRodney W. Grimes 	int	pgid;	/* target pgrp id */
431df8bae1dSRodney W. Grimes };
432d2d3e875SBruce Evans #endif
433835a82eeSMatthew Dillon /*
434835a82eeSMatthew Dillon  * MPSAFE
435835a82eeSMatthew Dillon  */
436df8bae1dSRodney W. Grimes /* ARGSUSED */
43726f9a767SRodney W. Grimes int
438b40ce416SJulian Elischer setpgid(td, uap)
439b40ce416SJulian Elischer 	struct thread *td;
440df8bae1dSRodney W. Grimes 	register struct setpgid_args *uap;
441df8bae1dSRodney W. Grimes {
442b40ce416SJulian Elischer 	struct proc *curp = td->td_proc;
443df8bae1dSRodney W. Grimes 	register struct proc *targp;		/* target process */
444df8bae1dSRodney W. Grimes 	register struct pgrp *pgrp;		/* target pgrp */
445eb9e5c1dSRobert Watson 	int error;
446df8bae1dSRodney W. Grimes 
44778f64bccSBruce Evans 	if (uap->pgid < 0)
44878f64bccSBruce Evans 		return (EINVAL);
449835a82eeSMatthew Dillon 
450835a82eeSMatthew Dillon 	mtx_lock(&Giant);
451835a82eeSMatthew Dillon 
452df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
45333a9ed9dSJohn Baldwin 		if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
45433a9ed9dSJohn Baldwin 			if (targp)
45533a9ed9dSJohn Baldwin 				PROC_UNLOCK(targp);
456835a82eeSMatthew Dillon 			error = ESRCH;
457835a82eeSMatthew Dillon 			goto done2;
45833a9ed9dSJohn Baldwin 		}
459a0f75161SRobert Watson 		if ((error = p_cansee(curproc, targp))) {
46033a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
461835a82eeSMatthew Dillon 			goto done2;
46233a9ed9dSJohn Baldwin 		}
46333a9ed9dSJohn Baldwin 		if (targp->p_pgrp == NULL ||
46433a9ed9dSJohn Baldwin 		    targp->p_session != curp->p_session) {
46533a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
466835a82eeSMatthew Dillon 			error = EPERM;
467835a82eeSMatthew Dillon 			goto done2;
46833a9ed9dSJohn Baldwin 		}
46933a9ed9dSJohn Baldwin 		if (targp->p_flag & P_EXEC) {
47033a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
471835a82eeSMatthew Dillon 			error = EACCES;
472835a82eeSMatthew Dillon 			goto done2;
47333a9ed9dSJohn Baldwin 		}
47433a9ed9dSJohn Baldwin 	} else {
475df8bae1dSRodney W. Grimes 		targp = curp;
47633a9ed9dSJohn Baldwin 		PROC_LOCK(curp);	/* XXX: not needed */
47733a9ed9dSJohn Baldwin 	}
47833a9ed9dSJohn Baldwin 	if (SESS_LEADER(targp)) {
47933a9ed9dSJohn Baldwin 		PROC_UNLOCK(targp);
480835a82eeSMatthew Dillon 		error = EPERM;
481835a82eeSMatthew Dillon 		goto done2;
48233a9ed9dSJohn Baldwin 	}
483835a82eeSMatthew Dillon 	if (uap->pgid == 0) {
484df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
485835a82eeSMatthew Dillon 	} else if (uap->pgid != targp->p_pid) {
486df8bae1dSRodney W. Grimes 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
48733a9ed9dSJohn Baldwin 	            pgrp->pg_session != curp->p_session) {
48833a9ed9dSJohn Baldwin 			PROC_UNLOCK(targp);
489835a82eeSMatthew Dillon 			error = EPERM;
490835a82eeSMatthew Dillon 			goto done2;
491835a82eeSMatthew Dillon 		}
49233a9ed9dSJohn Baldwin 	}
49333a9ed9dSJohn Baldwin 	/* XXX: We should probably hold the lock across enterpgrp. */
49433a9ed9dSJohn Baldwin 	PROC_UNLOCK(targp);
495835a82eeSMatthew Dillon 	error = enterpgrp(targp, uap->pgid, 0);
496835a82eeSMatthew Dillon done2:
497835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
498835a82eeSMatthew Dillon 	return (error);
499df8bae1dSRodney W. Grimes }
500df8bae1dSRodney W. Grimes 
501a08f4bf6SPeter Wemm /*
502a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
5032fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
504a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
505a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
506a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
507a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
508a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
509a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
510a08f4bf6SPeter Wemm  */
511a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
512a08f4bf6SPeter Wemm 
513d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
514df8bae1dSRodney W. Grimes struct setuid_args {
515df8bae1dSRodney W. Grimes 	uid_t	uid;
516df8bae1dSRodney W. Grimes };
517d2d3e875SBruce Evans #endif
518835a82eeSMatthew Dillon /*
519835a82eeSMatthew Dillon  * MPSAFE
520835a82eeSMatthew Dillon  */
521df8bae1dSRodney W. Grimes /* ARGSUSED */
52226f9a767SRodney W. Grimes int
523b40ce416SJulian Elischer setuid(td, uap)
524b40ce416SJulian Elischer 	struct thread *td;
525df8bae1dSRodney W. Grimes 	struct setuid_args *uap;
526df8bae1dSRodney W. Grimes {
527b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
528b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
529b1fc0ec1SRobert Watson 	uid_t uid;
530835a82eeSMatthew Dillon 	int error = 0;
531df8bae1dSRodney W. Grimes 
532b1fc0ec1SRobert Watson 	uid = uap->uid;
533b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
534835a82eeSMatthew Dillon 	mtx_lock(&Giant);
535835a82eeSMatthew Dillon 
536a08f4bf6SPeter Wemm 	/*
537a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
538a08f4bf6SPeter Wemm 	 *
539a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
540a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5412fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
542a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
543a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
544a08f4bf6SPeter Wemm 	 *
545a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
546a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
547a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
548a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
549a08f4bf6SPeter Wemm 	 * 2: We determine if the real and/or saved uid's are going to
550a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
551a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
552a08f4bf6SPeter Wemm 	 */
553b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
5543f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
555b1fc0ec1SRobert Watson 	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
556a08f4bf6SPeter Wemm #endif
557a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
558b1fc0ec1SRobert Watson 	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
5593f246666SAndrey A. Chernov #endif
560b1fc0ec1SRobert Watson 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
561835a82eeSMatthew Dillon 		goto done2;
562a08f4bf6SPeter Wemm 
563b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
564a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
565df8bae1dSRodney W. Grimes 	/*
566a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
567a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
568df8bae1dSRodney W. Grimes 	 */
5693f246666SAndrey A. Chernov 	if (
570a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
571b1fc0ec1SRobert Watson 	    uid == oldcred->cr_uid ||
5723f246666SAndrey A. Chernov #endif
573b1fc0ec1SRobert Watson 	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
574a08f4bf6SPeter Wemm #endif
575a08f4bf6SPeter Wemm 	{
576a08f4bf6SPeter Wemm 		/*
577f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
578a08f4bf6SPeter Wemm 		 */
579b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_ruid) {
580b1fc0ec1SRobert Watson 			change_ruid(newcred, uid);
581f535380cSDon Lewis 			setsugid(p);
582d3cdb93dSAndrey A. Chernov 		}
583a08f4bf6SPeter Wemm 		/*
584a08f4bf6SPeter Wemm 		 * Set saved uid
585a08f4bf6SPeter Wemm 		 *
586a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
587a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
588a08f4bf6SPeter Wemm 		 * is important that we should do this.
589a08f4bf6SPeter Wemm 		 */
590b1fc0ec1SRobert Watson 		if (uid != oldcred->cr_svuid) {
591b1fc0ec1SRobert Watson 			change_svuid(newcred, uid);
592d5f81602SSean Eric Fagan 			setsugid(p);
593a08f4bf6SPeter Wemm 		}
594a08f4bf6SPeter Wemm 	}
595a08f4bf6SPeter Wemm 
596a08f4bf6SPeter Wemm 	/*
597a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
598a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
599a08f4bf6SPeter Wemm 	 */
600b1fc0ec1SRobert Watson 	if (uid != oldcred->cr_uid) {
601b1fc0ec1SRobert Watson 		change_euid(newcred, uid);
602d5f81602SSean Eric Fagan 		setsugid(p);
603a08f4bf6SPeter Wemm 	}
604b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
605b1fc0ec1SRobert Watson 	crfree(oldcred);
606835a82eeSMatthew Dillon done2:
607835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
608835a82eeSMatthew Dillon 	return (error);
609df8bae1dSRodney W. Grimes }
610df8bae1dSRodney W. Grimes 
611d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
612df8bae1dSRodney W. Grimes struct seteuid_args {
613df8bae1dSRodney W. Grimes 	uid_t	euid;
614df8bae1dSRodney W. Grimes };
615d2d3e875SBruce Evans #endif
616835a82eeSMatthew Dillon /*
617835a82eeSMatthew Dillon  * MPSAFE
618835a82eeSMatthew Dillon  */
619df8bae1dSRodney W. Grimes /* ARGSUSED */
62026f9a767SRodney W. Grimes int
621b40ce416SJulian Elischer seteuid(td, uap)
622b40ce416SJulian Elischer 	struct thread *td;
623df8bae1dSRodney W. Grimes 	struct seteuid_args *uap;
624df8bae1dSRodney W. Grimes {
625b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
626b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
627b1fc0ec1SRobert Watson 	uid_t euid;
628835a82eeSMatthew Dillon 	int error = 0;
629df8bae1dSRodney W. Grimes 
630df8bae1dSRodney W. Grimes 	euid = uap->euid;
631835a82eeSMatthew Dillon 
632835a82eeSMatthew Dillon 	mtx_lock(&Giant);
633b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
634b1fc0ec1SRobert Watson 	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
635b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
636835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) {
637835a82eeSMatthew Dillon 		goto done2;
638835a82eeSMatthew Dillon 	}
639df8bae1dSRodney W. Grimes 	/*
640df8bae1dSRodney W. Grimes 	 * Everything's okay, do it.  Copy credentials so other references do
641df8bae1dSRodney W. Grimes 	 * not see our changes.
642df8bae1dSRodney W. Grimes 	 */
643b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
644b1fc0ec1SRobert Watson 	if (oldcred->cr_uid != euid) {
645b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
646d5f81602SSean Eric Fagan 		setsugid(p);
647229a15f0SPeter Wemm 	}
648b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
649b1fc0ec1SRobert Watson 	crfree(oldcred);
650835a82eeSMatthew Dillon done2:
651835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
652835a82eeSMatthew Dillon 	return (error);
653df8bae1dSRodney W. Grimes }
654df8bae1dSRodney W. Grimes 
655d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
656df8bae1dSRodney W. Grimes struct setgid_args {
657df8bae1dSRodney W. Grimes 	gid_t	gid;
658df8bae1dSRodney W. Grimes };
659d2d3e875SBruce Evans #endif
660835a82eeSMatthew Dillon /*
661835a82eeSMatthew Dillon  * MPSAFE
662835a82eeSMatthew Dillon  */
663df8bae1dSRodney W. Grimes /* ARGSUSED */
66426f9a767SRodney W. Grimes int
665b40ce416SJulian Elischer setgid(td, uap)
666b40ce416SJulian Elischer 	struct thread *td;
667df8bae1dSRodney W. Grimes 	struct setgid_args *uap;
668df8bae1dSRodney W. Grimes {
669b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
670b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
671b1fc0ec1SRobert Watson 	gid_t gid;
672835a82eeSMatthew Dillon 	int error = 0;
673df8bae1dSRodney W. Grimes 
674b1fc0ec1SRobert Watson 	gid = uap->gid;
675835a82eeSMatthew Dillon 
676835a82eeSMatthew Dillon 	mtx_lock(&Giant);
677b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
678a08f4bf6SPeter Wemm 	/*
679a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
680a08f4bf6SPeter Wemm 	 *
681a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
682a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
6832fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
684a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
685a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
686a08f4bf6SPeter Wemm 	 *
687a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
688a08f4bf6SPeter Wemm 	 */
689b1fc0ec1SRobert Watson 	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
6903f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
691b1fc0ec1SRobert Watson 	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
692a08f4bf6SPeter Wemm #endif
693a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
694b1fc0ec1SRobert Watson 	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
6953f246666SAndrey A. Chernov #endif
696835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) {
697835a82eeSMatthew Dillon 		goto done2;
698835a82eeSMatthew Dillon 	}
699a08f4bf6SPeter Wemm 
700b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
701a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
702a08f4bf6SPeter Wemm 	/*
703a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
704a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
705a08f4bf6SPeter Wemm 	 */
706a08f4bf6SPeter Wemm 	if (
707a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
708b1fc0ec1SRobert Watson 	    gid == oldcred->cr_groups[0] ||
709a08f4bf6SPeter Wemm #endif
710b1fc0ec1SRobert Watson 	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
711a08f4bf6SPeter Wemm #endif
712a08f4bf6SPeter Wemm 	{
713a08f4bf6SPeter Wemm 		/*
714a08f4bf6SPeter Wemm 		 * Set real gid
715a08f4bf6SPeter Wemm 		 */
716b1fc0ec1SRobert Watson 		if (oldcred->cr_rgid != gid) {
717b1fc0ec1SRobert Watson 			change_rgid(newcred, gid);
718d5f81602SSean Eric Fagan 			setsugid(p);
719a08f4bf6SPeter Wemm 		}
720a08f4bf6SPeter Wemm 		/*
721a08f4bf6SPeter Wemm 		 * Set saved gid
722a08f4bf6SPeter Wemm 		 *
723a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
724a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
725a08f4bf6SPeter Wemm 		 * is important that we should do this.
726a08f4bf6SPeter Wemm 		 */
727b1fc0ec1SRobert Watson 		if (oldcred->cr_svgid != gid) {
728b1fc0ec1SRobert Watson 			change_svgid(newcred, gid);
729d5f81602SSean Eric Fagan 			setsugid(p);
730a08f4bf6SPeter Wemm 		}
731a08f4bf6SPeter Wemm 	}
732a08f4bf6SPeter Wemm 	/*
733a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
734a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
735a08f4bf6SPeter Wemm 	 */
736b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != gid) {
737b1fc0ec1SRobert Watson 		change_egid(newcred, gid);
738d5f81602SSean Eric Fagan 		setsugid(p);
739a08f4bf6SPeter Wemm 	}
740b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
741b1fc0ec1SRobert Watson 	crfree(oldcred);
742835a82eeSMatthew Dillon done2:
743835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
744835a82eeSMatthew Dillon 	return (error);
745df8bae1dSRodney W. Grimes }
746df8bae1dSRodney W. Grimes 
747d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
748df8bae1dSRodney W. Grimes struct setegid_args {
749df8bae1dSRodney W. Grimes 	gid_t	egid;
750df8bae1dSRodney W. Grimes };
751d2d3e875SBruce Evans #endif
752835a82eeSMatthew Dillon /*
753835a82eeSMatthew Dillon  * MPSAFE
754835a82eeSMatthew Dillon  */
755df8bae1dSRodney W. Grimes /* ARGSUSED */
75626f9a767SRodney W. Grimes int
757b40ce416SJulian Elischer setegid(td, uap)
758b40ce416SJulian Elischer 	struct thread *td;
759df8bae1dSRodney W. Grimes 	struct setegid_args *uap;
760df8bae1dSRodney W. Grimes {
761b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
762b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
763b1fc0ec1SRobert Watson 	gid_t egid;
764835a82eeSMatthew Dillon 	int error = 0;
765df8bae1dSRodney W. Grimes 
766df8bae1dSRodney W. Grimes 	egid = uap->egid;
767835a82eeSMatthew Dillon 
768835a82eeSMatthew Dillon 	mtx_lock(&Giant);
769b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
770b1fc0ec1SRobert Watson 	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
771b1fc0ec1SRobert Watson 	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
772835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) {
773835a82eeSMatthew Dillon 		goto done2;
774835a82eeSMatthew Dillon 	}
775b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
776b1fc0ec1SRobert Watson 	if (oldcred->cr_groups[0] != egid) {
777b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
778d5f81602SSean Eric Fagan 		setsugid(p);
779229a15f0SPeter Wemm 	}
780b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
781b1fc0ec1SRobert Watson 	crfree(oldcred);
782835a82eeSMatthew Dillon done2:
783835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
784835a82eeSMatthew Dillon 	return (error);
785df8bae1dSRodney W. Grimes }
786df8bae1dSRodney W. Grimes 
787d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
788df8bae1dSRodney W. Grimes struct setgroups_args {
789df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
790df8bae1dSRodney W. Grimes 	gid_t	*gidset;
791df8bae1dSRodney W. Grimes };
792d2d3e875SBruce Evans #endif
793835a82eeSMatthew Dillon /*
794835a82eeSMatthew Dillon  * MPSAFE
795835a82eeSMatthew Dillon  */
796df8bae1dSRodney W. Grimes /* ARGSUSED */
79726f9a767SRodney W. Grimes int
798b40ce416SJulian Elischer setgroups(td, uap)
799b40ce416SJulian Elischer 	struct thread *td;
800df8bae1dSRodney W. Grimes 	struct setgroups_args *uap;
801df8bae1dSRodney W. Grimes {
802b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
803b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
804b1fc0ec1SRobert Watson 	u_int ngrp;
805df8bae1dSRodney W. Grimes 	int error;
806df8bae1dSRodney W. Grimes 
807835a82eeSMatthew Dillon 	mtx_lock(&Giant);
808835a82eeSMatthew Dillon 
8093956a170SDavid Greenman 	ngrp = uap->gidsetsize;
810b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
811b1fc0ec1SRobert Watson 	if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
812835a82eeSMatthew Dillon 		goto done2;
813835a82eeSMatthew Dillon 	if (ngrp > NGROUPS) {
814835a82eeSMatthew Dillon 		error = EINVAL;
815835a82eeSMatthew Dillon 		goto done2;
816835a82eeSMatthew Dillon 	}
8178a5d815aSPeter Wemm 	/*
8188a5d815aSPeter Wemm 	 * XXX A little bit lazy here.  We could test if anything has
8198a5d815aSPeter Wemm 	 * changed before crcopy() and setting P_SUGID.
8208a5d815aSPeter Wemm 	 */
821b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
8228a5d815aSPeter Wemm 	if (ngrp < 1) {
8238a5d815aSPeter Wemm 		/*
8248a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
8258a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
8268a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
8278a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
8288a5d815aSPeter Wemm 		 */
829b1fc0ec1SRobert Watson 		newcred->cr_ngroups = 1;
8308a5d815aSPeter Wemm 	} else {
831bb56ec4aSPoul-Henning Kamp 		if ((error = copyin((caddr_t)uap->gidset,
832b1fc0ec1SRobert Watson 		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
833b1fc0ec1SRobert Watson 			crfree(newcred);
834835a82eeSMatthew Dillon 			goto done2;
835b1fc0ec1SRobert Watson 		}
836b1fc0ec1SRobert Watson 		newcred->cr_ngroups = ngrp;
8378a5d815aSPeter Wemm 	}
838d5f81602SSean Eric Fagan 	setsugid(p);
839b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
840b1fc0ec1SRobert Watson 	crfree(oldcred);
841835a82eeSMatthew Dillon done2:
842835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
843835a82eeSMatthew Dillon 	return (error);
844df8bae1dSRodney W. Grimes }
845df8bae1dSRodney W. Grimes 
846d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
847df8bae1dSRodney W. Grimes struct setreuid_args {
84800999cd6SAndrey A. Chernov 	uid_t	ruid;
84900999cd6SAndrey A. Chernov 	uid_t	euid;
850df8bae1dSRodney W. Grimes };
851d2d3e875SBruce Evans #endif
852835a82eeSMatthew Dillon /*
853835a82eeSMatthew Dillon  * MPSAFE
854835a82eeSMatthew Dillon  */
855df8bae1dSRodney W. Grimes /* ARGSUSED */
85626f9a767SRodney W. Grimes int
857b40ce416SJulian Elischer setreuid(td, uap)
858b40ce416SJulian Elischer 	register struct thread *td;
859df8bae1dSRodney W. Grimes 	struct setreuid_args *uap;
860df8bae1dSRodney W. Grimes {
861b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
862b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
863b1fc0ec1SRobert Watson 	uid_t ruid, euid;
864835a82eeSMatthew Dillon 	int error = 0;
865df8bae1dSRodney W. Grimes 
86600999cd6SAndrey A. Chernov 	ruid = uap->ruid;
86700999cd6SAndrey A. Chernov 	euid = uap->euid;
868835a82eeSMatthew Dillon 
869835a82eeSMatthew Dillon 	mtx_lock(&Giant);
870835a82eeSMatthew Dillon 
871b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
872b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
873b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_svuid) ||
874b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
875b1fc0ec1SRobert Watson 	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
876835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
877835a82eeSMatthew Dillon 		goto done2;
878835a82eeSMatthew Dillon 	}
879b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
880b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
881b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
882d5f81602SSean Eric Fagan 		setsugid(p);
883a89a5370SPeter Wemm 	}
884b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
885b1fc0ec1SRobert Watson 		change_ruid(newcred, ruid);
886d5f81602SSean Eric Fagan 		setsugid(p);
88700999cd6SAndrey A. Chernov 	}
888b1fc0ec1SRobert Watson 	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
889b1fc0ec1SRobert Watson 	    newcred->cr_svuid != newcred->cr_uid) {
890b1fc0ec1SRobert Watson 		change_svuid(newcred, newcred->cr_uid);
891d5f81602SSean Eric Fagan 		setsugid(p);
892a89a5370SPeter Wemm 	}
893b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
894b1fc0ec1SRobert Watson 	crfree(oldcred);
895835a82eeSMatthew Dillon done2:
896835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
897835a82eeSMatthew Dillon 	return (error);
898df8bae1dSRodney W. Grimes }
899df8bae1dSRodney W. Grimes 
900d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
901df8bae1dSRodney W. Grimes struct setregid_args {
90200999cd6SAndrey A. Chernov 	gid_t	rgid;
90300999cd6SAndrey A. Chernov 	gid_t	egid;
904df8bae1dSRodney W. Grimes };
905d2d3e875SBruce Evans #endif
906835a82eeSMatthew Dillon /*
907835a82eeSMatthew Dillon  * MPSAFE
908835a82eeSMatthew Dillon  */
909df8bae1dSRodney W. Grimes /* ARGSUSED */
91026f9a767SRodney W. Grimes int
911b40ce416SJulian Elischer setregid(td, uap)
912b40ce416SJulian Elischer 	register struct thread *td;
913df8bae1dSRodney W. Grimes 	struct setregid_args *uap;
914df8bae1dSRodney W. Grimes {
915b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
916b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
917b1fc0ec1SRobert Watson 	gid_t rgid, egid;
918835a82eeSMatthew Dillon 	int error = 0;
919df8bae1dSRodney W. Grimes 
92000999cd6SAndrey A. Chernov 	rgid = uap->rgid;
92100999cd6SAndrey A. Chernov 	egid = uap->egid;
922835a82eeSMatthew Dillon 
923835a82eeSMatthew Dillon 	mtx_lock(&Giant);
924835a82eeSMatthew Dillon 
925b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
926b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
927b1fc0ec1SRobert Watson 	    rgid != oldcred->cr_svgid) ||
928b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
929b1fc0ec1SRobert Watson 	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
930835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
931835a82eeSMatthew Dillon 		goto done2;
932835a82eeSMatthew Dillon 	}
93300999cd6SAndrey A. Chernov 
934b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
935b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
936b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
937d5f81602SSean Eric Fagan 		setsugid(p);
938a89a5370SPeter Wemm 	}
939b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
940b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
941d5f81602SSean Eric Fagan 		setsugid(p);
942a89a5370SPeter Wemm 	}
943b1fc0ec1SRobert Watson 	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
944b1fc0ec1SRobert Watson 	    newcred->cr_svgid != newcred->cr_groups[0]) {
945b1fc0ec1SRobert Watson 		change_svgid(newcred, newcred->cr_groups[0]);
946d5f81602SSean Eric Fagan 		setsugid(p);
947a89a5370SPeter Wemm 	}
9484589be70SRuslan Ermilov 	p->p_ucred = newcred;
9494589be70SRuslan Ermilov 	crfree(oldcred);
950835a82eeSMatthew Dillon done2:
951835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
952835a82eeSMatthew Dillon 	return (error);
953df8bae1dSRodney W. Grimes }
954df8bae1dSRodney W. Grimes 
9558ccd6334SPeter Wemm /*
9568ccd6334SPeter Wemm  * setresuid(ruid, euid, suid) is like setreuid except control over the
9578ccd6334SPeter Wemm  * saved uid is explicit.
9588ccd6334SPeter Wemm  */
9598ccd6334SPeter Wemm 
9608ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
9618ccd6334SPeter Wemm struct setresuid_args {
9628ccd6334SPeter Wemm 	uid_t	ruid;
9638ccd6334SPeter Wemm 	uid_t	euid;
9648ccd6334SPeter Wemm 	uid_t	suid;
9658ccd6334SPeter Wemm };
9668ccd6334SPeter Wemm #endif
967835a82eeSMatthew Dillon /*
968835a82eeSMatthew Dillon  * MPSAFE
969835a82eeSMatthew Dillon  */
9708ccd6334SPeter Wemm /* ARGSUSED */
9718ccd6334SPeter Wemm int
972b40ce416SJulian Elischer setresuid(td, uap)
973b40ce416SJulian Elischer 	register struct thread *td;
9748ccd6334SPeter Wemm 	struct setresuid_args *uap;
9758ccd6334SPeter Wemm {
976b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
977b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
978b1fc0ec1SRobert Watson 	uid_t ruid, euid, suid;
9798ccd6334SPeter Wemm 	int error;
9808ccd6334SPeter Wemm 
9818ccd6334SPeter Wemm 	ruid = uap->ruid;
9828ccd6334SPeter Wemm 	euid = uap->euid;
9838ccd6334SPeter Wemm 	suid = uap->suid;
984835a82eeSMatthew Dillon 
985835a82eeSMatthew Dillon 	mtx_lock(&Giant);
986b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
987b1fc0ec1SRobert Watson 	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
988b1fc0ec1SRobert Watson 	     ruid != oldcred->cr_svuid &&
989b1fc0ec1SRobert Watson 	      ruid != oldcred->cr_uid) ||
990b1fc0ec1SRobert Watson 	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
991b1fc0ec1SRobert Watson 	    euid != oldcred->cr_svuid &&
992b1fc0ec1SRobert Watson 	      euid != oldcred->cr_uid) ||
993b1fc0ec1SRobert Watson 	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
994b1fc0ec1SRobert Watson 	    suid != oldcred->cr_svuid &&
995b1fc0ec1SRobert Watson 	      suid != oldcred->cr_uid)) &&
996835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
997835a82eeSMatthew Dillon 		goto done2;
998835a82eeSMatthew Dillon 	}
999b1fc0ec1SRobert Watson 
1000b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
1001b1fc0ec1SRobert Watson 	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
1002b1fc0ec1SRobert Watson 		change_euid(newcred, euid);
10038ccd6334SPeter Wemm 		setsugid(p);
10048ccd6334SPeter Wemm 	}
1005b1fc0ec1SRobert Watson 	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
1006b1fc0ec1SRobert Watson 		change_ruid(newcred, ruid);
10078ccd6334SPeter Wemm 		setsugid(p);
10088ccd6334SPeter Wemm 	}
1009b1fc0ec1SRobert Watson 	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
1010b1fc0ec1SRobert Watson 		change_svuid(newcred, suid);
10118ccd6334SPeter Wemm 		setsugid(p);
10128ccd6334SPeter Wemm 	}
1013b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
1014b1fc0ec1SRobert Watson 	crfree(oldcred);
1015835a82eeSMatthew Dillon 	error = 0;
1016835a82eeSMatthew Dillon done2:
1017835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1018835a82eeSMatthew Dillon 	return (error);
10198ccd6334SPeter Wemm }
10208ccd6334SPeter Wemm 
10218ccd6334SPeter Wemm /*
10228ccd6334SPeter Wemm  * setresgid(rgid, egid, sgid) is like setregid except control over the
10238ccd6334SPeter Wemm  * saved gid is explicit.
10248ccd6334SPeter Wemm  */
10258ccd6334SPeter Wemm 
10268ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10278ccd6334SPeter Wemm struct setresgid_args {
10288ccd6334SPeter Wemm 	gid_t	rgid;
10298ccd6334SPeter Wemm 	gid_t	egid;
10308ccd6334SPeter Wemm 	gid_t	sgid;
10318ccd6334SPeter Wemm };
10328ccd6334SPeter Wemm #endif
1033835a82eeSMatthew Dillon /*
1034835a82eeSMatthew Dillon  * MPSAFE
1035835a82eeSMatthew Dillon  */
10368ccd6334SPeter Wemm /* ARGSUSED */
10378ccd6334SPeter Wemm int
1038b40ce416SJulian Elischer setresgid(td, uap)
1039b40ce416SJulian Elischer 	register struct thread *td;
10408ccd6334SPeter Wemm 	struct setresgid_args *uap;
10418ccd6334SPeter Wemm {
1042b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1043b1fc0ec1SRobert Watson 	struct ucred *newcred, *oldcred;
1044b1fc0ec1SRobert Watson 	gid_t rgid, egid, sgid;
10458ccd6334SPeter Wemm 	int error;
10468ccd6334SPeter Wemm 
10478ccd6334SPeter Wemm 	rgid = uap->rgid;
10488ccd6334SPeter Wemm 	egid = uap->egid;
10498ccd6334SPeter Wemm 	sgid = uap->sgid;
1050835a82eeSMatthew Dillon 
1051835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1052b1fc0ec1SRobert Watson 	oldcred = p->p_ucred;
1053b1fc0ec1SRobert Watson 	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
1054b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_svgid &&
1055b1fc0ec1SRobert Watson 	      rgid != oldcred->cr_groups[0]) ||
1056b1fc0ec1SRobert Watson 	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
1057b1fc0ec1SRobert Watson 	      egid != oldcred->cr_svgid &&
1058b1fc0ec1SRobert Watson 	      egid != oldcred->cr_groups[0]) ||
1059b1fc0ec1SRobert Watson 	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
1060b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_svgid &&
1061b1fc0ec1SRobert Watson 	      sgid != oldcred->cr_groups[0])) &&
1062835a82eeSMatthew Dillon 	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) {
1063835a82eeSMatthew Dillon 		goto done2;
1064835a82eeSMatthew Dillon 	}
1065b1fc0ec1SRobert Watson 	newcred = crdup(oldcred);
1066b1fc0ec1SRobert Watson 	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
1067b1fc0ec1SRobert Watson 		change_egid(newcred, egid);
10688ccd6334SPeter Wemm 		setsugid(p);
10698ccd6334SPeter Wemm 	}
1070b1fc0ec1SRobert Watson 	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
1071b1fc0ec1SRobert Watson 		change_rgid(newcred, rgid);
10728ccd6334SPeter Wemm 		setsugid(p);
10738ccd6334SPeter Wemm 	}
1074b1fc0ec1SRobert Watson 	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
1075b1fc0ec1SRobert Watson 		change_svgid(newcred, sgid);
10768ccd6334SPeter Wemm 		setsugid(p);
10778ccd6334SPeter Wemm 	}
1078b1fc0ec1SRobert Watson 	p->p_ucred = newcred;
1079b1fc0ec1SRobert Watson 	crfree(oldcred);
1080835a82eeSMatthew Dillon 	error = 0;
1081835a82eeSMatthew Dillon done2:
1082835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1083835a82eeSMatthew Dillon 	return (error);
10848ccd6334SPeter Wemm }
10858ccd6334SPeter Wemm 
10868ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
10878ccd6334SPeter Wemm struct getresuid_args {
10888ccd6334SPeter Wemm 	uid_t	*ruid;
10898ccd6334SPeter Wemm 	uid_t	*euid;
10908ccd6334SPeter Wemm 	uid_t	*suid;
10918ccd6334SPeter Wemm };
10928ccd6334SPeter Wemm #endif
1093835a82eeSMatthew Dillon /*
1094835a82eeSMatthew Dillon  * MPSAFE
1095835a82eeSMatthew Dillon  */
10968ccd6334SPeter Wemm /* ARGSUSED */
10978ccd6334SPeter Wemm int
1098b40ce416SJulian Elischer getresuid(td, uap)
1099b40ce416SJulian Elischer 	register struct thread *td;
11008ccd6334SPeter Wemm 	struct getresuid_args *uap;
11018ccd6334SPeter Wemm {
1102835a82eeSMatthew Dillon 	struct ucred *cred;
1103b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
11048ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11058ccd6334SPeter Wemm 
1106835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1107835a82eeSMatthew Dillon 	cred = p->p_ucred;
1108835a82eeSMatthew Dillon 
11098ccd6334SPeter Wemm 	if (uap->ruid)
1110b1fc0ec1SRobert Watson 		error1 = copyout((caddr_t)&cred->cr_ruid,
1111b1fc0ec1SRobert Watson 		    (caddr_t)uap->ruid, sizeof(cred->cr_ruid));
11128ccd6334SPeter Wemm 	if (uap->euid)
1113b1fc0ec1SRobert Watson 		error2 = copyout((caddr_t)&cred->cr_uid,
1114b1fc0ec1SRobert Watson 		    (caddr_t)uap->euid, sizeof(cred->cr_uid));
11158ccd6334SPeter Wemm 	if (uap->suid)
1116b1fc0ec1SRobert Watson 		error3 = copyout((caddr_t)&cred->cr_svuid,
1117b1fc0ec1SRobert Watson 		    (caddr_t)uap->suid, sizeof(cred->cr_svuid));
1118835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
11198ccd6334SPeter Wemm 	return error1 ? error1 : (error2 ? error2 : error3);
11208ccd6334SPeter Wemm }
11218ccd6334SPeter Wemm 
11228ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
11238ccd6334SPeter Wemm struct getresgid_args {
11248ccd6334SPeter Wemm 	gid_t	*rgid;
11258ccd6334SPeter Wemm 	gid_t	*egid;
11268ccd6334SPeter Wemm 	gid_t	*sgid;
11278ccd6334SPeter Wemm };
11288ccd6334SPeter Wemm #endif
1129835a82eeSMatthew Dillon /*
1130835a82eeSMatthew Dillon  * MPSAFE
1131835a82eeSMatthew Dillon  */
11328ccd6334SPeter Wemm /* ARGSUSED */
11338ccd6334SPeter Wemm int
1134b40ce416SJulian Elischer getresgid(td, uap)
1135b40ce416SJulian Elischer 	register struct thread *td;
11368ccd6334SPeter Wemm 	struct getresgid_args *uap;
11378ccd6334SPeter Wemm {
1138835a82eeSMatthew Dillon 	struct ucred *cred;
1139b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
11408ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
11418ccd6334SPeter Wemm 
1142835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1143835a82eeSMatthew Dillon 	cred = p->p_ucred;
1144835a82eeSMatthew Dillon 
11458ccd6334SPeter Wemm 	if (uap->rgid)
1146b1fc0ec1SRobert Watson 		error1 = copyout((caddr_t)&cred->cr_rgid,
1147b1fc0ec1SRobert Watson 		    (caddr_t)uap->rgid, sizeof(cred->cr_rgid));
11488ccd6334SPeter Wemm 	if (uap->egid)
1149b1fc0ec1SRobert Watson 		error2 = copyout((caddr_t)&cred->cr_groups[0],
1150b1fc0ec1SRobert Watson 		    (caddr_t)uap->egid, sizeof(cred->cr_groups[0]));
11518ccd6334SPeter Wemm 	if (uap->sgid)
1152b1fc0ec1SRobert Watson 		error3 = copyout((caddr_t)&cred->cr_svgid,
1153b1fc0ec1SRobert Watson 		    (caddr_t)uap->sgid, sizeof(cred->cr_svgid));
1154835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
11558ccd6334SPeter Wemm 	return error1 ? error1 : (error2 ? error2 : error3);
11568ccd6334SPeter Wemm }
11578ccd6334SPeter Wemm 
11588ccd6334SPeter Wemm 
1159b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1160b67cbc65SPeter Wemm struct issetugid_args {
1161b67cbc65SPeter Wemm 	int dummy;
1162b67cbc65SPeter Wemm };
1163b67cbc65SPeter Wemm #endif
1164b67cbc65SPeter Wemm /* ARGSUSED */
1165b67cbc65SPeter Wemm int
1166b40ce416SJulian Elischer issetugid(td, uap)
1167b40ce416SJulian Elischer 	register struct thread *td;
1168b67cbc65SPeter Wemm 	struct issetugid_args *uap;
1169b67cbc65SPeter Wemm {
1170b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1171b40ce416SJulian Elischer 
1172b67cbc65SPeter Wemm 	/*
1173b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
1174b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
1175b67cbc65SPeter Wemm 	 * "tainting" as well.
1176b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
1177b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
1178b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
1179b67cbc65SPeter Wemm 	 */
1180b40ce416SJulian Elischer 	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
1181b67cbc65SPeter Wemm 	return (0);
1182b67cbc65SPeter Wemm }
1183b67cbc65SPeter Wemm 
1184835a82eeSMatthew Dillon /*
1185835a82eeSMatthew Dillon  * MPSAFE
1186835a82eeSMatthew Dillon  */
1187130d0157SRobert Watson int
1188b40ce416SJulian Elischer __setugid(td, uap)
1189b40ce416SJulian Elischer 	struct thread *td;
1190130d0157SRobert Watson 	struct __setugid_args *uap;
1191130d0157SRobert Watson {
1192130d0157SRobert Watson #ifdef REGRESSION
1193835a82eeSMatthew Dillon 	int error = 0;
1194835a82eeSMatthew Dillon 
1195835a82eeSMatthew Dillon 	mtx_lock(&Giant);
1196130d0157SRobert Watson 	switch (uap->flag) {
1197130d0157SRobert Watson 	case 0:
1198b40ce416SJulian Elischer 		td->td_proc->p_flag &= ~P_SUGID;
1199835a82eeSMatthew Dillon 		break;
1200130d0157SRobert Watson 	case 1:
1201b40ce416SJulian Elischer 		td->td_proc->p_flag |= P_SUGID;
1202835a82eeSMatthew Dillon 		break;
1203130d0157SRobert Watson 	default:
1204835a82eeSMatthew Dillon 		error = EINVAL;
1205835a82eeSMatthew Dillon 		break;
1206130d0157SRobert Watson 	}
1207835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1208835a82eeSMatthew Dillon 	return (error);
1209130d0157SRobert Watson #else /* !REGRESSION */
1210130d0157SRobert Watson 	return (ENOSYS);
1211130d0157SRobert Watson #endif /* !REGRESSION */
1212130d0157SRobert Watson }
1213130d0157SRobert Watson 
1214df8bae1dSRodney W. Grimes /*
1215df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
1216df8bae1dSRodney W. Grimes  */
121726f9a767SRodney W. Grimes int
1218df8bae1dSRodney W. Grimes groupmember(gid, cred)
1219df8bae1dSRodney W. Grimes 	gid_t gid;
1220b1fc0ec1SRobert Watson 	struct ucred *cred;
1221df8bae1dSRodney W. Grimes {
1222df8bae1dSRodney W. Grimes 	register gid_t *gp;
1223df8bae1dSRodney W. Grimes 	gid_t *egp;
1224df8bae1dSRodney W. Grimes 
1225df8bae1dSRodney W. Grimes 	egp = &(cred->cr_groups[cred->cr_ngroups]);
1226df8bae1dSRodney W. Grimes 	for (gp = cred->cr_groups; gp < egp; gp++)
1227df8bae1dSRodney W. Grimes 		if (*gp == gid)
1228df8bae1dSRodney W. Grimes 			return (1);
1229df8bae1dSRodney W. Grimes 	return (0);
1230df8bae1dSRodney W. Grimes }
1231df8bae1dSRodney W. Grimes 
12323b243b72SRobert Watson /*
123393f4fd1cSRobert Watson  * `suser_enabled' (which can be set by the kern.security.suser_enabled
12347fd6a959SRobert Watson  * sysctl) determines whether the system 'super-user' policy is in effect.
12357fd6a959SRobert Watson  * If it is nonzero, an effective uid of 0 connotes special privilege,
12367fd6a959SRobert Watson  * overriding many mandatory and discretionary protections.  If it is zero,
12377fd6a959SRobert Watson  * uid 0 is offered no special privilege in the kernel security policy.
12387fd6a959SRobert Watson  * Setting it to zero may seriously impact the functionality of many
12397fd6a959SRobert Watson  * existing userland programs, and should not be done without careful
12407fd6a959SRobert Watson  * consideration of the consequences.
12413b243b72SRobert Watson  */
124293f4fd1cSRobert Watson int	suser_enabled = 1;
124393f4fd1cSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, suser_enabled, CTLFLAG_RW,
124493f4fd1cSRobert Watson     &suser_enabled, 0, "processes with uid 0 have privilege");
1245579f4eb4SRobert Watson 
1246df8bae1dSRodney W. Grimes /*
12477fd6a959SRobert Watson  * Test whether the specified credentials imply "super-user" privilege.
12487fd6a959SRobert Watson  * Return 0 or EPERM.
1249df8bae1dSRodney W. Grimes  */
125026f9a767SRodney W. Grimes int
1251f711d546SPoul-Henning Kamp suser(p)
125291421ba2SRobert Watson 	struct proc *p;
1253f711d546SPoul-Henning Kamp {
125475c13541SPoul-Henning Kamp 	return suser_xxx(0, p, 0);
1255f711d546SPoul-Henning Kamp }
1256f711d546SPoul-Henning Kamp 
1257b40ce416SJulian Elischer /*
1258b40ce416SJulian Elischer  * version for when the thread pointer is available and not the proc.
1259b40ce416SJulian Elischer  * (saves having to include proc.h into every file that needs to do the change.)
1260b40ce416SJulian Elischer  */
1261b40ce416SJulian Elischer int
1262b40ce416SJulian Elischer suser_td(td)
1263b40ce416SJulian Elischer 
1264b40ce416SJulian Elischer 	struct thread *td;
1265b40ce416SJulian Elischer {
1266b40ce416SJulian Elischer 	return suser_xxx(0, td->td_proc, 0);
1267b40ce416SJulian Elischer }
1268b40ce416SJulian Elischer 
1269b40ce416SJulian Elischer /*
1270b40ce416SJulian Elischer  * wrapper to use if you have the thread on hand but not the proc.
1271b40ce416SJulian Elischer  */
1272b40ce416SJulian Elischer int
1273b40ce416SJulian Elischer suser_xxx_td(cred, td, flag)
1274b40ce416SJulian Elischer 	struct ucred *cred;
1275b40ce416SJulian Elischer 	struct thread *td;
1276b40ce416SJulian Elischer 	int flag;
1277b40ce416SJulian Elischer {
1278b40ce416SJulian Elischer 	return(suser_xxx(cred, td->td_proc, flag));
1279b40ce416SJulian Elischer }
1280b40ce416SJulian Elischer 
1281f711d546SPoul-Henning Kamp int
128275c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag)
128391421ba2SRobert Watson 	struct ucred *cred;
128491421ba2SRobert Watson 	struct proc *proc;
128575c13541SPoul-Henning Kamp 	int flag;
1286df8bae1dSRodney W. Grimes {
128793f4fd1cSRobert Watson 	if (!suser_enabled)
128803095547SRobert Watson 		return (EPERM);
128975c13541SPoul-Henning Kamp 	if (!cred && !proc) {
129075c13541SPoul-Henning Kamp 		printf("suser_xxx(): THINK!\n");
1291df8bae1dSRodney W. Grimes 		return (EPERM);
1292df8bae1dSRodney W. Grimes 	}
129375c13541SPoul-Henning Kamp 	if (!cred)
129475c13541SPoul-Henning Kamp 		cred = proc->p_ucred;
129575c13541SPoul-Henning Kamp 	if (cred->cr_uid != 0)
129675c13541SPoul-Henning Kamp 		return (EPERM);
129791421ba2SRobert Watson 	if (jailed(cred) && !(flag & PRISON_ROOT))
129875c13541SPoul-Henning Kamp 		return (EPERM);
129975c13541SPoul-Henning Kamp 	return (0);
130075c13541SPoul-Henning Kamp }
1301df8bae1dSRodney W. Grimes 
13023ca719f1SRobert Watson 
13033ca719f1SRobert Watson /*
130487fce2bbSRobert Watson  * Test (local, globale) securelevel values against passed required
130587fce2bbSRobert Watson  * securelevel.  _gt implements (level > securelevel), and _ge implements
130675bc5b3fSRobert Watson  * (level >= securelevel).  Returns 0 oer EPERM.
13073ca719f1SRobert Watson  *
13083ca719f1SRobert Watson  * cr is permitted to be NULL for the time being, as there were some
13093ca719f1SRobert Watson  * existing securelevel checks that occurred without a process/credential
13103ca719f1SRobert Watson  * context.  In the future this will be disallowed, so a kernel
13113ca719f1SRobert Watson  * message is displayed.
13123ca719f1SRobert Watson  */
13133ca719f1SRobert Watson int
13143ca719f1SRobert Watson securelevel_gt(struct ucred *cr, int level)
13153ca719f1SRobert Watson {
13163ca719f1SRobert Watson 
13173ca719f1SRobert Watson 	if (cr == NULL) {
13183ca719f1SRobert Watson 		printf("securelevel_gt: cr is NULL\n");
131975bc5b3fSRobert Watson 		if (level > securelevel)
13203ca719f1SRobert Watson 			return (0);
13213ca719f1SRobert Watson 		else
13223ca719f1SRobert Watson 			return (EPERM);
132387fce2bbSRobert Watson 	} else if (cr->cr_prison == NULL) {
132475bc5b3fSRobert Watson 		if (level > securelevel)
13253ca719f1SRobert Watson 			return (0);
13263ca719f1SRobert Watson 		else
13273ca719f1SRobert Watson 			return (EPERM);
132887fce2bbSRobert Watson 	} else {
132987fce2bbSRobert Watson 		if (level > imax(cr->cr_prison->pr_securelevel, securelevel))
133087fce2bbSRobert Watson 			return (0);
133187fce2bbSRobert Watson 		else
133287fce2bbSRobert Watson 			return (EPERM);
13333ca719f1SRobert Watson 	}
133487fce2bbSRobert Watson 
13353ca719f1SRobert Watson }
13363ca719f1SRobert Watson 
13373ca719f1SRobert Watson int
13383ca719f1SRobert Watson securelevel_ge(struct ucred *cr, int level)
13393ca719f1SRobert Watson {
13403ca719f1SRobert Watson 
13413ca719f1SRobert Watson 	if (cr == NULL) {
13423ca719f1SRobert Watson 		printf("securelevel_ge: cr is NULL\n");
134375bc5b3fSRobert Watson 		if (level >= securelevel)
13443ca719f1SRobert Watson 			return (0);
13453ca719f1SRobert Watson 		else
13463ca719f1SRobert Watson 			return (EPERM);
134787fce2bbSRobert Watson 	} if (cr->cr_prison == NULL) {
134875bc5b3fSRobert Watson 		if (level >= securelevel)
13493ca719f1SRobert Watson 			return (0);
13503ca719f1SRobert Watson 		else
13513ca719f1SRobert Watson 			return (EPERM);
135287fce2bbSRobert Watson 	} else {
135387fce2bbSRobert Watson 		if (level >= imax(cr->cr_prison->pr_securelevel, securelevel))
135487fce2bbSRobert Watson 			return (0);
135587fce2bbSRobert Watson 		else
135687fce2bbSRobert Watson 			return (EPERM);
13573ca719f1SRobert Watson 	}
13583ca719f1SRobert Watson }
13593ca719f1SRobert Watson 
13607fd6a959SRobert Watson /*-
13617fd6a959SRobert Watson  * Determine if u1 "can see" the subject specified by u2.
1362ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
1363ed639720SRobert Watson  * Locks: none
13647fd6a959SRobert Watson  * References: u1 and u2 must be immutable credentials
13657fd6a959SRobert Watson  *             u1 and u2 must be valid for the lifetime of the call
1366ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1367ed639720SRobert Watson  */
1368ed639720SRobert Watson int
136994088977SRobert Watson cr_cansee(struct ucred *u1, struct ucred *u2)
1370a9e0361bSPoul-Henning Kamp {
137191421ba2SRobert Watson 	int error;
1372a9e0361bSPoul-Henning Kamp 
1373ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
137491421ba2SRobert Watson 		return (error);
1375b1fc0ec1SRobert Watson 	if (!ps_showallprocs && u1->cr_ruid != u2->cr_ruid) {
1376f8e6ab29SRobert Watson 		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
1377387d2c03SRobert Watson 			return (ESRCH);
1378c52396e3SRobert Watson 	}
1379387d2c03SRobert Watson 	return (0);
1380387d2c03SRobert Watson }
1381387d2c03SRobert Watson 
13827fd6a959SRobert Watson /*-
13837fd6a959SRobert Watson  * Determine if p1 "can see" the subject specified by p2.
13843b243b72SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
13857fd6a959SRobert Watson  * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must
13863b243b72SRobert Watson  *        be held.  Normally, p1 will be curproc, and a lock must be held
13873b243b72SRobert Watson  *        for p2.
13883b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
13893b243b72SRobert Watson  */
1390a0f75161SRobert Watson int
1391a0f75161SRobert Watson p_cansee(struct proc *p1, struct proc *p2)
1392ed639720SRobert Watson {
1393ed639720SRobert Watson 
139494088977SRobert Watson 	/* Wrap cr_cansee() for all functionality. */
139594088977SRobert Watson 	return (cr_cansee(p1->p_ucred, p2->p_ucred));
1396ed639720SRobert Watson }
1397ed639720SRobert Watson 
13987fd6a959SRobert Watson /*-
13997fd6a959SRobert Watson  * Determine whether p1 may deliver the specified signal to p2.
14007fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
14017fd6a959SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
14027fd6a959SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
14037fd6a959SRobert Watson  *        be held for p2.
14043b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
14054c5eb9c3SRobert Watson  */
14064c5eb9c3SRobert Watson int
14074c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum)
1408387d2c03SRobert Watson {
140991421ba2SRobert Watson 	int error;
1410387d2c03SRobert Watson 
1411a9e0361bSPoul-Henning Kamp 	if (p1 == p2)
1412a9e0361bSPoul-Henning Kamp 		return (0);
1413387d2c03SRobert Watson 
14144c5eb9c3SRobert Watson 	/*
14154c5eb9c3SRobert Watson 	 * Jail semantics limit the scope of signalling to p2 in the same
14164c5eb9c3SRobert Watson 	 * jail as p1, if p1 is in jail.
14174c5eb9c3SRobert Watson 	 */
141891421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
141991421ba2SRobert Watson 		return (error);
1420387d2c03SRobert Watson 
1421387d2c03SRobert Watson 	/*
14224c5eb9c3SRobert Watson 	 * UNIX signalling semantics require that processes in the same
14234c5eb9c3SRobert Watson 	 * session always be able to deliver SIGCONT to one another,
14244c5eb9c3SRobert Watson 	 * overriding the remaining protections.
1425387d2c03SRobert Watson 	 */
14264c5eb9c3SRobert Watson 	if (signum == SIGCONT && p1->p_session == p2->p_session)
1427a9e0361bSPoul-Henning Kamp 		return (0);
1428387d2c03SRobert Watson 
14294c5eb9c3SRobert Watson 	/*
14303b243b72SRobert Watson 	 * UNIX signal semantics depend on the status of the P_SUGID
14313b243b72SRobert Watson 	 * bit on the target process.  If the bit is set, then additional
14323b243b72SRobert Watson 	 * restrictions are placed on the set of available signals.
14334c5eb9c3SRobert Watson 	 */
14344c5eb9c3SRobert Watson 	if (p2->p_flag & P_SUGID) {
14354c5eb9c3SRobert Watson 		switch (signum) {
14364c5eb9c3SRobert Watson 		case 0:
14374c5eb9c3SRobert Watson 		case SIGKILL:
14384c5eb9c3SRobert Watson 		case SIGINT:
14394c5eb9c3SRobert Watson 		case SIGTERM:
14404c5eb9c3SRobert Watson 		case SIGSTOP:
14414c5eb9c3SRobert Watson 		case SIGTTIN:
14424c5eb9c3SRobert Watson 		case SIGTTOU:
14434c5eb9c3SRobert Watson 		case SIGTSTP:
14444c5eb9c3SRobert Watson 		case SIGHUP:
14454c5eb9c3SRobert Watson 		case SIGUSR1:
14464c5eb9c3SRobert Watson 		case SIGUSR2:
14477fd6a959SRobert Watson 			/*
14487fd6a959SRobert Watson 			 * Generally, permit job and terminal control
14497fd6a959SRobert Watson 			 * signals.
14507fd6a959SRobert Watson 			 */
14514c5eb9c3SRobert Watson 			break;
14524c5eb9c3SRobert Watson 		default:
14533b243b72SRobert Watson 			/* Not permitted, privilege is required. */
14544c5eb9c3SRobert Watson 			error = suser_xxx(NULL, p1, PRISON_ROOT);
14554c5eb9c3SRobert Watson 			if (error)
14564c5eb9c3SRobert Watson 				return (error);
14574c5eb9c3SRobert Watson 		}
1458e9e7ff5bSRobert Watson 	}
1459e9e7ff5bSRobert Watson 
14604c5eb9c3SRobert Watson 	/*
14613b243b72SRobert Watson 	 * Generally, the target credential's ruid or svuid must match the
1462e9e7ff5bSRobert Watson 	 * subject credential's ruid or euid.
14634c5eb9c3SRobert Watson 	 */
1464b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid &&
1465b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid &&
1466b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid &&
1467b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) {
14684c5eb9c3SRobert Watson 		/* Not permitted, try privilege. */
14694c5eb9c3SRobert Watson 		error = suser_xxx(NULL, p1, PRISON_ROOT);
14704c5eb9c3SRobert Watson 		if (error)
14714c5eb9c3SRobert Watson 			return (error);
14724c5eb9c3SRobert Watson 	}
1473387d2c03SRobert Watson 
1474387d2c03SRobert Watson         return (0);
1475387d2c03SRobert Watson }
1476a9e0361bSPoul-Henning Kamp 
14777fd6a959SRobert Watson /*-
14787fd6a959SRobert Watson  * Determine whether p1 may reschedule p2
14797fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
14803b243b72SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
14813b243b72SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
14827fd6a959SRobert Watson  *        be held for p2.
14833b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
14843b243b72SRobert Watson  */
1485a0f75161SRobert Watson int
1486a0f75161SRobert Watson p_cansched(struct proc *p1, struct proc *p2)
1487387d2c03SRobert Watson {
148891421ba2SRobert Watson 	int error;
1489387d2c03SRobert Watson 
1490387d2c03SRobert Watson 	if (p1 == p2)
1491387d2c03SRobert Watson 		return (0);
149291421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
149391421ba2SRobert Watson 		return (error);
1494b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid)
1495387d2c03SRobert Watson 		return (0);
1496b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid)
1497387d2c03SRobert Watson 		return (0);
14987fd6a959SRobert Watson 	if (suser_xxx(0, p1, PRISON_ROOT) == 0)
1499387d2c03SRobert Watson 		return (0);
1500387d2c03SRobert Watson 
1501387d2c03SRobert Watson #ifdef CAPABILITIES
1502a0f75161SRobert Watson 	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT))
1503387d2c03SRobert Watson 		return (0);
1504387d2c03SRobert Watson #endif
1505387d2c03SRobert Watson 
1506387d2c03SRobert Watson 	return (EPERM);
1507387d2c03SRobert Watson }
1508387d2c03SRobert Watson 
15093b243b72SRobert Watson /*
15107fd6a959SRobert Watson  * The kern_unprivileged_procdebug_permitted flag may be used to disable
15113b243b72SRobert Watson  * a variety of unprivileged inter-process debugging services, including
15123b243b72SRobert Watson  * some procfs functionality, ptrace(), and ktrace().  In the past,
15133b243b72SRobert Watson  * inter-process debugging has been involved in a variety of security
15143b243b72SRobert Watson  * problems, and sites not requiring the service might choose to disable it
15153b243b72SRobert Watson  * when hardening systems.
15163b243b72SRobert Watson  *
15173b243b72SRobert Watson  * XXX: Should modifying and reading this variable require locking?
15183b243b72SRobert Watson  */
15190ef5652eSRobert Watson static int	kern_unprivileged_procdebug_permitted = 1;
15200ef5652eSRobert Watson SYSCTL_INT(_kern_security, OID_AUTO, unprivileged_procdebug_permitted,
15210ef5652eSRobert Watson     CTLFLAG_RW, &kern_unprivileged_procdebug_permitted, 0,
15220ef5652eSRobert Watson     "Unprivileged processes may use process debugging facilities");
15230ef5652eSRobert Watson 
15247fd6a959SRobert Watson /*-
15257fd6a959SRobert Watson  * Determine whether p1 may debug p2.
15267fd6a959SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
15277fd6a959SRobert Watson  * Locks: Sufficient locks to protect various components of p1 and p2
15287fd6a959SRobert Watson  *        must be held.  Normally, p1 will be curproc, and a lock must
15297fd6a959SRobert Watson  *        be held for p2.
15303b243b72SRobert Watson  * References: p1 and p2 must be valid for the lifetime of the call
15313b243b72SRobert Watson  */
1532a0f75161SRobert Watson int
1533a0f75161SRobert Watson p_candebug(struct proc *p1, struct proc *p2)
1534387d2c03SRobert Watson {
1535387d2c03SRobert Watson 	int error;
1536387d2c03SRobert Watson 
153791421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
153891421ba2SRobert Watson 		return (error);
1539387d2c03SRobert Watson 
15407fd6a959SRobert Watson 	/*
15417fd6a959SRobert Watson 	 * Not owned by you, has done setuid (unless you're root).
15427fd6a959SRobert Watson 	 * XXX add a CAP_SYS_PTRACE here?
15437fd6a959SRobert Watson 	 */
1544b1fc0ec1SRobert Watson 	if (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid ||
1545b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid ||
1546b1fc0ec1SRobert Watson 	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid ||
15477fd6a959SRobert Watson 	    p2->p_flag & P_SUGID || !kern_unprivileged_procdebug_permitted) {
15487fd6a959SRobert Watson 		if ((error = suser_xxx(0, p1, PRISON_ROOT)) != 0)
1549387d2c03SRobert Watson 			return (error);
15507fd6a959SRobert Watson 	}
1551387d2c03SRobert Watson 
15523ca719f1SRobert Watson 	/* can't trace init when securelevel > 0 */
15533ca719f1SRobert Watson 	if (p2->p_pid == 1) {
15543ca719f1SRobert Watson 		error = securelevel_gt(p1->p_ucred, 0);
15553ca719f1SRobert Watson 		if (error)
15563ca719f1SRobert Watson 			return (error);
15573ca719f1SRobert Watson 	}
1558387d2c03SRobert Watson 
1559387d2c03SRobert Watson 	return (0);
1560387d2c03SRobert Watson }
1561387d2c03SRobert Watson 
1562a9e0361bSPoul-Henning Kamp /*
1563df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1564df8bae1dSRodney W. Grimes  */
1565df8bae1dSRodney W. Grimes struct ucred *
1566df8bae1dSRodney W. Grimes crget()
1567df8bae1dSRodney W. Grimes {
1568df8bae1dSRodney W. Grimes 	register struct ucred *cr;
1569df8bae1dSRodney W. Grimes 
15701e5d626aSAlfred Perlstein 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
1571df8bae1dSRodney W. Grimes 	cr->cr_ref = 1;
15721e5d626aSAlfred Perlstein 	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
1573df8bae1dSRodney W. Grimes 	return (cr);
1574df8bae1dSRodney W. Grimes }
1575df8bae1dSRodney W. Grimes 
1576df8bae1dSRodney W. Grimes /*
15777fd6a959SRobert Watson  * Claim another reference to a ucred structure.
15785c3f70d7SAlfred Perlstein  */
15795c3f70d7SAlfred Perlstein void
15805c3f70d7SAlfred Perlstein crhold(cr)
15815c3f70d7SAlfred Perlstein 	struct ucred *cr;
15825c3f70d7SAlfred Perlstein {
15835c3f70d7SAlfred Perlstein 
15849ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
15855c3f70d7SAlfred Perlstein 	cr->cr_ref++;
15869ed346baSBosko Milekic 	mtx_unlock(&(cr)->cr_mtx);
15875c3f70d7SAlfred Perlstein }
15885c3f70d7SAlfred Perlstein 
15895c3f70d7SAlfred Perlstein 
15905c3f70d7SAlfred Perlstein /*
1591df8bae1dSRodney W. Grimes  * Free a cred structure.
1592df8bae1dSRodney W. Grimes  * Throws away space when ref count gets to 0.
1593df8bae1dSRodney W. Grimes  */
159426f9a767SRodney W. Grimes void
1595df8bae1dSRodney W. Grimes crfree(cr)
1596df8bae1dSRodney W. Grimes 	struct ucred *cr;
1597df8bae1dSRodney W. Grimes {
15981e5d626aSAlfred Perlstein 
15999ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
1600e04670b7SAlfred Perlstein 	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1601f535380cSDon Lewis 	if (--cr->cr_ref == 0) {
16021e5d626aSAlfred Perlstein 		mtx_destroy(&cr->cr_mtx);
1603f535380cSDon Lewis 		/*
1604f535380cSDon Lewis 		 * Some callers of crget(), such as nfs_statfs(),
1605f535380cSDon Lewis 		 * allocate a temporary credential, but don't
1606f535380cSDon Lewis 		 * allocate a uidinfo structure.
1607f535380cSDon Lewis 		 */
1608f535380cSDon Lewis 		if (cr->cr_uidinfo != NULL)
1609f535380cSDon Lewis 			uifree(cr->cr_uidinfo);
1610823c224eSRobert Watson 		if (cr->cr_ruidinfo != NULL)
1611823c224eSRobert Watson 			uifree(cr->cr_ruidinfo);
161291421ba2SRobert Watson 		/*
161391421ba2SRobert Watson 		 * Free a prison, if any.
161491421ba2SRobert Watson 		 */
161591421ba2SRobert Watson 		if (jailed(cr))
161691421ba2SRobert Watson 			prison_free(cr->cr_prison);
1617df8bae1dSRodney W. Grimes 		FREE((caddr_t)cr, M_CRED);
16181e5d626aSAlfred Perlstein 	} else {
16199ed346baSBosko Milekic 		mtx_unlock(&cr->cr_mtx);
1620df8bae1dSRodney W. Grimes 	}
1621f535380cSDon Lewis }
1622df8bae1dSRodney W. Grimes 
1623df8bae1dSRodney W. Grimes /*
1624df8bae1dSRodney W. Grimes  * Copy cred structure to a new one and free the old one.
1625df8bae1dSRodney W. Grimes  */
1626df8bae1dSRodney W. Grimes struct ucred *
1627df8bae1dSRodney W. Grimes crcopy(cr)
1628df8bae1dSRodney W. Grimes 	struct ucred *cr;
1629df8bae1dSRodney W. Grimes {
1630df8bae1dSRodney W. Grimes 	struct ucred *newcr;
1631df8bae1dSRodney W. Grimes 
16329ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
16331e5d626aSAlfred Perlstein 	if (cr->cr_ref == 1) {
16349ed346baSBosko Milekic 		mtx_unlock(&cr->cr_mtx);
1635df8bae1dSRodney W. Grimes 		return (cr);
16361e5d626aSAlfred Perlstein 	}
16379ed346baSBosko Milekic 	mtx_unlock(&cr->cr_mtx);
16381e5d626aSAlfred Perlstein 	newcr = crdup(cr);
1639df8bae1dSRodney W. Grimes 	crfree(cr);
1640df8bae1dSRodney W. Grimes 	return (newcr);
1641df8bae1dSRodney W. Grimes }
1642df8bae1dSRodney W. Grimes 
1643df8bae1dSRodney W. Grimes /*
1644df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
1645df8bae1dSRodney W. Grimes  */
1646df8bae1dSRodney W. Grimes struct ucred *
1647df8bae1dSRodney W. Grimes crdup(cr)
1648df8bae1dSRodney W. Grimes 	struct ucred *cr;
1649df8bae1dSRodney W. Grimes {
1650df8bae1dSRodney W. Grimes 	struct ucred *newcr;
1651df8bae1dSRodney W. Grimes 
16521e5d626aSAlfred Perlstein 	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
1653df8bae1dSRodney W. Grimes 	*newcr = *cr;
16541e5d626aSAlfred Perlstein 	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
1655f535380cSDon Lewis 	uihold(newcr->cr_uidinfo);
1656b1fc0ec1SRobert Watson 	uihold(newcr->cr_ruidinfo);
165791421ba2SRobert Watson 	if (jailed(newcr))
165891421ba2SRobert Watson 		prison_hold(newcr->cr_prison);
1659df8bae1dSRodney W. Grimes 	newcr->cr_ref = 1;
1660df8bae1dSRodney W. Grimes 	return (newcr);
1661df8bae1dSRodney W. Grimes }
1662df8bae1dSRodney W. Grimes 
1663df8bae1dSRodney W. Grimes /*
1664df8bae1dSRodney W. Grimes  * Get login name, if available.
1665df8bae1dSRodney W. Grimes  */
1666d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1667df8bae1dSRodney W. Grimes struct getlogin_args {
1668df8bae1dSRodney W. Grimes 	char	*namebuf;
1669df8bae1dSRodney W. Grimes 	u_int	namelen;
1670df8bae1dSRodney W. Grimes };
1671d2d3e875SBruce Evans #endif
1672835a82eeSMatthew Dillon /*
1673835a82eeSMatthew Dillon  * MPSAFE
1674835a82eeSMatthew Dillon  */
1675df8bae1dSRodney W. Grimes /* ARGSUSED */
167626f9a767SRodney W. Grimes int
1677b40ce416SJulian Elischer getlogin(td, uap)
1678b40ce416SJulian Elischer 	struct thread *td;
1679df8bae1dSRodney W. Grimes 	struct getlogin_args *uap;
1680df8bae1dSRodney W. Grimes {
1681835a82eeSMatthew Dillon 	int error;
1682b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1683df8bae1dSRodney W. Grimes 
1684835a82eeSMatthew Dillon 	mtx_lock(&Giant);
168530cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
168653490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
1687835a82eeSMatthew Dillon 	error = copyout((caddr_t) p->p_pgrp->pg_session->s_login,
1688835a82eeSMatthew Dillon 	    (caddr_t) uap->namebuf, uap->namelen);
1689835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1690835a82eeSMatthew Dillon 	return(error);
1691df8bae1dSRodney W. Grimes }
1692df8bae1dSRodney W. Grimes 
1693df8bae1dSRodney W. Grimes /*
1694df8bae1dSRodney W. Grimes  * Set login name.
1695df8bae1dSRodney W. Grimes  */
1696d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1697df8bae1dSRodney W. Grimes struct setlogin_args {
1698df8bae1dSRodney W. Grimes 	char	*namebuf;
1699df8bae1dSRodney W. Grimes };
1700d2d3e875SBruce Evans #endif
1701835a82eeSMatthew Dillon /*
1702835a82eeSMatthew Dillon  * MPSAFE
1703835a82eeSMatthew Dillon  */
1704df8bae1dSRodney W. Grimes /* ARGSUSED */
170526f9a767SRodney W. Grimes int
1706b40ce416SJulian Elischer setlogin(td, uap)
1707b40ce416SJulian Elischer 	struct thread *td;
1708df8bae1dSRodney W. Grimes 	struct setlogin_args *uap;
1709df8bae1dSRodney W. Grimes {
1710b40ce416SJulian Elischer 	struct proc *p = td->td_proc;
1711df8bae1dSRodney W. Grimes 	int error;
1712964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
1713df8bae1dSRodney W. Grimes 
1714835a82eeSMatthew Dillon 	mtx_lock(&Giant);
171575c13541SPoul-Henning Kamp 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
1716835a82eeSMatthew Dillon 		goto done2;
1717184989c2SDavid Nugent 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
171810d4743fSDoug Rabson 	    sizeof(logintmp), (size_t *)0);
1719835a82eeSMatthew Dillon 	if (error == ENAMETOOLONG) {
1720df8bae1dSRodney W. Grimes 		error = EINVAL;
1721835a82eeSMatthew Dillon 	} else if (!error) {
1722184989c2SDavid Nugent 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
1723964ca0caSAndrey A. Chernov 		    sizeof(logintmp));
1724835a82eeSMatthew Dillon 	}
1725835a82eeSMatthew Dillon done2:
1726835a82eeSMatthew Dillon 	mtx_unlock(&Giant);
1727df8bae1dSRodney W. Grimes 	return (error);
1728df8bae1dSRodney W. Grimes }
1729d5f81602SSean Eric Fagan 
1730d5f81602SSean Eric Fagan void
1731d5f81602SSean Eric Fagan setsugid(p)
1732d5f81602SSean Eric Fagan 	struct proc *p;
1733d5f81602SSean Eric Fagan {
1734d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
173589361835SSean Eric Fagan 	if (!(p->p_pfsflags & PF_ISUGID))
1736d5f81602SSean Eric Fagan 		p->p_stops = 0;
1737d5f81602SSean Eric Fagan }
1738f535380cSDon Lewis 
17397fd6a959SRobert Watson /*-
17407fd6a959SRobert Watson  * Change a process's effective uid.
1741b1fc0ec1SRobert Watson  * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
1742b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1743b1fc0ec1SRobert Watson  *             duration of the call.
1744f535380cSDon Lewis  */
1745f535380cSDon Lewis void
1746b1fc0ec1SRobert Watson change_euid(newcred, euid)
1747b1fc0ec1SRobert Watson 	struct ucred *newcred;
1748f535380cSDon Lewis 	uid_t euid;
1749f535380cSDon Lewis {
1750f535380cSDon Lewis 
1751b1fc0ec1SRobert Watson 	newcred->cr_uid = euid;
1752b1fc0ec1SRobert Watson 	uifree(newcred->cr_uidinfo);
1753b1fc0ec1SRobert Watson 	newcred->cr_uidinfo = uifind(euid);
1754f535380cSDon Lewis }
1755f535380cSDon Lewis 
17567fd6a959SRobert Watson /*-
17577fd6a959SRobert Watson  * Change a process's effective gid.
1758b1fc0ec1SRobert Watson  * Side effects: newcred->cr_gid will be modified.
1759b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1760b1fc0ec1SRobert Watson  *             duration of the call.
1761f535380cSDon Lewis  */
1762810bfc8eSAndrew Gallatin void
1763b1fc0ec1SRobert Watson change_egid(newcred, egid)
1764b1fc0ec1SRobert Watson 	struct ucred *newcred;
1765b1fc0ec1SRobert Watson 	gid_t egid;
1766b1fc0ec1SRobert Watson {
1767b1fc0ec1SRobert Watson 
1768b1fc0ec1SRobert Watson 	newcred->cr_groups[0] = egid;
1769b1fc0ec1SRobert Watson }
1770b1fc0ec1SRobert Watson 
17717fd6a959SRobert Watson /*-
17727fd6a959SRobert Watson  * Change a process's real uid.
1773b1fc0ec1SRobert Watson  * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
1774b1fc0ec1SRobert Watson  *               will be updated, and the old and new cr_ruidinfo proc
1775b1fc0ec1SRobert Watson  *               counts will be updated.
1776b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1777b1fc0ec1SRobert Watson  *             duration of the call.
1778b1fc0ec1SRobert Watson  */
1779b1fc0ec1SRobert Watson void
1780b1fc0ec1SRobert Watson change_ruid(newcred, ruid)
1781b1fc0ec1SRobert Watson 	struct ucred *newcred;
1782f535380cSDon Lewis 	uid_t ruid;
1783f535380cSDon Lewis {
1784f535380cSDon Lewis 
1785b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
1786b1fc0ec1SRobert Watson 	newcred->cr_ruid = ruid;
1787b1fc0ec1SRobert Watson 	uifree(newcred->cr_ruidinfo);
1788b1fc0ec1SRobert Watson 	newcred->cr_ruidinfo = uifind(ruid);
1789b1fc0ec1SRobert Watson 	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
1790b1fc0ec1SRobert Watson }
1791b1fc0ec1SRobert Watson 
17927fd6a959SRobert Watson /*-
17937fd6a959SRobert Watson  * Change a process's real gid.
1794b1fc0ec1SRobert Watson  * Side effects: newcred->cr_rgid will be updated.
1795b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1796b1fc0ec1SRobert Watson  *             duration of the call.
1797b1fc0ec1SRobert Watson  */
1798b1fc0ec1SRobert Watson void
1799b1fc0ec1SRobert Watson change_rgid(newcred, rgid)
1800b1fc0ec1SRobert Watson 	struct ucred *newcred;
1801b1fc0ec1SRobert Watson 	gid_t rgid;
1802b1fc0ec1SRobert Watson {
1803b1fc0ec1SRobert Watson 
1804b1fc0ec1SRobert Watson 	newcred->cr_rgid = rgid;
1805b1fc0ec1SRobert Watson }
1806b1fc0ec1SRobert Watson 
18077fd6a959SRobert Watson /*-
18087fd6a959SRobert Watson  * Change a process's saved uid.
1809b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svuid will be updated.
1810b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1811b1fc0ec1SRobert Watson  *             duration of the call.
1812b1fc0ec1SRobert Watson  */
1813b1fc0ec1SRobert Watson void
1814b1fc0ec1SRobert Watson change_svuid(newcred, svuid)
1815b1fc0ec1SRobert Watson 	struct ucred *newcred;
1816b1fc0ec1SRobert Watson 	uid_t svuid;
1817b1fc0ec1SRobert Watson {
1818b1fc0ec1SRobert Watson 
1819b1fc0ec1SRobert Watson 	newcred->cr_svuid = svuid;
1820b1fc0ec1SRobert Watson }
1821b1fc0ec1SRobert Watson 
18227fd6a959SRobert Watson /*-
18237fd6a959SRobert Watson  * Change a process's saved gid.
1824b1fc0ec1SRobert Watson  * Side effects: newcred->cr_svgid will be updated.
1825b1fc0ec1SRobert Watson  * References: newcred must be an exclusive credential reference for the
1826b1fc0ec1SRobert Watson  *             duration of the call.
1827b1fc0ec1SRobert Watson  */
1828b1fc0ec1SRobert Watson void
1829b1fc0ec1SRobert Watson change_svgid(newcred, svgid)
1830b1fc0ec1SRobert Watson 	struct ucred *newcred;
1831b1fc0ec1SRobert Watson 	gid_t svgid;
1832b1fc0ec1SRobert Watson {
1833b1fc0ec1SRobert Watson 
1834b1fc0ec1SRobert Watson 	newcred->cr_svgid = svgid;
1835f535380cSDon Lewis }
1836