xref: /freebsd/sys/kern/kern_prot.c (revision 130d0157d13bdaa424c0702fea915d1e2bdc6c77)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  * (c) UNIX System Laboratories, Inc.
5df8bae1dSRodney W. Grimes  * All or some portions of this file are derived from material licensed
6df8bae1dSRodney W. Grimes  * to the University of California by American Telephone and Telegraph
7df8bae1dSRodney W. Grimes  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8df8bae1dSRodney W. Grimes  * the permission of UNIX System Laboratories, Inc.
9df8bae1dSRodney W. Grimes  *
10df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
11df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
12df8bae1dSRodney W. Grimes  * are met:
13df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
14df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
15df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
16df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
17df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
19df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
20df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
21df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
22df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
23df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
24df8bae1dSRodney W. Grimes  *    without specific prior written permission.
25df8bae1dSRodney W. Grimes  *
26df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
37df8bae1dSRodney W. Grimes  *
38df8bae1dSRodney W. Grimes  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
39c3aac50fSPeter Wemm  * $FreeBSD$
40df8bae1dSRodney W. Grimes  */
41df8bae1dSRodney W. Grimes 
42df8bae1dSRodney W. Grimes /*
43df8bae1dSRodney W. Grimes  * System calls related to processes and protection
44df8bae1dSRodney W. Grimes  */
45df8bae1dSRodney W. Grimes 
465591b823SEivind Eklund #include "opt_compat.h"
47130d0157SRobert Watson #include "opt_global.h"
485591b823SEivind Eklund 
49df8bae1dSRodney W. Grimes #include <sys/param.h>
50df8bae1dSRodney W. Grimes #include <sys/acct.h>
51df8bae1dSRodney W. Grimes #include <sys/systm.h>
52d2d3e875SBruce Evans #include <sys/sysproto.h>
531c5bb3eaSPeter Wemm #include <sys/kernel.h>
5498f03f90SJake Burkholder #include <sys/lock.h>
55df8bae1dSRodney W. Grimes #include <sys/proc.h>
56df8bae1dSRodney W. Grimes #include <sys/malloc.h>
57d5f81602SSean Eric Fagan #include <sys/pioctl.h>
58f535380cSDon Lewis #include <sys/resourcevar.h>
59579f4eb4SRobert Watson #include <sys/sysctl.h>
6091421ba2SRobert Watson #include <sys/jail.h>
61df8bae1dSRodney W. Grimes 
62a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials");
63a1c995b6SPoul-Henning Kamp 
64d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
65ad7507e2SSteven Wallace struct getpid_args {
66df8bae1dSRodney W. Grimes 	int	dummy;
67df8bae1dSRodney W. Grimes };
68d2d3e875SBruce Evans #endif
69df8bae1dSRodney W. Grimes 
7036e9f877SMatthew Dillon /*
7198f03f90SJake Burkholder  * getpid - MP SAFE
7236e9f877SMatthew Dillon  */
7398f03f90SJake Burkholder 
74df8bae1dSRodney W. Grimes /* ARGSUSED */
7526f9a767SRodney W. Grimes int
76cb226aaaSPoul-Henning Kamp getpid(p, uap)
77df8bae1dSRodney W. Grimes 	struct proc *p;
78ad7507e2SSteven Wallace 	struct getpid_args *uap;
79df8bae1dSRodney W. Grimes {
80df8bae1dSRodney W. Grimes 
81cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_pid;
82df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
83bae3a80bSJohn Baldwin 	PROC_LOCK(p);
84cb226aaaSPoul-Henning Kamp 	p->p_retval[1] = p->p_pptr->p_pid;
85bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
86df8bae1dSRodney W. Grimes #endif
87df8bae1dSRodney W. Grimes 	return (0);
88df8bae1dSRodney W. Grimes }
89df8bae1dSRodney W. Grimes 
9098f03f90SJake Burkholder /*
9198f03f90SJake Burkholder  * getppid - MP SAFE
9298f03f90SJake Burkholder  */
9398f03f90SJake Burkholder 
94d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
95ad7507e2SSteven Wallace struct getppid_args {
96ad7507e2SSteven Wallace         int     dummy;
97ad7507e2SSteven Wallace };
98d2d3e875SBruce Evans #endif
99df8bae1dSRodney W. Grimes /* ARGSUSED */
10026f9a767SRodney W. Grimes int
101cb226aaaSPoul-Henning Kamp getppid(p, uap)
102df8bae1dSRodney W. Grimes 	struct proc *p;
103ad7507e2SSteven Wallace 	struct getppid_args *uap;
104df8bae1dSRodney W. Grimes {
105df8bae1dSRodney W. Grimes 
106bae3a80bSJohn Baldwin 	PROC_LOCK(p);
107cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_pptr->p_pid;
108bae3a80bSJohn Baldwin 	PROC_UNLOCK(p);
109df8bae1dSRodney W. Grimes 	return (0);
110df8bae1dSRodney W. Grimes }
111df8bae1dSRodney W. Grimes 
11236e9f877SMatthew Dillon /*
11336e9f877SMatthew Dillon  * Get process group ID; note that POSIX getpgrp takes no parameter
11436e9f877SMatthew Dillon  *
11536e9f877SMatthew Dillon  * MP SAFE
11636e9f877SMatthew Dillon  */
117d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
118ad7507e2SSteven Wallace struct getpgrp_args {
119ad7507e2SSteven Wallace         int     dummy;
120ad7507e2SSteven Wallace };
121d2d3e875SBruce Evans #endif
122ad7507e2SSteven Wallace 
12326f9a767SRodney W. Grimes int
124cb226aaaSPoul-Henning Kamp getpgrp(p, uap)
125df8bae1dSRodney W. Grimes 	struct proc *p;
126ad7507e2SSteven Wallace 	struct getpgrp_args *uap;
127df8bae1dSRodney W. Grimes {
128df8bae1dSRodney W. Grimes 
129cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_pgrp->pg_id;
130df8bae1dSRodney W. Grimes 	return (0);
131df8bae1dSRodney W. Grimes }
132df8bae1dSRodney W. Grimes 
1331a5018a0SPeter Wemm /* Get an arbitary pid's process group id */
1341a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1351a5018a0SPeter Wemm struct getpgid_args {
1361a5018a0SPeter Wemm 	pid_t	pid;
1371a5018a0SPeter Wemm };
1381a5018a0SPeter Wemm #endif
1391a5018a0SPeter Wemm 
1401a5018a0SPeter Wemm int
141cb226aaaSPoul-Henning Kamp getpgid(p, uap)
1421a5018a0SPeter Wemm 	struct proc *p;
1431a5018a0SPeter Wemm 	struct getpgid_args *uap;
1441a5018a0SPeter Wemm {
14565de0c7aSDon Lewis 	struct proc *pt;
14665de0c7aSDon Lewis 
14765de0c7aSDon Lewis 	pt = p;
1481a5018a0SPeter Wemm 	if (uap->pid == 0)
1491a5018a0SPeter Wemm 		goto found;
1501a5018a0SPeter Wemm 
15165de0c7aSDon Lewis 	if ((pt = pfind(uap->pid)) == 0)
1521a5018a0SPeter Wemm 		return ESRCH;
1531a5018a0SPeter Wemm found:
15465de0c7aSDon Lewis 	p->p_retval[0] = pt->p_pgrp->pg_id;
1551a5018a0SPeter Wemm 	return 0;
1561a5018a0SPeter Wemm }
1571a5018a0SPeter Wemm 
1581a5018a0SPeter Wemm /*
1591a5018a0SPeter Wemm  * Get an arbitary pid's session id.
1601a5018a0SPeter Wemm  */
1611a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1621a5018a0SPeter Wemm struct getsid_args {
1631a5018a0SPeter Wemm 	pid_t	pid;
1641a5018a0SPeter Wemm };
1651a5018a0SPeter Wemm #endif
1661a5018a0SPeter Wemm 
1671a5018a0SPeter Wemm int
168cb226aaaSPoul-Henning Kamp getsid(p, uap)
1691a5018a0SPeter Wemm 	struct proc *p;
1701a5018a0SPeter Wemm 	struct getsid_args *uap;
1711a5018a0SPeter Wemm {
17265de0c7aSDon Lewis 	struct proc *pt;
17365de0c7aSDon Lewis 
17465de0c7aSDon Lewis 	pt = p;
1751a5018a0SPeter Wemm 	if (uap->pid == 0)
1761a5018a0SPeter Wemm 		goto found;
1771a5018a0SPeter Wemm 
1784c061a9dSBen Smithurst 	if ((pt = pfind(uap->pid)) == 0)
1791a5018a0SPeter Wemm 		return ESRCH;
1801a5018a0SPeter Wemm found:
18165de0c7aSDon Lewis 	p->p_retval[0] = pt->p_session->s_sid;
1821a5018a0SPeter Wemm 	return 0;
1831a5018a0SPeter Wemm }
1841a5018a0SPeter Wemm 
1851a5018a0SPeter Wemm 
1867c8fdcbdSMatthew Dillon /*
1877c8fdcbdSMatthew Dillon  * getuid() - MP SAFE
1887c8fdcbdSMatthew Dillon  */
189d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
190ad7507e2SSteven Wallace struct getuid_args {
191ad7507e2SSteven Wallace         int     dummy;
192ad7507e2SSteven Wallace };
193d2d3e875SBruce Evans #endif
194ad7507e2SSteven Wallace 
195df8bae1dSRodney W. Grimes /* ARGSUSED */
19626f9a767SRodney W. Grimes int
197cb226aaaSPoul-Henning Kamp getuid(p, uap)
198df8bae1dSRodney W. Grimes 	struct proc *p;
199ad7507e2SSteven Wallace 	struct getuid_args *uap;
200df8bae1dSRodney W. Grimes {
201df8bae1dSRodney W. Grimes 
202cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_cred->p_ruid;
203df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
204cb226aaaSPoul-Henning Kamp 	p->p_retval[1] = p->p_ucred->cr_uid;
205df8bae1dSRodney W. Grimes #endif
206df8bae1dSRodney W. Grimes 	return (0);
207df8bae1dSRodney W. Grimes }
208df8bae1dSRodney W. Grimes 
2097c8fdcbdSMatthew Dillon /*
2107c8fdcbdSMatthew Dillon  * geteuid() - MP SAFE
2117c8fdcbdSMatthew Dillon  */
212d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
213ad7507e2SSteven Wallace struct geteuid_args {
214ad7507e2SSteven Wallace         int     dummy;
215ad7507e2SSteven Wallace };
216d2d3e875SBruce Evans #endif
217ad7507e2SSteven Wallace 
218df8bae1dSRodney W. Grimes /* ARGSUSED */
21926f9a767SRodney W. Grimes int
220cb226aaaSPoul-Henning Kamp geteuid(p, uap)
221df8bae1dSRodney W. Grimes 	struct proc *p;
222ad7507e2SSteven Wallace 	struct geteuid_args *uap;
223df8bae1dSRodney W. Grimes {
224df8bae1dSRodney W. Grimes 
225cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_ucred->cr_uid;
226df8bae1dSRodney W. Grimes 	return (0);
227df8bae1dSRodney W. Grimes }
228df8bae1dSRodney W. Grimes 
2297c8fdcbdSMatthew Dillon /*
2307c8fdcbdSMatthew Dillon  * getgid() - MP SAFE
2317c8fdcbdSMatthew Dillon  */
232d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
233ad7507e2SSteven Wallace struct getgid_args {
234ad7507e2SSteven Wallace         int     dummy;
235ad7507e2SSteven Wallace };
236d2d3e875SBruce Evans #endif
237ad7507e2SSteven Wallace 
238df8bae1dSRodney W. Grimes /* ARGSUSED */
23926f9a767SRodney W. Grimes int
240cb226aaaSPoul-Henning Kamp getgid(p, uap)
241df8bae1dSRodney W. Grimes 	struct proc *p;
242ad7507e2SSteven Wallace 	struct getgid_args *uap;
243df8bae1dSRodney W. Grimes {
244df8bae1dSRodney W. Grimes 
245cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_cred->p_rgid;
246df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
247cb226aaaSPoul-Henning Kamp 	p->p_retval[1] = p->p_ucred->cr_groups[0];
248df8bae1dSRodney W. Grimes #endif
249df8bae1dSRodney W. Grimes 	return (0);
250df8bae1dSRodney W. Grimes }
251df8bae1dSRodney W. Grimes 
252df8bae1dSRodney W. Grimes /*
253df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
254df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
255df8bae1dSRodney W. Grimes  * correctly in a library function.
256df8bae1dSRodney W. Grimes  */
257d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
258ad7507e2SSteven Wallace struct getegid_args {
259ad7507e2SSteven Wallace         int     dummy;
260ad7507e2SSteven Wallace };
261d2d3e875SBruce Evans #endif
262ad7507e2SSteven Wallace 
263df8bae1dSRodney W. Grimes /* ARGSUSED */
26426f9a767SRodney W. Grimes int
265cb226aaaSPoul-Henning Kamp getegid(p, uap)
266df8bae1dSRodney W. Grimes 	struct proc *p;
267ad7507e2SSteven Wallace 	struct getegid_args *uap;
268df8bae1dSRodney W. Grimes {
269df8bae1dSRodney W. Grimes 
270cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = p->p_ucred->cr_groups[0];
271df8bae1dSRodney W. Grimes 	return (0);
272df8bae1dSRodney W. Grimes }
273df8bae1dSRodney W. Grimes 
274d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
275df8bae1dSRodney W. Grimes struct getgroups_args {
276df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
277df8bae1dSRodney W. Grimes 	gid_t	*gidset;
278df8bae1dSRodney W. Grimes };
279d2d3e875SBruce Evans #endif
28026f9a767SRodney W. Grimes int
281cb226aaaSPoul-Henning Kamp getgroups(p, uap)
282df8bae1dSRodney W. Grimes 	struct proc *p;
283df8bae1dSRodney W. Grimes 	register struct	getgroups_args *uap;
284df8bae1dSRodney W. Grimes {
285df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
286df8bae1dSRodney W. Grimes 	register u_int ngrp;
287df8bae1dSRodney W. Grimes 	int error;
288df8bae1dSRodney W. Grimes 
289df8bae1dSRodney W. Grimes 	if ((ngrp = uap->gidsetsize) == 0) {
290cb226aaaSPoul-Henning Kamp 		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
291df8bae1dSRodney W. Grimes 		return (0);
292df8bae1dSRodney W. Grimes 	}
293df8bae1dSRodney W. Grimes 	if (ngrp < pc->pc_ucred->cr_ngroups)
294df8bae1dSRodney W. Grimes 		return (EINVAL);
295df8bae1dSRodney W. Grimes 	ngrp = pc->pc_ucred->cr_ngroups;
296bb56ec4aSPoul-Henning Kamp 	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
297bb56ec4aSPoul-Henning Kamp 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
298df8bae1dSRodney W. Grimes 		return (error);
299cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = ngrp;
300df8bae1dSRodney W. Grimes 	return (0);
301df8bae1dSRodney W. Grimes }
302df8bae1dSRodney W. Grimes 
303d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
30482970b81SBruce Evans struct setsid_args {
305ad7507e2SSteven Wallace         int     dummy;
306ad7507e2SSteven Wallace };
307d2d3e875SBruce Evans #endif
308ad7507e2SSteven Wallace 
309df8bae1dSRodney W. Grimes /* ARGSUSED */
31026f9a767SRodney W. Grimes int
311cb226aaaSPoul-Henning Kamp setsid(p, uap)
312df8bae1dSRodney W. Grimes 	register struct proc *p;
31382970b81SBruce Evans 	struct setsid_args *uap;
314df8bae1dSRodney W. Grimes {
315df8bae1dSRodney W. Grimes 
316df8bae1dSRodney W. Grimes 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
317df8bae1dSRodney W. Grimes 		return (EPERM);
318df8bae1dSRodney W. Grimes 	} else {
319df8bae1dSRodney W. Grimes 		(void)enterpgrp(p, p->p_pid, 1);
320cb226aaaSPoul-Henning Kamp 		p->p_retval[0] = p->p_pid;
321df8bae1dSRodney W. Grimes 		return (0);
322df8bae1dSRodney W. Grimes 	}
323df8bae1dSRodney W. Grimes }
324df8bae1dSRodney W. Grimes 
325df8bae1dSRodney W. Grimes /*
326df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
327df8bae1dSRodney W. Grimes  *
328df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
329df8bae1dSRodney W. Grimes  *
330df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
331df8bae1dSRodney W. Grimes  * if a child
332df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
333df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
334df8bae1dSRodney W. Grimes  * if pgid != pid
335df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
336df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
337df8bae1dSRodney W. Grimes  */
338d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
339df8bae1dSRodney W. Grimes struct setpgid_args {
340df8bae1dSRodney W. Grimes 	int	pid;	/* target process id */
341df8bae1dSRodney W. Grimes 	int	pgid;	/* target pgrp id */
342df8bae1dSRodney W. Grimes };
343d2d3e875SBruce Evans #endif
344df8bae1dSRodney W. Grimes /* ARGSUSED */
34526f9a767SRodney W. Grimes int
346cb226aaaSPoul-Henning Kamp setpgid(curp, uap)
347df8bae1dSRodney W. Grimes 	struct proc *curp;
348df8bae1dSRodney W. Grimes 	register struct setpgid_args *uap;
349df8bae1dSRodney W. Grimes {
350df8bae1dSRodney W. Grimes 	register struct proc *targp;		/* target process */
351df8bae1dSRodney W. Grimes 	register struct pgrp *pgrp;		/* target pgrp */
352df8bae1dSRodney W. Grimes 
35378f64bccSBruce Evans 	if (uap->pgid < 0)
35478f64bccSBruce Evans 		return (EINVAL);
355df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
356df8bae1dSRodney W. Grimes 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
357df8bae1dSRodney W. Grimes 			return (ESRCH);
358cd73303cSDavid Greenman 		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
359df8bae1dSRodney W. Grimes 			return (EPERM);
360df8bae1dSRodney W. Grimes 		if (targp->p_flag & P_EXEC)
361df8bae1dSRodney W. Grimes 			return (EACCES);
362df8bae1dSRodney W. Grimes 	} else
363df8bae1dSRodney W. Grimes 		targp = curp;
364df8bae1dSRodney W. Grimes 	if (SESS_LEADER(targp))
365df8bae1dSRodney W. Grimes 		return (EPERM);
366df8bae1dSRodney W. Grimes 	if (uap->pgid == 0)
367df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
368df8bae1dSRodney W. Grimes 	else if (uap->pgid != targp->p_pid)
369df8bae1dSRodney W. Grimes 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
370df8bae1dSRodney W. Grimes 	            pgrp->pg_session != curp->p_session)
371df8bae1dSRodney W. Grimes 			return (EPERM);
372df8bae1dSRodney W. Grimes 	return (enterpgrp(targp, uap->pgid, 0));
373df8bae1dSRodney W. Grimes }
374df8bae1dSRodney W. Grimes 
375a08f4bf6SPeter Wemm /*
376a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
3772fa72ea7SJeroen Ruigrok van der Werven  * compatible.  It says that setting the uid/gid to euid/egid is a special
378a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
379a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
380a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
381a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
382a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
383a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
384a08f4bf6SPeter Wemm  */
385a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
386a08f4bf6SPeter Wemm 
387d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
388df8bae1dSRodney W. Grimes struct setuid_args {
389df8bae1dSRodney W. Grimes 	uid_t	uid;
390df8bae1dSRodney W. Grimes };
391d2d3e875SBruce Evans #endif
392df8bae1dSRodney W. Grimes /* ARGSUSED */
39326f9a767SRodney W. Grimes int
394cb226aaaSPoul-Henning Kamp setuid(p, uap)
395df8bae1dSRodney W. Grimes 	struct proc *p;
396df8bae1dSRodney W. Grimes 	struct setuid_args *uap;
397df8bae1dSRodney W. Grimes {
398df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
399df8bae1dSRodney W. Grimes 	register uid_t uid;
400df8bae1dSRodney W. Grimes 	int error;
401df8bae1dSRodney W. Grimes 
402a08f4bf6SPeter Wemm 	/*
403a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
404a08f4bf6SPeter Wemm 	 *
405a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
406a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
4072fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
408a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
409a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
410a08f4bf6SPeter Wemm 	 *
411a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
412a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
413a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
414a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
415a08f4bf6SPeter Wemm 	 * 2: We determine if the real and/or saved uid's are going to
416a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
417a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
418a08f4bf6SPeter Wemm 	 */
419df8bae1dSRodney W. Grimes 	uid = uap->uid;
420a08f4bf6SPeter Wemm 	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
4213f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
422a08f4bf6SPeter Wemm 	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
423a08f4bf6SPeter Wemm #endif
424a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
425a08f4bf6SPeter Wemm 	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
4263f246666SAndrey A. Chernov #endif
42775c13541SPoul-Henning Kamp 	    (error = suser_xxx(0, p, PRISON_ROOT)))
428df8bae1dSRodney W. Grimes 		return (error);
429a08f4bf6SPeter Wemm 
430a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
431df8bae1dSRodney W. Grimes 	/*
432a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
433a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
434df8bae1dSRodney W. Grimes 	 */
4353f246666SAndrey A. Chernov 	if (
436a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
437a08f4bf6SPeter Wemm 	    uid == pc->pc_ucred->cr_uid ||
4383f246666SAndrey A. Chernov #endif
43975c13541SPoul-Henning Kamp 	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
440a08f4bf6SPeter Wemm #endif
441a08f4bf6SPeter Wemm 	{
442a08f4bf6SPeter Wemm 		/*
443f535380cSDon Lewis 		 * Set the real uid and transfer proc count to new user.
444a08f4bf6SPeter Wemm 		 */
445a08f4bf6SPeter Wemm 		if (uid != pc->p_ruid) {
446f535380cSDon Lewis 			change_ruid(p, uid);
447f535380cSDon Lewis 			setsugid(p);
448d3cdb93dSAndrey A. Chernov 		}
449a08f4bf6SPeter Wemm 		/*
450a08f4bf6SPeter Wemm 		 * Set saved uid
451a08f4bf6SPeter Wemm 		 *
452a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
453a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
454a08f4bf6SPeter Wemm 		 * is important that we should do this.
455a08f4bf6SPeter Wemm 		 */
456a08f4bf6SPeter Wemm 		if (pc->p_svuid != uid) {
457a08f4bf6SPeter Wemm 			pc->p_svuid = uid;
458d5f81602SSean Eric Fagan 			setsugid(p);
459a08f4bf6SPeter Wemm 		}
460a08f4bf6SPeter Wemm 	}
461a08f4bf6SPeter Wemm 
462a08f4bf6SPeter Wemm 	/*
463a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
464a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
465a08f4bf6SPeter Wemm 	 */
466a08f4bf6SPeter Wemm 	if (pc->pc_ucred->cr_uid != uid) {
467f535380cSDon Lewis 		change_euid(p, uid);
468d5f81602SSean Eric Fagan 		setsugid(p);
469a08f4bf6SPeter Wemm 	}
470df8bae1dSRodney W. Grimes 	return (0);
471df8bae1dSRodney W. Grimes }
472df8bae1dSRodney W. Grimes 
473d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
474df8bae1dSRodney W. Grimes struct seteuid_args {
475df8bae1dSRodney W. Grimes 	uid_t	euid;
476df8bae1dSRodney W. Grimes };
477d2d3e875SBruce Evans #endif
478df8bae1dSRodney W. Grimes /* ARGSUSED */
47926f9a767SRodney W. Grimes int
480cb226aaaSPoul-Henning Kamp seteuid(p, uap)
481df8bae1dSRodney W. Grimes 	struct proc *p;
482df8bae1dSRodney W. Grimes 	struct seteuid_args *uap;
483df8bae1dSRodney W. Grimes {
484df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
485df8bae1dSRodney W. Grimes 	register uid_t euid;
486df8bae1dSRodney W. Grimes 	int error;
487df8bae1dSRodney W. Grimes 
488df8bae1dSRodney W. Grimes 	euid = uap->euid;
489229a15f0SPeter Wemm 	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
490229a15f0SPeter Wemm 	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
49175c13541SPoul-Henning Kamp 	    (error = suser_xxx(0, p, PRISON_ROOT)))
492df8bae1dSRodney W. Grimes 		return (error);
493df8bae1dSRodney W. Grimes 	/*
494df8bae1dSRodney W. Grimes 	 * Everything's okay, do it.  Copy credentials so other references do
495df8bae1dSRodney W. Grimes 	 * not see our changes.
496df8bae1dSRodney W. Grimes 	 */
497229a15f0SPeter Wemm 	if (pc->pc_ucred->cr_uid != euid) {
498f535380cSDon Lewis 		change_euid(p, euid);
499d5f81602SSean Eric Fagan 		setsugid(p);
500229a15f0SPeter Wemm 	}
501df8bae1dSRodney W. Grimes 	return (0);
502df8bae1dSRodney W. Grimes }
503df8bae1dSRodney W. Grimes 
504d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
505df8bae1dSRodney W. Grimes struct setgid_args {
506df8bae1dSRodney W. Grimes 	gid_t	gid;
507df8bae1dSRodney W. Grimes };
508d2d3e875SBruce Evans #endif
509df8bae1dSRodney W. Grimes /* ARGSUSED */
51026f9a767SRodney W. Grimes int
511cb226aaaSPoul-Henning Kamp setgid(p, uap)
512df8bae1dSRodney W. Grimes 	struct proc *p;
513df8bae1dSRodney W. Grimes 	struct setgid_args *uap;
514df8bae1dSRodney W. Grimes {
515df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
516df8bae1dSRodney W. Grimes 	register gid_t gid;
517df8bae1dSRodney W. Grimes 	int error;
518df8bae1dSRodney W. Grimes 
519a08f4bf6SPeter Wemm 	/*
520a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
521a08f4bf6SPeter Wemm 	 *
522a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
523a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
5242fa72ea7SJeroen Ruigrok van der Werven 	 * to use this clause to be compatible with traditional BSD
525a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
526a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
527a08f4bf6SPeter Wemm 	 *
528a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
529a08f4bf6SPeter Wemm 	 */
530df8bae1dSRodney W. Grimes 	gid = uap->gid;
531a08f4bf6SPeter Wemm 	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
5323f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
533a08f4bf6SPeter Wemm 	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
534a08f4bf6SPeter Wemm #endif
535a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
536a08f4bf6SPeter Wemm 	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
5373f246666SAndrey A. Chernov #endif
53875c13541SPoul-Henning Kamp 	    (error = suser_xxx(0, p, PRISON_ROOT)))
539df8bae1dSRodney W. Grimes 		return (error);
540a08f4bf6SPeter Wemm 
541a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
542a08f4bf6SPeter Wemm 	/*
543a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
544a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
545a08f4bf6SPeter Wemm 	 */
546a08f4bf6SPeter Wemm 	if (
547a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
548a08f4bf6SPeter Wemm 	    gid == pc->pc_ucred->cr_groups[0] ||
549a08f4bf6SPeter Wemm #endif
55075c13541SPoul-Henning Kamp 	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
551a08f4bf6SPeter Wemm #endif
552a08f4bf6SPeter Wemm 	{
553a08f4bf6SPeter Wemm 		/*
554a08f4bf6SPeter Wemm 		 * Set real gid
555a08f4bf6SPeter Wemm 		 */
556a08f4bf6SPeter Wemm 		if (pc->p_rgid != gid) {
557a08f4bf6SPeter Wemm 			pc->p_rgid = gid;
558d5f81602SSean Eric Fagan 			setsugid(p);
559a08f4bf6SPeter Wemm 		}
560a08f4bf6SPeter Wemm 		/*
561a08f4bf6SPeter Wemm 		 * Set saved gid
562a08f4bf6SPeter Wemm 		 *
563a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
564a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
565a08f4bf6SPeter Wemm 		 * is important that we should do this.
566a08f4bf6SPeter Wemm 		 */
567a08f4bf6SPeter Wemm 		if (pc->p_svgid != gid) {
568a08f4bf6SPeter Wemm 			pc->p_svgid = gid;
569d5f81602SSean Eric Fagan 			setsugid(p);
570a08f4bf6SPeter Wemm 		}
571a08f4bf6SPeter Wemm 	}
572a08f4bf6SPeter Wemm 	/*
573a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
574a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
575a08f4bf6SPeter Wemm 	 */
576a08f4bf6SPeter Wemm 	if (pc->pc_ucred->cr_groups[0] != gid) {
577df8bae1dSRodney W. Grimes 		pc->pc_ucred = crcopy(pc->pc_ucred);
578df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_groups[0] = gid;
579d5f81602SSean Eric Fagan 		setsugid(p);
580a08f4bf6SPeter Wemm 	}
581df8bae1dSRodney W. Grimes 	return (0);
582df8bae1dSRodney W. Grimes }
583df8bae1dSRodney W. Grimes 
584d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
585df8bae1dSRodney W. Grimes struct setegid_args {
586df8bae1dSRodney W. Grimes 	gid_t	egid;
587df8bae1dSRodney W. Grimes };
588d2d3e875SBruce Evans #endif
589df8bae1dSRodney W. Grimes /* ARGSUSED */
59026f9a767SRodney W. Grimes int
591cb226aaaSPoul-Henning Kamp setegid(p, uap)
592df8bae1dSRodney W. Grimes 	struct proc *p;
593df8bae1dSRodney W. Grimes 	struct setegid_args *uap;
594df8bae1dSRodney W. Grimes {
595df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
596df8bae1dSRodney W. Grimes 	register gid_t egid;
597df8bae1dSRodney W. Grimes 	int error;
598df8bae1dSRodney W. Grimes 
599df8bae1dSRodney W. Grimes 	egid = uap->egid;
600229a15f0SPeter Wemm 	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
601229a15f0SPeter Wemm 	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
60275c13541SPoul-Henning Kamp 	    (error = suser_xxx(0, p, PRISON_ROOT)))
603df8bae1dSRodney W. Grimes 		return (error);
604229a15f0SPeter Wemm 	if (pc->pc_ucred->cr_groups[0] != egid) {
605df8bae1dSRodney W. Grimes 		pc->pc_ucred = crcopy(pc->pc_ucred);
606df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_groups[0] = egid;
607d5f81602SSean Eric Fagan 		setsugid(p);
608229a15f0SPeter Wemm 	}
609df8bae1dSRodney W. Grimes 	return (0);
610df8bae1dSRodney W. Grimes }
611df8bae1dSRodney W. Grimes 
612d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
613df8bae1dSRodney W. Grimes struct setgroups_args {
614df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
615df8bae1dSRodney W. Grimes 	gid_t	*gidset;
616df8bae1dSRodney W. Grimes };
617d2d3e875SBruce Evans #endif
618df8bae1dSRodney W. Grimes /* ARGSUSED */
61926f9a767SRodney W. Grimes int
620cb226aaaSPoul-Henning Kamp setgroups(p, uap)
621df8bae1dSRodney W. Grimes 	struct proc *p;
622df8bae1dSRodney W. Grimes 	struct setgroups_args *uap;
623df8bae1dSRodney W. Grimes {
624df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
625df8bae1dSRodney W. Grimes 	register u_int ngrp;
626df8bae1dSRodney W. Grimes 	int error;
627df8bae1dSRodney W. Grimes 
62875c13541SPoul-Henning Kamp 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
629df8bae1dSRodney W. Grimes 		return (error);
6303956a170SDavid Greenman 	ngrp = uap->gidsetsize;
6318a5d815aSPeter Wemm 	if (ngrp > NGROUPS)
632df8bae1dSRodney W. Grimes 		return (EINVAL);
6338a5d815aSPeter Wemm 	/*
6348a5d815aSPeter Wemm 	 * XXX A little bit lazy here.  We could test if anything has
6358a5d815aSPeter Wemm 	 * changed before crcopy() and setting P_SUGID.
6368a5d815aSPeter Wemm 	 */
637df8bae1dSRodney W. Grimes 	pc->pc_ucred = crcopy(pc->pc_ucred);
6388a5d815aSPeter Wemm 	if (ngrp < 1) {
6398a5d815aSPeter Wemm 		/*
6408a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
6418a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
6428a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
6438a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
6448a5d815aSPeter Wemm 		 */
6458a5d815aSPeter Wemm 		pc->pc_ucred->cr_ngroups = 1;
6468a5d815aSPeter Wemm 	} else {
647bb56ec4aSPoul-Henning Kamp 		if ((error = copyin((caddr_t)uap->gidset,
648bb56ec4aSPoul-Henning Kamp 		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
649df8bae1dSRodney W. Grimes 			return (error);
650df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_ngroups = ngrp;
6518a5d815aSPeter Wemm 	}
652d5f81602SSean Eric Fagan 	setsugid(p);
653df8bae1dSRodney W. Grimes 	return (0);
654df8bae1dSRodney W. Grimes }
655df8bae1dSRodney W. Grimes 
656d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
657df8bae1dSRodney W. Grimes struct setreuid_args {
65800999cd6SAndrey A. Chernov 	uid_t	ruid;
65900999cd6SAndrey A. Chernov 	uid_t	euid;
660df8bae1dSRodney W. Grimes };
661d2d3e875SBruce Evans #endif
662df8bae1dSRodney W. Grimes /* ARGSUSED */
66326f9a767SRodney W. Grimes int
664cb226aaaSPoul-Henning Kamp setreuid(p, uap)
665df8bae1dSRodney W. Grimes 	register struct proc *p;
666df8bae1dSRodney W. Grimes 	struct setreuid_args *uap;
667df8bae1dSRodney W. Grimes {
668df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
66900999cd6SAndrey A. Chernov 	register uid_t ruid, euid;
670611d721eSAndrey A. Chernov 	int error;
671df8bae1dSRodney W. Grimes 
67200999cd6SAndrey A. Chernov 	ruid = uap->ruid;
67300999cd6SAndrey A. Chernov 	euid = uap->euid;
6748aef1712SMatthew Dillon 	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
6758aef1712SMatthew Dillon 	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
6768aef1712SMatthew Dillon 	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
67775c13541SPoul-Henning Kamp 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
678611d721eSAndrey A. Chernov 		return (error);
67900999cd6SAndrey A. Chernov 
680a89a5370SPeter Wemm 	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
681f535380cSDon Lewis 		change_euid(p, euid);
682d5f81602SSean Eric Fagan 		setsugid(p);
683a89a5370SPeter Wemm 	}
684a89a5370SPeter Wemm 	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
685f535380cSDon Lewis 		change_ruid(p, ruid);
686d5f81602SSean Eric Fagan 		setsugid(p);
68700999cd6SAndrey A. Chernov 	}
688b79c6a86SPeter Wemm 	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
689b79c6a86SPeter Wemm 	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6904bc8f31fSAndrey A. Chernov 		pc->p_svuid = pc->pc_ucred->cr_uid;
691d5f81602SSean Eric Fagan 		setsugid(p);
692a89a5370SPeter Wemm 	}
693611d721eSAndrey A. Chernov 	return (0);
694df8bae1dSRodney W. Grimes }
695df8bae1dSRodney W. Grimes 
696d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
697df8bae1dSRodney W. Grimes struct setregid_args {
69800999cd6SAndrey A. Chernov 	gid_t	rgid;
69900999cd6SAndrey A. Chernov 	gid_t	egid;
700df8bae1dSRodney W. Grimes };
701d2d3e875SBruce Evans #endif
702df8bae1dSRodney W. Grimes /* ARGSUSED */
70326f9a767SRodney W. Grimes int
704cb226aaaSPoul-Henning Kamp setregid(p, uap)
705df8bae1dSRodney W. Grimes 	register struct proc *p;
706df8bae1dSRodney W. Grimes 	struct setregid_args *uap;
707df8bae1dSRodney W. Grimes {
708df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
70900999cd6SAndrey A. Chernov 	register gid_t rgid, egid;
710611d721eSAndrey A. Chernov 	int error;
711df8bae1dSRodney W. Grimes 
71200999cd6SAndrey A. Chernov 	rgid = uap->rgid;
71300999cd6SAndrey A. Chernov 	egid = uap->egid;
7148aef1712SMatthew Dillon 	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
7158aef1712SMatthew Dillon 	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
7168aef1712SMatthew Dillon 	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
71775c13541SPoul-Henning Kamp 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
718611d721eSAndrey A. Chernov 		return (error);
71900999cd6SAndrey A. Chernov 
720a89a5370SPeter Wemm 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
72100999cd6SAndrey A. Chernov 		pc->pc_ucred = crcopy(pc->pc_ucred);
72200999cd6SAndrey A. Chernov 		pc->pc_ucred->cr_groups[0] = egid;
723d5f81602SSean Eric Fagan 		setsugid(p);
724a89a5370SPeter Wemm 	}
725a89a5370SPeter Wemm 	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
72600999cd6SAndrey A. Chernov 		pc->p_rgid = rgid;
727d5f81602SSean Eric Fagan 		setsugid(p);
728a89a5370SPeter Wemm 	}
729b79c6a86SPeter Wemm 	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
730b79c6a86SPeter Wemm 	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7314bc8f31fSAndrey A. Chernov 		pc->p_svgid = pc->pc_ucred->cr_groups[0];
732d5f81602SSean Eric Fagan 		setsugid(p);
733a89a5370SPeter Wemm 	}
734611d721eSAndrey A. Chernov 	return (0);
735df8bae1dSRodney W. Grimes }
736df8bae1dSRodney W. Grimes 
7378ccd6334SPeter Wemm /*
7388ccd6334SPeter Wemm  * setresuid(ruid, euid, suid) is like setreuid except control over the
7398ccd6334SPeter Wemm  * saved uid is explicit.
7408ccd6334SPeter Wemm  */
7418ccd6334SPeter Wemm 
7428ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
7438ccd6334SPeter Wemm struct setresuid_args {
7448ccd6334SPeter Wemm 	uid_t	ruid;
7458ccd6334SPeter Wemm 	uid_t	euid;
7468ccd6334SPeter Wemm 	uid_t	suid;
7478ccd6334SPeter Wemm };
7488ccd6334SPeter Wemm #endif
7498ccd6334SPeter Wemm /* ARGSUSED */
7508ccd6334SPeter Wemm int
7518ccd6334SPeter Wemm setresuid(p, uap)
7528ccd6334SPeter Wemm 	register struct proc *p;
7538ccd6334SPeter Wemm 	struct setresuid_args *uap;
7548ccd6334SPeter Wemm {
7558ccd6334SPeter Wemm 	register struct pcred *pc = p->p_cred;
7568ccd6334SPeter Wemm 	register uid_t ruid, euid, suid;
7578ccd6334SPeter Wemm 	int error;
7588ccd6334SPeter Wemm 
7598ccd6334SPeter Wemm 	ruid = uap->ruid;
7608ccd6334SPeter Wemm 	euid = uap->euid;
7618ccd6334SPeter Wemm 	suid = uap->suid;
7628ccd6334SPeter Wemm 	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
7638ccd6334SPeter Wemm 	      ruid != pc->pc_ucred->cr_uid) ||
7648ccd6334SPeter Wemm 	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
7658ccd6334SPeter Wemm 	      euid != pc->pc_ucred->cr_uid) ||
7668ccd6334SPeter Wemm 	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
7678ccd6334SPeter Wemm 	      suid != pc->pc_ucred->cr_uid)) &&
7688ccd6334SPeter Wemm 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
7698ccd6334SPeter Wemm 		return (error);
7708ccd6334SPeter Wemm 	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
771f535380cSDon Lewis 		change_euid(p, euid);
7728ccd6334SPeter Wemm 		setsugid(p);
7738ccd6334SPeter Wemm 	}
7748ccd6334SPeter Wemm 	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
775f535380cSDon Lewis 		change_ruid(p, ruid);
7768ccd6334SPeter Wemm 		setsugid(p);
7778ccd6334SPeter Wemm 	}
7788ccd6334SPeter Wemm 	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
7798ccd6334SPeter Wemm 		pc->p_svuid = suid;
7808ccd6334SPeter Wemm 		setsugid(p);
7818ccd6334SPeter Wemm 	}
7828ccd6334SPeter Wemm 	return (0);
7838ccd6334SPeter Wemm }
7848ccd6334SPeter Wemm 
7858ccd6334SPeter Wemm /*
7868ccd6334SPeter Wemm  * setresgid(rgid, egid, sgid) is like setregid except control over the
7878ccd6334SPeter Wemm  * saved gid is explicit.
7888ccd6334SPeter Wemm  */
7898ccd6334SPeter Wemm 
7908ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
7918ccd6334SPeter Wemm struct setresgid_args {
7928ccd6334SPeter Wemm 	gid_t	rgid;
7938ccd6334SPeter Wemm 	gid_t	egid;
7948ccd6334SPeter Wemm 	gid_t	sgid;
7958ccd6334SPeter Wemm };
7968ccd6334SPeter Wemm #endif
7978ccd6334SPeter Wemm /* ARGSUSED */
7988ccd6334SPeter Wemm int
7998ccd6334SPeter Wemm setresgid(p, uap)
8008ccd6334SPeter Wemm 	register struct proc *p;
8018ccd6334SPeter Wemm 	struct setresgid_args *uap;
8028ccd6334SPeter Wemm {
8038ccd6334SPeter Wemm 	register struct pcred *pc = p->p_cred;
8048ccd6334SPeter Wemm 	register gid_t rgid, egid, sgid;
8058ccd6334SPeter Wemm 	int error;
8068ccd6334SPeter Wemm 
8078ccd6334SPeter Wemm 	rgid = uap->rgid;
8088ccd6334SPeter Wemm 	egid = uap->egid;
8098ccd6334SPeter Wemm 	sgid = uap->sgid;
8108ccd6334SPeter Wemm 	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
8118ccd6334SPeter Wemm 	      rgid != pc->pc_ucred->cr_groups[0]) ||
8128ccd6334SPeter Wemm 	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
8138ccd6334SPeter Wemm 	      egid != pc->pc_ucred->cr_groups[0]) ||
8148ccd6334SPeter Wemm 	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
8158ccd6334SPeter Wemm 	      sgid != pc->pc_ucred->cr_groups[0])) &&
8168ccd6334SPeter Wemm 	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
8178ccd6334SPeter Wemm 		return (error);
8188ccd6334SPeter Wemm 
8198ccd6334SPeter Wemm 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
8208ccd6334SPeter Wemm 		pc->pc_ucred = crcopy(pc->pc_ucred);
8218ccd6334SPeter Wemm 		pc->pc_ucred->cr_groups[0] = egid;
8228ccd6334SPeter Wemm 		setsugid(p);
8238ccd6334SPeter Wemm 	}
8248ccd6334SPeter Wemm 	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
8258ccd6334SPeter Wemm 		pc->p_rgid = rgid;
8268ccd6334SPeter Wemm 		setsugid(p);
8278ccd6334SPeter Wemm 	}
8288ccd6334SPeter Wemm 	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
8298ccd6334SPeter Wemm 		pc->p_svgid = sgid;
8308ccd6334SPeter Wemm 		setsugid(p);
8318ccd6334SPeter Wemm 	}
8328ccd6334SPeter Wemm 	return (0);
8338ccd6334SPeter Wemm }
8348ccd6334SPeter Wemm 
8358ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
8368ccd6334SPeter Wemm struct getresuid_args {
8378ccd6334SPeter Wemm 	uid_t	*ruid;
8388ccd6334SPeter Wemm 	uid_t	*euid;
8398ccd6334SPeter Wemm 	uid_t	*suid;
8408ccd6334SPeter Wemm };
8418ccd6334SPeter Wemm #endif
8428ccd6334SPeter Wemm /* ARGSUSED */
8438ccd6334SPeter Wemm int
8448ccd6334SPeter Wemm getresuid(p, uap)
8458ccd6334SPeter Wemm 	register struct proc *p;
8468ccd6334SPeter Wemm 	struct getresuid_args *uap;
8478ccd6334SPeter Wemm {
8488ccd6334SPeter Wemm 	struct pcred *pc = p->p_cred;
8498ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
8508ccd6334SPeter Wemm 
8518ccd6334SPeter Wemm 	if (uap->ruid)
8528ccd6334SPeter Wemm 		error1 = copyout((caddr_t)&pc->p_ruid,
8538ccd6334SPeter Wemm 		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
8548ccd6334SPeter Wemm 	if (uap->euid)
8558ccd6334SPeter Wemm 		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
8568ccd6334SPeter Wemm 		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
8578ccd6334SPeter Wemm 	if (uap->suid)
8588ccd6334SPeter Wemm 		error3 = copyout((caddr_t)&pc->p_svuid,
8598ccd6334SPeter Wemm 		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
8608ccd6334SPeter Wemm 	return error1 ? error1 : (error2 ? error2 : error3);
8618ccd6334SPeter Wemm }
8628ccd6334SPeter Wemm 
8638ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_
8648ccd6334SPeter Wemm struct getresgid_args {
8658ccd6334SPeter Wemm 	gid_t	*rgid;
8668ccd6334SPeter Wemm 	gid_t	*egid;
8678ccd6334SPeter Wemm 	gid_t	*sgid;
8688ccd6334SPeter Wemm };
8698ccd6334SPeter Wemm #endif
8708ccd6334SPeter Wemm /* ARGSUSED */
8718ccd6334SPeter Wemm int
8728ccd6334SPeter Wemm getresgid(p, uap)
8738ccd6334SPeter Wemm 	register struct proc *p;
8748ccd6334SPeter Wemm 	struct getresgid_args *uap;
8758ccd6334SPeter Wemm {
8768ccd6334SPeter Wemm 	struct pcred *pc = p->p_cred;
8778ccd6334SPeter Wemm 	int error1 = 0, error2 = 0, error3 = 0;
8788ccd6334SPeter Wemm 
8798ccd6334SPeter Wemm 	if (uap->rgid)
8808ccd6334SPeter Wemm 		error1 = copyout((caddr_t)&pc->p_rgid,
8818ccd6334SPeter Wemm 		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
8828ccd6334SPeter Wemm 	if (uap->egid)
8838ccd6334SPeter Wemm 		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
8848ccd6334SPeter Wemm 		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
8858ccd6334SPeter Wemm 	if (uap->sgid)
8868ccd6334SPeter Wemm 		error3 = copyout((caddr_t)&pc->p_svgid,
8878ccd6334SPeter Wemm 		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
8888ccd6334SPeter Wemm 	return error1 ? error1 : (error2 ? error2 : error3);
8898ccd6334SPeter Wemm }
8908ccd6334SPeter Wemm 
8918ccd6334SPeter Wemm 
892b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
893b67cbc65SPeter Wemm struct issetugid_args {
894b67cbc65SPeter Wemm 	int dummy;
895b67cbc65SPeter Wemm };
896b67cbc65SPeter Wemm #endif
897b67cbc65SPeter Wemm /* ARGSUSED */
898b67cbc65SPeter Wemm int
899cb226aaaSPoul-Henning Kamp issetugid(p, uap)
900b67cbc65SPeter Wemm 	register struct proc *p;
901b67cbc65SPeter Wemm 	struct issetugid_args *uap;
902b67cbc65SPeter Wemm {
903b67cbc65SPeter Wemm 	/*
904b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
905b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
906b67cbc65SPeter Wemm 	 * "tainting" as well.
907b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
908b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
909b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
910b67cbc65SPeter Wemm 	 */
9110e59fec6SPeter Wemm 	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
912b67cbc65SPeter Wemm 	return (0);
913b67cbc65SPeter Wemm }
914b67cbc65SPeter Wemm 
915130d0157SRobert Watson int
916130d0157SRobert Watson __setugid(p, uap)
917130d0157SRobert Watson 	struct proc *p;
918130d0157SRobert Watson 	struct __setugid_args *uap;
919130d0157SRobert Watson {
920130d0157SRobert Watson 
921130d0157SRobert Watson #ifdef REGRESSION
922130d0157SRobert Watson 	switch (uap->flag) {
923130d0157SRobert Watson 	case 0:
924130d0157SRobert Watson 		p->p_flag &= ~P_SUGID;
925130d0157SRobert Watson 		return (0);
926130d0157SRobert Watson 	case 1:
927130d0157SRobert Watson 		p->p_flag |= P_SUGID;
928130d0157SRobert Watson 		return (0);
929130d0157SRobert Watson 	default:
930130d0157SRobert Watson 		return (EINVAL);
931130d0157SRobert Watson 	}
932130d0157SRobert Watson #else /* !REGRESSION */
933130d0157SRobert Watson 	return (ENOSYS);
934130d0157SRobert Watson #endif /* !REGRESSION */
935130d0157SRobert Watson }
936130d0157SRobert Watson 
937df8bae1dSRodney W. Grimes /*
938df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
939df8bae1dSRodney W. Grimes  */
94026f9a767SRodney W. Grimes int
941df8bae1dSRodney W. Grimes groupmember(gid, cred)
942df8bae1dSRodney W. Grimes 	gid_t gid;
943df8bae1dSRodney W. Grimes 	register struct ucred *cred;
944df8bae1dSRodney W. Grimes {
945df8bae1dSRodney W. Grimes 	register gid_t *gp;
946df8bae1dSRodney W. Grimes 	gid_t *egp;
947df8bae1dSRodney W. Grimes 
948df8bae1dSRodney W. Grimes 	egp = &(cred->cr_groups[cred->cr_ngroups]);
949df8bae1dSRodney W. Grimes 	for (gp = cred->cr_groups; gp < egp; gp++)
950df8bae1dSRodney W. Grimes 		if (*gp == gid)
951df8bae1dSRodney W. Grimes 			return (1);
952df8bae1dSRodney W. Grimes 	return (0);
953df8bae1dSRodney W. Grimes }
954df8bae1dSRodney W. Grimes 
955579f4eb4SRobert Watson static int suser_permitted = 1;
956579f4eb4SRobert Watson 
957579f4eb4SRobert Watson SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
958579f4eb4SRobert Watson     "processes with uid 0 have privilege");
959579f4eb4SRobert Watson 
960df8bae1dSRodney W. Grimes /*
961df8bae1dSRodney W. Grimes  * Test whether the specified credentials imply "super-user"
962df8bae1dSRodney W. Grimes  * privilege; if so, and we have accounting info, set the flag
963df8bae1dSRodney W. Grimes  * indicating use of super-powers.
964df8bae1dSRodney W. Grimes  * Returns 0 or error.
965df8bae1dSRodney W. Grimes  */
96626f9a767SRodney W. Grimes int
967f711d546SPoul-Henning Kamp suser(p)
96891421ba2SRobert Watson 	struct proc *p;
969f711d546SPoul-Henning Kamp {
97075c13541SPoul-Henning Kamp 	return suser_xxx(0, p, 0);
971f711d546SPoul-Henning Kamp }
972f711d546SPoul-Henning Kamp 
973f711d546SPoul-Henning Kamp int
97475c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag)
97591421ba2SRobert Watson 	struct ucred *cred;
97691421ba2SRobert Watson 	struct proc *proc;
97775c13541SPoul-Henning Kamp 	int flag;
978df8bae1dSRodney W. Grimes {
97903095547SRobert Watson 	if (!suser_permitted)
98003095547SRobert Watson 		return (EPERM);
98175c13541SPoul-Henning Kamp 	if (!cred && !proc) {
98275c13541SPoul-Henning Kamp 		printf("suser_xxx(): THINK!\n");
983df8bae1dSRodney W. Grimes 		return (EPERM);
984df8bae1dSRodney W. Grimes 	}
98575c13541SPoul-Henning Kamp 	if (!cred)
98675c13541SPoul-Henning Kamp 		cred = proc->p_ucred;
98775c13541SPoul-Henning Kamp 	if (cred->cr_uid != 0)
98875c13541SPoul-Henning Kamp 		return (EPERM);
98991421ba2SRobert Watson 	if (jailed(cred) && !(flag & PRISON_ROOT))
99075c13541SPoul-Henning Kamp 		return (EPERM);
99175c13541SPoul-Henning Kamp 	return (0);
99275c13541SPoul-Henning Kamp }
993df8bae1dSRodney W. Grimes 
994ed639720SRobert Watson /*
995ed639720SRobert Watson  * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2
996ed639720SRobert Watson  * Arguments: imutable credentials u1, u2
997ed639720SRobert Watson  * Returns: 0 for permitted, an errno value otherwise
998ed639720SRobert Watson  * Locks: none
999ed639720SRobert Watson  * References: u1 and u2 must be valid for the lifetime of the call
1000ed639720SRobert Watson  *             u1 may equal u2, in which case only one reference is required
1001ed639720SRobert Watson  */
1002ed639720SRobert Watson int
1003ed639720SRobert Watson u_cansee(struct ucred *u1, struct ucred *u2)
1004a9e0361bSPoul-Henning Kamp {
100591421ba2SRobert Watson 	int error;
1006a9e0361bSPoul-Henning Kamp 
1007ed639720SRobert Watson 	if ((error = prison_check(u1, u2)))
100891421ba2SRobert Watson 		return (error);
1009ed639720SRobert Watson 	if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) {
1010f8e6ab29SRobert Watson 		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
1011387d2c03SRobert Watson 			return (ESRCH);
1012c52396e3SRobert Watson 	}
1013387d2c03SRobert Watson 	return (0);
1014387d2c03SRobert Watson }
1015387d2c03SRobert Watson 
1016387d2c03SRobert Watson static int
1017ed639720SRobert Watson p_cansee(struct proc *p1, struct proc *p2, int *privused)
1018ed639720SRobert Watson {
1019ed639720SRobert Watson 
1020ed639720SRobert Watson 	/* XXX: privused is going away, so don't do that here. */
1021ed639720SRobert Watson 	if (privused != NULL)
1022ed639720SRobert Watson 		*privused = 0;
1023ed639720SRobert Watson 	/* Wrap u_cansee() for all functionality. */
1024ed639720SRobert Watson 	return (u_cansee(p1->p_ucred, p2->p_ucred));
1025ed639720SRobert Watson }
1026ed639720SRobert Watson 
1027ed639720SRobert Watson static int
102891421ba2SRobert Watson p_cankill(struct proc *p1, struct proc *p2, int *privused)
1029387d2c03SRobert Watson {
103091421ba2SRobert Watson 	int error;
1031387d2c03SRobert Watson 
1032387d2c03SRobert Watson 	if (privused != NULL)
1033387d2c03SRobert Watson 		*privused = 0;
1034387d2c03SRobert Watson 
1035a9e0361bSPoul-Henning Kamp 	if (p1 == p2)
1036a9e0361bSPoul-Henning Kamp 		return (0);
1037387d2c03SRobert Watson 
103891421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
103991421ba2SRobert Watson 		return (error);
1040387d2c03SRobert Watson 
1041a9e0361bSPoul-Henning Kamp 	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
1042a9e0361bSPoul-Henning Kamp 		return (0);
1043a9e0361bSPoul-Henning Kamp 	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
1044a9e0361bSPoul-Henning Kamp 		return (0);
1045387d2c03SRobert Watson 	/*
1046387d2c03SRobert Watson 	 * XXX should a process be able to affect another process
1047387d2c03SRobert Watson 	 * acting as the same uid (i.e., a userland nfsd or the like?)
1048387d2c03SRobert Watson 	 */
1049a9e0361bSPoul-Henning Kamp 	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
1050a9e0361bSPoul-Henning Kamp 		return (0);
1051a9e0361bSPoul-Henning Kamp 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
1052a9e0361bSPoul-Henning Kamp 		return (0);
1053387d2c03SRobert Watson 
1054387d2c03SRobert Watson 	if (!suser_xxx(0, p1, PRISON_ROOT)) {
1055387d2c03SRobert Watson 		if (privused != NULL)
1056387d2c03SRobert Watson 			*privused = 1;
1057a9e0361bSPoul-Henning Kamp 		return (0);
1058387d2c03SRobert Watson 	}
1059387d2c03SRobert Watson 
1060387d2c03SRobert Watson #ifdef CAPABILITIES
1061387d2c03SRobert Watson 	if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) {
1062387d2c03SRobert Watson 		if (privused != NULL)
1063387d2c03SRobert Watson 			*privused = 1;
1064387d2c03SRobert Watson 		return (0);
1065387d2c03SRobert Watson 	}
1066387d2c03SRobert Watson #endif
1067387d2c03SRobert Watson 
1068a9e0361bSPoul-Henning Kamp 	return (EPERM);
1069a9e0361bSPoul-Henning Kamp }
1070a9e0361bSPoul-Henning Kamp 
1071387d2c03SRobert Watson static int
107291421ba2SRobert Watson p_cansched(struct proc *p1, struct proc *p2, int *privused)
1073387d2c03SRobert Watson {
107491421ba2SRobert Watson 	int error;
1075387d2c03SRobert Watson 
1076387d2c03SRobert Watson 	if (privused != NULL)
1077387d2c03SRobert Watson 		*privused = 0;
1078387d2c03SRobert Watson 
1079387d2c03SRobert Watson 	if (p1 == p2)
1080387d2c03SRobert Watson 		return (0);
1081387d2c03SRobert Watson 
108291421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
108391421ba2SRobert Watson 		return (error);
1084387d2c03SRobert Watson 
1085387d2c03SRobert Watson 	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
1086387d2c03SRobert Watson 		return (0);
1087387d2c03SRobert Watson 	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
1088387d2c03SRobert Watson 		return (0);
1089387d2c03SRobert Watson 	/*
1090387d2c03SRobert Watson 	 * XXX should a process be able to affect another process
1091387d2c03SRobert Watson 	 * acting as the same uid (i.e., a userland nfsd or the like?)
1092387d2c03SRobert Watson 	 */
1093387d2c03SRobert Watson 	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
1094387d2c03SRobert Watson 		return (0);
1095387d2c03SRobert Watson 	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
1096387d2c03SRobert Watson 		return (0);
1097387d2c03SRobert Watson 
1098387d2c03SRobert Watson 	if (!suser_xxx(0, p1, PRISON_ROOT)) {
1099387d2c03SRobert Watson 		if (privused != NULL)
1100387d2c03SRobert Watson 			*privused = 1;
1101387d2c03SRobert Watson 		return (0);
1102387d2c03SRobert Watson 	}
1103387d2c03SRobert Watson 
1104387d2c03SRobert Watson #ifdef CAPABILITIES
1105387d2c03SRobert Watson 	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) {
1106387d2c03SRobert Watson 		if (privused != NULL)
1107387d2c03SRobert Watson 			*privused = 1;
1108387d2c03SRobert Watson 		return (0);
1109387d2c03SRobert Watson 	}
1110387d2c03SRobert Watson #endif
1111387d2c03SRobert Watson 
1112387d2c03SRobert Watson 	return (EPERM);
1113387d2c03SRobert Watson }
1114387d2c03SRobert Watson 
1115387d2c03SRobert Watson static int
111691421ba2SRobert Watson p_candebug(struct proc *p1, struct proc *p2, int *privused)
1117387d2c03SRobert Watson {
1118387d2c03SRobert Watson 	int error;
1119387d2c03SRobert Watson 
1120387d2c03SRobert Watson 	if (privused != NULL)
1121387d2c03SRobert Watson 		*privused = 0;
1122387d2c03SRobert Watson 
1123387d2c03SRobert Watson 	/* XXX it is authorized, but semantics don't permit it */
1124387d2c03SRobert Watson 	if (p1 == p2)
1125387d2c03SRobert Watson 		return (0);
1126387d2c03SRobert Watson 
112791421ba2SRobert Watson 	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
112891421ba2SRobert Watson 		return (error);
1129387d2c03SRobert Watson 
1130387d2c03SRobert Watson 	/* not owned by you, has done setuid (unless you're root) */
1131387d2c03SRobert Watson 	/* add a CAP_SYS_PTRACE here? */
1132c087a04fSRobert Watson 	if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid ||
1133c087a04fSRobert Watson 	    p1->p_cred->p_ruid != p2->p_cred->p_ruid ||
11347f73938eSRobert Watson 	    p1->p_cred->p_svuid != p2->p_cred->p_ruid ||
1135c087a04fSRobert Watson 	    p2->p_flag & P_SUGID) {
1136387d2c03SRobert Watson 		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
1137387d2c03SRobert Watson 			return (error);
1138387d2c03SRobert Watson 		if (privused != NULL)
1139387d2c03SRobert Watson 			*privused = 1;
1140387d2c03SRobert Watson 	}
1141387d2c03SRobert Watson 
1142387d2c03SRobert Watson 	/* can't trace init when securelevel > 0 */
1143387d2c03SRobert Watson 	if (securelevel > 0 && p2->p_pid == 1)
1144387d2c03SRobert Watson 		return (EPERM);
1145387d2c03SRobert Watson 
1146387d2c03SRobert Watson 	return (0);
1147387d2c03SRobert Watson }
1148387d2c03SRobert Watson 
1149387d2c03SRobert Watson int
115091421ba2SRobert Watson p_can(struct proc *p1, struct proc *p2, int operation,
1151387d2c03SRobert Watson     int *privused)
1152387d2c03SRobert Watson {
1153387d2c03SRobert Watson 
1154387d2c03SRobert Watson 	switch(operation) {
1155387d2c03SRobert Watson 	case P_CAN_SEE:
1156387d2c03SRobert Watson 		return (p_cansee(p1, p2, privused));
1157387d2c03SRobert Watson 
1158387d2c03SRobert Watson 	case P_CAN_KILL:
1159387d2c03SRobert Watson 		return (p_cankill(p1, p2, privused));
1160387d2c03SRobert Watson 
1161387d2c03SRobert Watson 	case P_CAN_SCHED:
1162387d2c03SRobert Watson 		return (p_cansched(p1, p2, privused));
1163387d2c03SRobert Watson 
1164387d2c03SRobert Watson 	case P_CAN_DEBUG:
1165387d2c03SRobert Watson 		return (p_candebug(p1, p2, privused));
1166387d2c03SRobert Watson 
1167387d2c03SRobert Watson 	default:
1168387d2c03SRobert Watson 		panic("p_can: invalid operation");
1169387d2c03SRobert Watson 	}
1170387d2c03SRobert Watson }
1171387d2c03SRobert Watson 
1172387d2c03SRobert Watson 
1173a9e0361bSPoul-Henning Kamp /*
1174df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
1175df8bae1dSRodney W. Grimes  */
1176df8bae1dSRodney W. Grimes struct ucred *
1177df8bae1dSRodney W. Grimes crget()
1178df8bae1dSRodney W. Grimes {
1179df8bae1dSRodney W. Grimes 	register struct ucred *cr;
1180df8bae1dSRodney W. Grimes 
11811e5d626aSAlfred Perlstein 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
1182df8bae1dSRodney W. Grimes 	cr->cr_ref = 1;
11831e5d626aSAlfred Perlstein 	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
1184df8bae1dSRodney W. Grimes 	return (cr);
1185df8bae1dSRodney W. Grimes }
1186df8bae1dSRodney W. Grimes 
1187df8bae1dSRodney W. Grimes /*
1188661702abSRobert Watson  * Claim another reference to a ucred structure
11895c3f70d7SAlfred Perlstein  */
11905c3f70d7SAlfred Perlstein void
11915c3f70d7SAlfred Perlstein crhold(cr)
11925c3f70d7SAlfred Perlstein 	struct ucred *cr;
11935c3f70d7SAlfred Perlstein {
11945c3f70d7SAlfred Perlstein 
11959ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
11965c3f70d7SAlfred Perlstein 	cr->cr_ref++;
11979ed346baSBosko Milekic 	mtx_unlock(&(cr)->cr_mtx);
11985c3f70d7SAlfred Perlstein }
11995c3f70d7SAlfred Perlstein 
12005c3f70d7SAlfred Perlstein 
12015c3f70d7SAlfred Perlstein /*
1202df8bae1dSRodney W. Grimes  * Free a cred structure.
1203df8bae1dSRodney W. Grimes  * Throws away space when ref count gets to 0.
1204df8bae1dSRodney W. Grimes  */
120526f9a767SRodney W. Grimes void
1206df8bae1dSRodney W. Grimes crfree(cr)
1207df8bae1dSRodney W. Grimes 	struct ucred *cr;
1208df8bae1dSRodney W. Grimes {
12091e5d626aSAlfred Perlstein 
12109ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
1211f535380cSDon Lewis 	if (--cr->cr_ref == 0) {
12121e5d626aSAlfred Perlstein 		mtx_destroy(&cr->cr_mtx);
1213f535380cSDon Lewis 		/*
1214f535380cSDon Lewis 		 * Some callers of crget(), such as nfs_statfs(),
1215f535380cSDon Lewis 		 * allocate a temporary credential, but don't
1216f535380cSDon Lewis 		 * allocate a uidinfo structure.
1217f535380cSDon Lewis 		 */
1218f535380cSDon Lewis 		if (cr->cr_uidinfo != NULL)
1219f535380cSDon Lewis 			uifree(cr->cr_uidinfo);
122091421ba2SRobert Watson 		/*
122191421ba2SRobert Watson 		 * Free a prison, if any.
122291421ba2SRobert Watson 		 */
122391421ba2SRobert Watson 		if (jailed(cr))
122491421ba2SRobert Watson 			prison_free(cr->cr_prison);
1225df8bae1dSRodney W. Grimes 		FREE((caddr_t)cr, M_CRED);
12261e5d626aSAlfred Perlstein 	} else {
12279ed346baSBosko Milekic 		mtx_unlock(&cr->cr_mtx);
1228df8bae1dSRodney W. Grimes 	}
1229f535380cSDon Lewis }
1230df8bae1dSRodney W. Grimes 
1231df8bae1dSRodney W. Grimes /*
1232df8bae1dSRodney W. Grimes  * Copy cred structure to a new one and free the old one.
1233df8bae1dSRodney W. Grimes  */
1234df8bae1dSRodney W. Grimes struct ucred *
1235df8bae1dSRodney W. Grimes crcopy(cr)
1236df8bae1dSRodney W. Grimes 	struct ucred *cr;
1237df8bae1dSRodney W. Grimes {
1238df8bae1dSRodney W. Grimes 	struct ucred *newcr;
1239df8bae1dSRodney W. Grimes 
12409ed346baSBosko Milekic 	mtx_lock(&cr->cr_mtx);
12411e5d626aSAlfred Perlstein 	if (cr->cr_ref == 1) {
12429ed346baSBosko Milekic 		mtx_unlock(&cr->cr_mtx);
1243df8bae1dSRodney W. Grimes 		return (cr);
12441e5d626aSAlfred Perlstein 	}
12459ed346baSBosko Milekic 	mtx_unlock(&cr->cr_mtx);
12461e5d626aSAlfred Perlstein 	newcr = crdup(cr);
1247df8bae1dSRodney W. Grimes 	crfree(cr);
1248df8bae1dSRodney W. Grimes 	return (newcr);
1249df8bae1dSRodney W. Grimes }
1250df8bae1dSRodney W. Grimes 
1251df8bae1dSRodney W. Grimes /*
1252df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
1253df8bae1dSRodney W. Grimes  */
1254df8bae1dSRodney W. Grimes struct ucred *
1255df8bae1dSRodney W. Grimes crdup(cr)
1256df8bae1dSRodney W. Grimes 	struct ucred *cr;
1257df8bae1dSRodney W. Grimes {
1258df8bae1dSRodney W. Grimes 	struct ucred *newcr;
1259df8bae1dSRodney W. Grimes 
12601e5d626aSAlfred Perlstein 	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
1261df8bae1dSRodney W. Grimes 	*newcr = *cr;
12621e5d626aSAlfred Perlstein 	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
1263f535380cSDon Lewis 	uihold(newcr->cr_uidinfo);
126491421ba2SRobert Watson 	if (jailed(newcr))
126591421ba2SRobert Watson 		prison_hold(newcr->cr_prison);
1266df8bae1dSRodney W. Grimes 	newcr->cr_ref = 1;
1267df8bae1dSRodney W. Grimes 	return (newcr);
1268df8bae1dSRodney W. Grimes }
1269df8bae1dSRodney W. Grimes 
1270df8bae1dSRodney W. Grimes /*
1271df8bae1dSRodney W. Grimes  * Get login name, if available.
1272df8bae1dSRodney W. Grimes  */
1273d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1274df8bae1dSRodney W. Grimes struct getlogin_args {
1275df8bae1dSRodney W. Grimes 	char	*namebuf;
1276df8bae1dSRodney W. Grimes 	u_int	namelen;
1277df8bae1dSRodney W. Grimes };
1278d2d3e875SBruce Evans #endif
1279df8bae1dSRodney W. Grimes /* ARGSUSED */
128026f9a767SRodney W. Grimes int
1281cb226aaaSPoul-Henning Kamp getlogin(p, uap)
1282df8bae1dSRodney W. Grimes 	struct proc *p;
1283df8bae1dSRodney W. Grimes 	struct getlogin_args *uap;
1284df8bae1dSRodney W. Grimes {
1285df8bae1dSRodney W. Grimes 
128630cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
128753490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
1288df8bae1dSRodney W. Grimes 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
1289df8bae1dSRodney W. Grimes 	    (caddr_t) uap->namebuf, uap->namelen));
1290df8bae1dSRodney W. Grimes }
1291df8bae1dSRodney W. Grimes 
1292df8bae1dSRodney W. Grimes /*
1293df8bae1dSRodney W. Grimes  * Set login name.
1294df8bae1dSRodney W. Grimes  */
1295d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1296df8bae1dSRodney W. Grimes struct setlogin_args {
1297df8bae1dSRodney W. Grimes 	char	*namebuf;
1298df8bae1dSRodney W. Grimes };
1299d2d3e875SBruce Evans #endif
1300df8bae1dSRodney W. Grimes /* ARGSUSED */
130126f9a767SRodney W. Grimes int
1302cb226aaaSPoul-Henning Kamp setlogin(p, uap)
1303df8bae1dSRodney W. Grimes 	struct proc *p;
1304df8bae1dSRodney W. Grimes 	struct setlogin_args *uap;
1305df8bae1dSRodney W. Grimes {
1306df8bae1dSRodney W. Grimes 	int error;
1307964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
1308df8bae1dSRodney W. Grimes 
130975c13541SPoul-Henning Kamp 	if ((error = suser_xxx(0, p, PRISON_ROOT)))
1310df8bae1dSRodney W. Grimes 		return (error);
1311184989c2SDavid Nugent 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
131210d4743fSDoug Rabson 	    sizeof(logintmp), (size_t *)0);
1313df8bae1dSRodney W. Grimes 	if (error == ENAMETOOLONG)
1314df8bae1dSRodney W. Grimes 		error = EINVAL;
1315184989c2SDavid Nugent 	else if (!error)
1316184989c2SDavid Nugent 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
1317964ca0caSAndrey A. Chernov 		    sizeof(logintmp));
1318df8bae1dSRodney W. Grimes 	return (error);
1319df8bae1dSRodney W. Grimes }
1320d5f81602SSean Eric Fagan 
1321d5f81602SSean Eric Fagan void
1322d5f81602SSean Eric Fagan setsugid(p)
1323d5f81602SSean Eric Fagan 	struct proc *p;
1324d5f81602SSean Eric Fagan {
1325d5f81602SSean Eric Fagan 	p->p_flag |= P_SUGID;
132689361835SSean Eric Fagan 	if (!(p->p_pfsflags & PF_ISUGID))
1327d5f81602SSean Eric Fagan 		p->p_stops = 0;
1328d5f81602SSean Eric Fagan }
1329f535380cSDon Lewis 
1330f535380cSDon Lewis /*
1331f535380cSDon Lewis  * Helper function to change the effective uid of a process
1332f535380cSDon Lewis  */
1333f535380cSDon Lewis void
1334f535380cSDon Lewis change_euid(p, euid)
1335f535380cSDon Lewis 	struct	proc *p;
1336f535380cSDon Lewis 	uid_t	euid;
1337f535380cSDon Lewis {
1338f535380cSDon Lewis 	struct	pcred *pc;
1339f535380cSDon Lewis 	struct	uidinfo *uip;
1340f535380cSDon Lewis 
1341f535380cSDon Lewis 	pc = p->p_cred;
1342f535380cSDon Lewis 	/*
1343f535380cSDon Lewis 	 * crcopy is essentially a NOP if ucred has a reference count
1344f535380cSDon Lewis 	 * of 1, which is true if it has already been copied.
1345f535380cSDon Lewis 	 */
1346f535380cSDon Lewis 	pc->pc_ucred = crcopy(pc->pc_ucred);
1347f535380cSDon Lewis 	uip = pc->pc_ucred->cr_uidinfo;
1348f535380cSDon Lewis 	pc->pc_ucred->cr_uid = euid;
1349f535380cSDon Lewis 	pc->pc_ucred->cr_uidinfo = uifind(euid);
1350f535380cSDon Lewis 	uifree(uip);
1351f535380cSDon Lewis }
1352f535380cSDon Lewis 
1353f535380cSDon Lewis /*
1354f535380cSDon Lewis  * Helper function to change the real uid of a process
1355f535380cSDon Lewis  *
1356f535380cSDon Lewis  * The per-uid process count for this process is transfered from
1357f535380cSDon Lewis  * the old uid to the new uid.
1358f535380cSDon Lewis  */
1359810bfc8eSAndrew Gallatin void
1360f535380cSDon Lewis change_ruid(p, ruid)
1361f535380cSDon Lewis 	struct	proc *p;
1362f535380cSDon Lewis 	uid_t	ruid;
1363f535380cSDon Lewis {
1364f535380cSDon Lewis 	struct	pcred *pc;
1365f535380cSDon Lewis 	struct	uidinfo *uip;
1366f535380cSDon Lewis 
1367f535380cSDon Lewis 	pc = p->p_cred;
1368f535380cSDon Lewis 	(void)chgproccnt(pc->p_uidinfo, -1, 0);
1369f535380cSDon Lewis 	uip = pc->p_uidinfo;
1370f535380cSDon Lewis 	/* It is assumed that pcred is not shared between processes */
1371f535380cSDon Lewis 	pc->p_ruid = ruid;
1372f535380cSDon Lewis 	pc->p_uidinfo = uifind(ruid);
1373f535380cSDon Lewis 	(void)chgproccnt(pc->p_uidinfo, 1, 0);
1374f535380cSDon Lewis 	uifree(uip);
1375f535380cSDon Lewis }
1376