xref: /freebsd/sys/kern/kern_prot.c (revision 1a5018a043664a50368976703d0429eada5bb0f2)
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
391a5018a0SPeter Wemm  * $Id: kern_prot.c,v 1.33 1997/08/02 14:31:34 bde Exp $
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 
46df8bae1dSRodney W. Grimes #include <sys/param.h>
47df8bae1dSRodney W. Grimes #include <sys/acct.h>
48df8bae1dSRodney W. Grimes #include <sys/systm.h>
49d2d3e875SBruce Evans #include <sys/sysproto.h>
50df8bae1dSRodney W. Grimes #include <sys/proc.h>
51df8bae1dSRodney W. Grimes #include <sys/malloc.h>
52c957118eSBruce Evans #include <sys/unistd.h>
53df8bae1dSRodney W. Grimes 
54d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
55ad7507e2SSteven Wallace struct getpid_args {
56df8bae1dSRodney W. Grimes 	int	dummy;
57df8bae1dSRodney W. Grimes };
58d2d3e875SBruce Evans #endif
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes /* ARGSUSED */
6126f9a767SRodney W. Grimes int
62df8bae1dSRodney W. Grimes getpid(p, uap, retval)
63df8bae1dSRodney W. Grimes 	struct proc *p;
64ad7507e2SSteven Wallace 	struct getpid_args *uap;
65df8bae1dSRodney W. Grimes 	int *retval;
66df8bae1dSRodney W. Grimes {
67df8bae1dSRodney W. Grimes 
68df8bae1dSRodney W. Grimes 	*retval = p->p_pid;
69df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
70df8bae1dSRodney W. Grimes 	retval[1] = p->p_pptr->p_pid;
71df8bae1dSRodney W. Grimes #endif
72df8bae1dSRodney W. Grimes 	return (0);
73df8bae1dSRodney W. Grimes }
74df8bae1dSRodney W. Grimes 
75d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
76ad7507e2SSteven Wallace struct getppid_args {
77ad7507e2SSteven Wallace         int     dummy;
78ad7507e2SSteven Wallace };
79d2d3e875SBruce Evans #endif
80df8bae1dSRodney W. Grimes /* ARGSUSED */
8126f9a767SRodney W. Grimes int
82df8bae1dSRodney W. Grimes getppid(p, uap, retval)
83df8bae1dSRodney W. Grimes 	struct proc *p;
84ad7507e2SSteven Wallace 	struct getppid_args *uap;
85df8bae1dSRodney W. Grimes 	int *retval;
86df8bae1dSRodney W. Grimes {
87df8bae1dSRodney W. Grimes 
88df8bae1dSRodney W. Grimes 	*retval = p->p_pptr->p_pid;
89df8bae1dSRodney W. Grimes 	return (0);
90df8bae1dSRodney W. Grimes }
91df8bae1dSRodney W. Grimes 
92df8bae1dSRodney W. Grimes /* Get process group ID; note that POSIX getpgrp takes no parameter */
93d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
94ad7507e2SSteven Wallace struct getpgrp_args {
95ad7507e2SSteven Wallace         int     dummy;
96ad7507e2SSteven Wallace };
97d2d3e875SBruce Evans #endif
98ad7507e2SSteven Wallace 
9926f9a767SRodney W. Grimes int
100df8bae1dSRodney W. Grimes getpgrp(p, uap, retval)
101df8bae1dSRodney W. Grimes 	struct proc *p;
102ad7507e2SSteven Wallace 	struct getpgrp_args *uap;
103df8bae1dSRodney W. Grimes 	int *retval;
104df8bae1dSRodney W. Grimes {
105df8bae1dSRodney W. Grimes 
106df8bae1dSRodney W. Grimes 	*retval = p->p_pgrp->pg_id;
107df8bae1dSRodney W. Grimes 	return (0);
108df8bae1dSRodney W. Grimes }
109df8bae1dSRodney W. Grimes 
1101a5018a0SPeter Wemm /* Get an arbitary pid's process group id */
1111a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1121a5018a0SPeter Wemm struct getpgid_args {
1131a5018a0SPeter Wemm 	pid_t	pid;
1141a5018a0SPeter Wemm };
1151a5018a0SPeter Wemm #endif
1161a5018a0SPeter Wemm 
1171a5018a0SPeter Wemm int
1181a5018a0SPeter Wemm getpgid(p, uap, retval)
1191a5018a0SPeter Wemm 	struct proc *p;
1201a5018a0SPeter Wemm 	struct getpgid_args *uap;
1211a5018a0SPeter Wemm 	int *retval;
1221a5018a0SPeter Wemm {
1231a5018a0SPeter Wemm 	if (uap->pid == 0)
1241a5018a0SPeter Wemm 		goto found;
1251a5018a0SPeter Wemm 
1261a5018a0SPeter Wemm 	if ((p == pfind(uap->pid)) == 0)
1271a5018a0SPeter Wemm 		return ESRCH;
1281a5018a0SPeter Wemm found:
1291a5018a0SPeter Wemm 	*retval = p->p_pgrp->pg_id;
1301a5018a0SPeter Wemm 	return 0;
1311a5018a0SPeter Wemm }
1321a5018a0SPeter Wemm 
1331a5018a0SPeter Wemm /*
1341a5018a0SPeter Wemm  * Get an arbitary pid's session id.
1351a5018a0SPeter Wemm  */
1361a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_
1371a5018a0SPeter Wemm struct getsid_args {
1381a5018a0SPeter Wemm 	pid_t	pid;
1391a5018a0SPeter Wemm };
1401a5018a0SPeter Wemm #endif
1411a5018a0SPeter Wemm 
1421a5018a0SPeter Wemm int
1431a5018a0SPeter Wemm getsid(p, uap, retval)
1441a5018a0SPeter Wemm 	struct proc *p;
1451a5018a0SPeter Wemm 	struct getsid_args *uap;
1461a5018a0SPeter Wemm 	int *retval;
1471a5018a0SPeter Wemm {
1481a5018a0SPeter Wemm 	if (uap->pid == 0)
1491a5018a0SPeter Wemm 		goto found;
1501a5018a0SPeter Wemm 
1511a5018a0SPeter Wemm 	if ((p == pfind(uap->pid)) == 0)
1521a5018a0SPeter Wemm 		return ESRCH;
1531a5018a0SPeter Wemm found:
1541a5018a0SPeter Wemm 	*retval = p->p_pgrp->pg_session->s_leader->p_pid;
1551a5018a0SPeter Wemm 	return 0;
1561a5018a0SPeter Wemm }
1571a5018a0SPeter Wemm 
1581a5018a0SPeter Wemm 
159d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
160ad7507e2SSteven Wallace struct getuid_args {
161ad7507e2SSteven Wallace         int     dummy;
162ad7507e2SSteven Wallace };
163d2d3e875SBruce Evans #endif
164ad7507e2SSteven Wallace 
165df8bae1dSRodney W. Grimes /* ARGSUSED */
16626f9a767SRodney W. Grimes int
167df8bae1dSRodney W. Grimes getuid(p, uap, retval)
168df8bae1dSRodney W. Grimes 	struct proc *p;
169ad7507e2SSteven Wallace 	struct getuid_args *uap;
170df8bae1dSRodney W. Grimes 	int *retval;
171df8bae1dSRodney W. Grimes {
172df8bae1dSRodney W. Grimes 
173df8bae1dSRodney W. Grimes 	*retval = p->p_cred->p_ruid;
174df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
175df8bae1dSRodney W. Grimes 	retval[1] = p->p_ucred->cr_uid;
176df8bae1dSRodney W. Grimes #endif
177df8bae1dSRodney W. Grimes 	return (0);
178df8bae1dSRodney W. Grimes }
179df8bae1dSRodney W. Grimes 
180d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
181ad7507e2SSteven Wallace struct geteuid_args {
182ad7507e2SSteven Wallace         int     dummy;
183ad7507e2SSteven Wallace };
184d2d3e875SBruce Evans #endif
185ad7507e2SSteven Wallace 
186df8bae1dSRodney W. Grimes /* ARGSUSED */
18726f9a767SRodney W. Grimes int
188df8bae1dSRodney W. Grimes geteuid(p, uap, retval)
189df8bae1dSRodney W. Grimes 	struct proc *p;
190ad7507e2SSteven Wallace 	struct geteuid_args *uap;
191df8bae1dSRodney W. Grimes 	int *retval;
192df8bae1dSRodney W. Grimes {
193df8bae1dSRodney W. Grimes 
194df8bae1dSRodney W. Grimes 	*retval = p->p_ucred->cr_uid;
195df8bae1dSRodney W. Grimes 	return (0);
196df8bae1dSRodney W. Grimes }
197df8bae1dSRodney W. Grimes 
198d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
199ad7507e2SSteven Wallace struct getgid_args {
200ad7507e2SSteven Wallace         int     dummy;
201ad7507e2SSteven Wallace };
202d2d3e875SBruce Evans #endif
203ad7507e2SSteven Wallace 
204df8bae1dSRodney W. Grimes /* ARGSUSED */
20526f9a767SRodney W. Grimes int
206df8bae1dSRodney W. Grimes getgid(p, uap, retval)
207df8bae1dSRodney W. Grimes 	struct proc *p;
208ad7507e2SSteven Wallace 	struct getgid_args *uap;
209df8bae1dSRodney W. Grimes 	int *retval;
210df8bae1dSRodney W. Grimes {
211df8bae1dSRodney W. Grimes 
212df8bae1dSRodney W. Grimes 	*retval = p->p_cred->p_rgid;
213df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
214df8bae1dSRodney W. Grimes 	retval[1] = p->p_ucred->cr_groups[0];
215df8bae1dSRodney W. Grimes #endif
216df8bae1dSRodney W. Grimes 	return (0);
217df8bae1dSRodney W. Grimes }
218df8bae1dSRodney W. Grimes 
219df8bae1dSRodney W. Grimes /*
220df8bae1dSRodney W. Grimes  * Get effective group ID.  The "egid" is groups[0], and could be obtained
221df8bae1dSRodney W. Grimes  * via getgroups.  This syscall exists because it is somewhat painful to do
222df8bae1dSRodney W. Grimes  * correctly in a library function.
223df8bae1dSRodney W. Grimes  */
224d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
225ad7507e2SSteven Wallace struct getegid_args {
226ad7507e2SSteven Wallace         int     dummy;
227ad7507e2SSteven Wallace };
228d2d3e875SBruce Evans #endif
229ad7507e2SSteven Wallace 
230df8bae1dSRodney W. Grimes /* ARGSUSED */
23126f9a767SRodney W. Grimes int
232df8bae1dSRodney W. Grimes getegid(p, uap, retval)
233df8bae1dSRodney W. Grimes 	struct proc *p;
234ad7507e2SSteven Wallace 	struct getegid_args *uap;
235df8bae1dSRodney W. Grimes 	int *retval;
236df8bae1dSRodney W. Grimes {
237df8bae1dSRodney W. Grimes 
238df8bae1dSRodney W. Grimes 	*retval = p->p_ucred->cr_groups[0];
239df8bae1dSRodney W. Grimes 	return (0);
240df8bae1dSRodney W. Grimes }
241df8bae1dSRodney W. Grimes 
242d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
243df8bae1dSRodney W. Grimes struct getgroups_args {
244df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
245df8bae1dSRodney W. Grimes 	gid_t	*gidset;
246df8bae1dSRodney W. Grimes };
247d2d3e875SBruce Evans #endif
24826f9a767SRodney W. Grimes int
249df8bae1dSRodney W. Grimes getgroups(p, uap, retval)
250df8bae1dSRodney W. Grimes 	struct proc *p;
251df8bae1dSRodney W. Grimes 	register struct	getgroups_args *uap;
252df8bae1dSRodney W. Grimes 	int *retval;
253df8bae1dSRodney W. Grimes {
254df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
255df8bae1dSRodney W. Grimes 	register u_int ngrp;
256df8bae1dSRodney W. Grimes 	int error;
257df8bae1dSRodney W. Grimes 
258df8bae1dSRodney W. Grimes 	if ((ngrp = uap->gidsetsize) == 0) {
259df8bae1dSRodney W. Grimes 		*retval = pc->pc_ucred->cr_ngroups;
260df8bae1dSRodney W. Grimes 		return (0);
261df8bae1dSRodney W. Grimes 	}
262df8bae1dSRodney W. Grimes 	if (ngrp < pc->pc_ucred->cr_ngroups)
263df8bae1dSRodney W. Grimes 		return (EINVAL);
264df8bae1dSRodney W. Grimes 	ngrp = pc->pc_ucred->cr_ngroups;
265bb56ec4aSPoul-Henning Kamp 	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
266bb56ec4aSPoul-Henning Kamp 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
267df8bae1dSRodney W. Grimes 		return (error);
268df8bae1dSRodney W. Grimes 	*retval = ngrp;
269df8bae1dSRodney W. Grimes 	return (0);
270df8bae1dSRodney W. Grimes }
271df8bae1dSRodney W. Grimes 
272d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
27382970b81SBruce Evans struct setsid_args {
274ad7507e2SSteven Wallace         int     dummy;
275ad7507e2SSteven Wallace };
276d2d3e875SBruce Evans #endif
277ad7507e2SSteven Wallace 
278df8bae1dSRodney W. Grimes /* ARGSUSED */
27926f9a767SRodney W. Grimes int
280df8bae1dSRodney W. Grimes setsid(p, uap, retval)
281df8bae1dSRodney W. Grimes 	register struct proc *p;
28282970b81SBruce Evans 	struct setsid_args *uap;
283df8bae1dSRodney W. Grimes 	int *retval;
284df8bae1dSRodney W. Grimes {
285df8bae1dSRodney W. Grimes 
286df8bae1dSRodney W. Grimes 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
287df8bae1dSRodney W. Grimes 		return (EPERM);
288df8bae1dSRodney W. Grimes 	} else {
289df8bae1dSRodney W. Grimes 		(void)enterpgrp(p, p->p_pid, 1);
290df8bae1dSRodney W. Grimes 		*retval = p->p_pid;
291df8bae1dSRodney W. Grimes 		return (0);
292df8bae1dSRodney W. Grimes 	}
293df8bae1dSRodney W. Grimes }
294df8bae1dSRodney W. Grimes 
295df8bae1dSRodney W. Grimes /*
296df8bae1dSRodney W. Grimes  * set process group (setpgid/old setpgrp)
297df8bae1dSRodney W. Grimes  *
298df8bae1dSRodney W. Grimes  * caller does setpgid(targpid, targpgid)
299df8bae1dSRodney W. Grimes  *
300df8bae1dSRodney W. Grimes  * pid must be caller or child of caller (ESRCH)
301df8bae1dSRodney W. Grimes  * if a child
302df8bae1dSRodney W. Grimes  *	pid must be in same session (EPERM)
303df8bae1dSRodney W. Grimes  *	pid can't have done an exec (EACCES)
304df8bae1dSRodney W. Grimes  * if pgid != pid
305df8bae1dSRodney W. Grimes  * 	there must exist some pid in same session having pgid (EPERM)
306df8bae1dSRodney W. Grimes  * pid must not be session leader (EPERM)
307df8bae1dSRodney W. Grimes  */
308d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
309df8bae1dSRodney W. Grimes struct setpgid_args {
310df8bae1dSRodney W. Grimes 	int	pid;	/* target process id */
311df8bae1dSRodney W. Grimes 	int	pgid;	/* target pgrp id */
312df8bae1dSRodney W. Grimes };
313d2d3e875SBruce Evans #endif
314df8bae1dSRodney W. Grimes /* ARGSUSED */
31526f9a767SRodney W. Grimes int
316df8bae1dSRodney W. Grimes setpgid(curp, uap, retval)
317df8bae1dSRodney W. Grimes 	struct proc *curp;
318df8bae1dSRodney W. Grimes 	register struct setpgid_args *uap;
319df8bae1dSRodney W. Grimes 	int *retval;
320df8bae1dSRodney W. Grimes {
321df8bae1dSRodney W. Grimes 	register struct proc *targp;		/* target process */
322df8bae1dSRodney W. Grimes 	register struct pgrp *pgrp;		/* target pgrp */
323df8bae1dSRodney W. Grimes 
32478f64bccSBruce Evans 	if (uap->pgid < 0)
32578f64bccSBruce Evans 		return (EINVAL);
326df8bae1dSRodney W. Grimes 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
327df8bae1dSRodney W. Grimes 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
328df8bae1dSRodney W. Grimes 			return (ESRCH);
329cd73303cSDavid Greenman 		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
330df8bae1dSRodney W. Grimes 			return (EPERM);
331df8bae1dSRodney W. Grimes 		if (targp->p_flag & P_EXEC)
332df8bae1dSRodney W. Grimes 			return (EACCES);
333df8bae1dSRodney W. Grimes 	} else
334df8bae1dSRodney W. Grimes 		targp = curp;
335df8bae1dSRodney W. Grimes 	if (SESS_LEADER(targp))
336df8bae1dSRodney W. Grimes 		return (EPERM);
337df8bae1dSRodney W. Grimes 	if (uap->pgid == 0)
338df8bae1dSRodney W. Grimes 		uap->pgid = targp->p_pid;
339df8bae1dSRodney W. Grimes 	else if (uap->pgid != targp->p_pid)
340df8bae1dSRodney W. Grimes 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
341df8bae1dSRodney W. Grimes 	            pgrp->pg_session != curp->p_session)
342df8bae1dSRodney W. Grimes 			return (EPERM);
343df8bae1dSRodney W. Grimes 	return (enterpgrp(targp, uap->pgid, 0));
344df8bae1dSRodney W. Grimes }
345df8bae1dSRodney W. Grimes 
346a08f4bf6SPeter Wemm /*
347a08f4bf6SPeter Wemm  * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
348a08f4bf6SPeter Wemm  * compatable.  It says that setting the uid/gid to euid/egid is a special
349a08f4bf6SPeter Wemm  * case of "appropriate privilege".  Once the rules are expanded out, this
350a08f4bf6SPeter Wemm  * basically means that setuid(nnn) sets all three id's, in all permitted
351a08f4bf6SPeter Wemm  * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
352a08f4bf6SPeter Wemm  * does not set the saved id - this is dangerous for traditional BSD
353a08f4bf6SPeter Wemm  * programs.  For this reason, we *really* do not want to set
354a08f4bf6SPeter Wemm  * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
355a08f4bf6SPeter Wemm  */
356a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2
357a08f4bf6SPeter Wemm 
358d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
359df8bae1dSRodney W. Grimes struct setuid_args {
360df8bae1dSRodney W. Grimes 	uid_t	uid;
361df8bae1dSRodney W. Grimes };
362d2d3e875SBruce Evans #endif
363df8bae1dSRodney W. Grimes /* ARGSUSED */
36426f9a767SRodney W. Grimes int
365df8bae1dSRodney W. Grimes setuid(p, uap, retval)
366df8bae1dSRodney W. Grimes 	struct proc *p;
367df8bae1dSRodney W. Grimes 	struct setuid_args *uap;
368df8bae1dSRodney W. Grimes 	int *retval;
369df8bae1dSRodney W. Grimes {
370df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
371df8bae1dSRodney W. Grimes 	register uid_t uid;
372df8bae1dSRodney W. Grimes 	int error;
373df8bae1dSRodney W. Grimes 
374a08f4bf6SPeter Wemm 	/*
375a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
376a08f4bf6SPeter Wemm 	 *
377a08f4bf6SPeter Wemm 	 * Note that setuid(geteuid()) is a special case of
378a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
379a08f4bf6SPeter Wemm 	 * to use this clause to be compatable with traditional BSD
380a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setuid(xx)" sets all
381a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
382a08f4bf6SPeter Wemm 	 *
383a08f4bf6SPeter Wemm 	 * Notes on the logic.  We do things in three steps.
384a08f4bf6SPeter Wemm 	 * 1: We determine if the euid is going to change, and do EPERM
385a08f4bf6SPeter Wemm 	 *    right away.  We unconditionally change the euid later if this
386a08f4bf6SPeter Wemm 	 *    test is satisfied, simplifying that part of the logic.
387a08f4bf6SPeter Wemm 	 * 2: We determine if the real and/or saved uid's are going to
388a08f4bf6SPeter Wemm 	 *    change.  Determined by compile options.
389a08f4bf6SPeter Wemm 	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
390a08f4bf6SPeter Wemm 	 */
391df8bae1dSRodney W. Grimes 	uid = uap->uid;
392a08f4bf6SPeter Wemm 	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
3933f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
394a08f4bf6SPeter Wemm 	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
395a08f4bf6SPeter Wemm #endif
396a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
397a08f4bf6SPeter Wemm 	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
3983f246666SAndrey A. Chernov #endif
3992c3be6c3SAndrey A. Chernov 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
400df8bae1dSRodney W. Grimes 		return (error);
401a08f4bf6SPeter Wemm 
402a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
403df8bae1dSRodney W. Grimes 	/*
404a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or uid == euid)
405a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and/or saved uid.
406df8bae1dSRodney W. Grimes 	 */
4073f246666SAndrey A. Chernov 	if (
408a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
409a08f4bf6SPeter Wemm 	    uid == pc->pc_ucred->cr_uid ||
4103f246666SAndrey A. Chernov #endif
411a08f4bf6SPeter Wemm 	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
412a08f4bf6SPeter Wemm #endif
413a08f4bf6SPeter Wemm 	{
414a08f4bf6SPeter Wemm 		/*
415a08f4bf6SPeter Wemm 		 * Transfer proc count to new user.
416a08f4bf6SPeter Wemm 		 */
417a08f4bf6SPeter Wemm 		if (uid != pc->p_ruid) {
418df8bae1dSRodney W. Grimes 			(void)chgproccnt(pc->p_ruid, -1);
419df8bae1dSRodney W. Grimes 			(void)chgproccnt(uid, 1);
420d3cdb93dSAndrey A. Chernov 		}
421a08f4bf6SPeter Wemm 		/*
422a08f4bf6SPeter Wemm 		 * Set real uid
423a08f4bf6SPeter Wemm 		 */
424a08f4bf6SPeter Wemm 		if (uid != pc->p_ruid) {
425a08f4bf6SPeter Wemm 			p->p_flag |= P_SUGID;
426df8bae1dSRodney W. Grimes 			pc->p_ruid = uid;
427d3cdb93dSAndrey A. Chernov 		}
428a08f4bf6SPeter Wemm 		/*
429a08f4bf6SPeter Wemm 		 * Set saved uid
430a08f4bf6SPeter Wemm 		 *
431a08f4bf6SPeter Wemm 		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
432a08f4bf6SPeter Wemm 		 * the security of seteuid() depends on it.  B.4.2.2 says it
433a08f4bf6SPeter Wemm 		 * is important that we should do this.
434a08f4bf6SPeter Wemm 		 */
435a08f4bf6SPeter Wemm 		if (pc->p_svuid != uid) {
436a08f4bf6SPeter Wemm 			p->p_flag |= P_SUGID;
437a08f4bf6SPeter Wemm 			pc->p_svuid = uid;
438a08f4bf6SPeter Wemm 		}
439a08f4bf6SPeter Wemm 	}
440a08f4bf6SPeter Wemm 
441a08f4bf6SPeter Wemm 	/*
442a08f4bf6SPeter Wemm 	 * In all permitted cases, we are changing the euid.
443a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
444a08f4bf6SPeter Wemm 	 */
445a08f4bf6SPeter Wemm 	if (pc->pc_ucred->cr_uid != uid) {
446a08f4bf6SPeter Wemm 		pc->pc_ucred = crcopy(pc->pc_ucred);
4472c3be6c3SAndrey A. Chernov 		pc->pc_ucred->cr_uid = uid;
448df8bae1dSRodney W. Grimes 		p->p_flag |= P_SUGID;
449a08f4bf6SPeter Wemm 	}
450df8bae1dSRodney W. Grimes 	return (0);
451df8bae1dSRodney W. Grimes }
452df8bae1dSRodney W. Grimes 
453d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
454df8bae1dSRodney W. Grimes struct seteuid_args {
455df8bae1dSRodney W. Grimes 	uid_t	euid;
456df8bae1dSRodney W. Grimes };
457d2d3e875SBruce Evans #endif
458df8bae1dSRodney W. Grimes /* ARGSUSED */
45926f9a767SRodney W. Grimes int
460df8bae1dSRodney W. Grimes seteuid(p, uap, retval)
461df8bae1dSRodney W. Grimes 	struct proc *p;
462df8bae1dSRodney W. Grimes 	struct seteuid_args *uap;
463df8bae1dSRodney W. Grimes 	int *retval;
464df8bae1dSRodney W. Grimes {
465df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
466df8bae1dSRodney W. Grimes 	register uid_t euid;
467df8bae1dSRodney W. Grimes 	int error;
468df8bae1dSRodney W. Grimes 
469df8bae1dSRodney W. Grimes 	euid = uap->euid;
470229a15f0SPeter Wemm 	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
471229a15f0SPeter Wemm 	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
472df8bae1dSRodney W. Grimes 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
473df8bae1dSRodney W. Grimes 		return (error);
474df8bae1dSRodney W. Grimes 	/*
475df8bae1dSRodney W. Grimes 	 * Everything's okay, do it.  Copy credentials so other references do
476df8bae1dSRodney W. Grimes 	 * not see our changes.
477df8bae1dSRodney W. Grimes 	 */
478229a15f0SPeter Wemm 	if (pc->pc_ucred->cr_uid != euid) {
479df8bae1dSRodney W. Grimes 		pc->pc_ucred = crcopy(pc->pc_ucred);
480df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_uid = euid;
481df8bae1dSRodney W. Grimes 		p->p_flag |= P_SUGID;
482229a15f0SPeter Wemm 	}
483df8bae1dSRodney W. Grimes 	return (0);
484df8bae1dSRodney W. Grimes }
485df8bae1dSRodney W. Grimes 
486d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
487df8bae1dSRodney W. Grimes struct setgid_args {
488df8bae1dSRodney W. Grimes 	gid_t	gid;
489df8bae1dSRodney W. Grimes };
490d2d3e875SBruce Evans #endif
491df8bae1dSRodney W. Grimes /* ARGSUSED */
49226f9a767SRodney W. Grimes int
493df8bae1dSRodney W. Grimes setgid(p, uap, retval)
494df8bae1dSRodney W. Grimes 	struct proc *p;
495df8bae1dSRodney W. Grimes 	struct setgid_args *uap;
496df8bae1dSRodney W. Grimes 	int *retval;
497df8bae1dSRodney W. Grimes {
498df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
499df8bae1dSRodney W. Grimes 	register gid_t gid;
500df8bae1dSRodney W. Grimes 	int error;
501df8bae1dSRodney W. Grimes 
502a08f4bf6SPeter Wemm 	/*
503a08f4bf6SPeter Wemm 	 * See if we have "permission" by POSIX 1003.1 rules.
504a08f4bf6SPeter Wemm 	 *
505a08f4bf6SPeter Wemm 	 * Note that setgid(getegid()) is a special case of
506a08f4bf6SPeter Wemm 	 * "appropriate privileges" in appendix B.4.2.2.  We need
507a08f4bf6SPeter Wemm 	 * to use this clause to be compatable with traditional BSD
508a08f4bf6SPeter Wemm 	 * semantics.  Basically, it means that "setgid(xx)" sets all
509a08f4bf6SPeter Wemm 	 * three id's (assuming you have privs).
510a08f4bf6SPeter Wemm 	 *
511a08f4bf6SPeter Wemm 	 * For notes on the logic here, see setuid() above.
512a08f4bf6SPeter Wemm 	 */
513df8bae1dSRodney W. Grimes 	gid = uap->gid;
514a08f4bf6SPeter Wemm 	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
5153f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS
516a08f4bf6SPeter Wemm 	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
517a08f4bf6SPeter Wemm #endif
518a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
519a08f4bf6SPeter Wemm 	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
5203f246666SAndrey A. Chernov #endif
5212c3be6c3SAndrey A. Chernov 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
522df8bae1dSRodney W. Grimes 		return (error);
523a08f4bf6SPeter Wemm 
524a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS
525a08f4bf6SPeter Wemm 	/*
526a08f4bf6SPeter Wemm 	 * Do we have "appropriate privileges" (are we root or gid == egid)
527a08f4bf6SPeter Wemm 	 * If so, we are changing the real uid and saved gid.
528a08f4bf6SPeter Wemm 	 */
529a08f4bf6SPeter Wemm 	if (
530a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
531a08f4bf6SPeter Wemm 	    gid == pc->pc_ucred->cr_groups[0] ||
532a08f4bf6SPeter Wemm #endif
533a08f4bf6SPeter Wemm 	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
534a08f4bf6SPeter Wemm #endif
535a08f4bf6SPeter Wemm 	{
536a08f4bf6SPeter Wemm 		/*
537a08f4bf6SPeter Wemm 		 * Set real gid
538a08f4bf6SPeter Wemm 		 */
539a08f4bf6SPeter Wemm 		if (pc->p_rgid != gid) {
540a08f4bf6SPeter Wemm 			p->p_flag |= P_SUGID;
541a08f4bf6SPeter Wemm 			pc->p_rgid = gid;
542a08f4bf6SPeter Wemm 		}
543a08f4bf6SPeter Wemm 		/*
544a08f4bf6SPeter Wemm 		 * Set saved gid
545a08f4bf6SPeter Wemm 		 *
546a08f4bf6SPeter Wemm 		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
547a08f4bf6SPeter Wemm 		 * the security of setegid() depends on it.  B.4.2.2 says it
548a08f4bf6SPeter Wemm 		 * is important that we should do this.
549a08f4bf6SPeter Wemm 		 */
550a08f4bf6SPeter Wemm 		if (pc->p_svgid != gid) {
551a08f4bf6SPeter Wemm 			p->p_flag |= P_SUGID;
552a08f4bf6SPeter Wemm 			pc->p_svgid = gid;
553a08f4bf6SPeter Wemm 		}
554a08f4bf6SPeter Wemm 	}
555a08f4bf6SPeter Wemm 	/*
556a08f4bf6SPeter Wemm 	 * In all cases permitted cases, we are changing the egid.
557a08f4bf6SPeter Wemm 	 * Copy credentials so other references do not see our changes.
558a08f4bf6SPeter Wemm 	 */
559a08f4bf6SPeter Wemm 	if (pc->pc_ucred->cr_groups[0] != gid) {
560df8bae1dSRodney W. Grimes 		pc->pc_ucred = crcopy(pc->pc_ucred);
561df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_groups[0] = gid;
562df8bae1dSRodney W. Grimes 		p->p_flag |= P_SUGID;
563a08f4bf6SPeter Wemm 	}
564df8bae1dSRodney W. Grimes 	return (0);
565df8bae1dSRodney W. Grimes }
566df8bae1dSRodney W. Grimes 
567d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
568df8bae1dSRodney W. Grimes struct setegid_args {
569df8bae1dSRodney W. Grimes 	gid_t	egid;
570df8bae1dSRodney W. Grimes };
571d2d3e875SBruce Evans #endif
572df8bae1dSRodney W. Grimes /* ARGSUSED */
57326f9a767SRodney W. Grimes int
574df8bae1dSRodney W. Grimes setegid(p, uap, retval)
575df8bae1dSRodney W. Grimes 	struct proc *p;
576df8bae1dSRodney W. Grimes 	struct setegid_args *uap;
577df8bae1dSRodney W. Grimes 	int *retval;
578df8bae1dSRodney W. Grimes {
579df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
580df8bae1dSRodney W. Grimes 	register gid_t egid;
581df8bae1dSRodney W. Grimes 	int error;
582df8bae1dSRodney W. Grimes 
583df8bae1dSRodney W. Grimes 	egid = uap->egid;
584229a15f0SPeter Wemm 	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
585229a15f0SPeter Wemm 	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
586df8bae1dSRodney W. Grimes 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
587df8bae1dSRodney W. Grimes 		return (error);
588229a15f0SPeter Wemm 	if (pc->pc_ucred->cr_groups[0] != egid) {
589df8bae1dSRodney W. Grimes 		pc->pc_ucred = crcopy(pc->pc_ucred);
590df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_groups[0] = egid;
591df8bae1dSRodney W. Grimes 		p->p_flag |= P_SUGID;
592229a15f0SPeter Wemm 	}
593df8bae1dSRodney W. Grimes 	return (0);
594df8bae1dSRodney W. Grimes }
595df8bae1dSRodney W. Grimes 
596d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
597df8bae1dSRodney W. Grimes struct setgroups_args {
598df8bae1dSRodney W. Grimes 	u_int	gidsetsize;
599df8bae1dSRodney W. Grimes 	gid_t	*gidset;
600df8bae1dSRodney W. Grimes };
601d2d3e875SBruce Evans #endif
602df8bae1dSRodney W. Grimes /* ARGSUSED */
60326f9a767SRodney W. Grimes int
604df8bae1dSRodney W. Grimes setgroups(p, uap, retval)
605df8bae1dSRodney W. Grimes 	struct proc *p;
606df8bae1dSRodney W. Grimes 	struct setgroups_args *uap;
607df8bae1dSRodney W. Grimes 	int *retval;
608df8bae1dSRodney W. Grimes {
609df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
610df8bae1dSRodney W. Grimes 	register u_int ngrp;
611df8bae1dSRodney W. Grimes 	int error;
612df8bae1dSRodney W. Grimes 
613bb56ec4aSPoul-Henning Kamp 	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
614df8bae1dSRodney W. Grimes 		return (error);
6153956a170SDavid Greenman 	ngrp = uap->gidsetsize;
6168a5d815aSPeter Wemm 	if (ngrp > NGROUPS)
617df8bae1dSRodney W. Grimes 		return (EINVAL);
6188a5d815aSPeter Wemm 	/*
6198a5d815aSPeter Wemm 	 * XXX A little bit lazy here.  We could test if anything has
6208a5d815aSPeter Wemm 	 * changed before crcopy() and setting P_SUGID.
6218a5d815aSPeter Wemm 	 */
622df8bae1dSRodney W. Grimes 	pc->pc_ucred = crcopy(pc->pc_ucred);
6238a5d815aSPeter Wemm 	if (ngrp < 1) {
6248a5d815aSPeter Wemm 		/*
6258a5d815aSPeter Wemm 		 * setgroups(0, NULL) is a legitimate way of clearing the
6268a5d815aSPeter Wemm 		 * groups vector on non-BSD systems (which generally do not
6278a5d815aSPeter Wemm 		 * have the egid in the groups[0]).  We risk security holes
6288a5d815aSPeter Wemm 		 * when running non-BSD software if we do not do the same.
6298a5d815aSPeter Wemm 		 */
6308a5d815aSPeter Wemm 		pc->pc_ucred->cr_ngroups = 1;
6318a5d815aSPeter Wemm 	} else {
632bb56ec4aSPoul-Henning Kamp 		if ((error = copyin((caddr_t)uap->gidset,
633bb56ec4aSPoul-Henning Kamp 		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
634df8bae1dSRodney W. Grimes 			return (error);
635df8bae1dSRodney W. Grimes 		pc->pc_ucred->cr_ngroups = ngrp;
6368a5d815aSPeter Wemm 	}
637df8bae1dSRodney W. Grimes 	p->p_flag |= P_SUGID;
638df8bae1dSRodney W. Grimes 	return (0);
639df8bae1dSRodney W. Grimes }
640df8bae1dSRodney W. Grimes 
641d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
642df8bae1dSRodney W. Grimes struct setreuid_args {
64300999cd6SAndrey A. Chernov 	uid_t	ruid;
64400999cd6SAndrey A. Chernov 	uid_t	euid;
645df8bae1dSRodney W. Grimes };
646d2d3e875SBruce Evans #endif
647df8bae1dSRodney W. Grimes /* ARGSUSED */
64826f9a767SRodney W. Grimes int
649e876c909SAndrey A. Chernov setreuid(p, uap, retval)
650df8bae1dSRodney W. Grimes 	register struct proc *p;
651df8bae1dSRodney W. Grimes 	struct setreuid_args *uap;
652df8bae1dSRodney W. Grimes 	int *retval;
653df8bae1dSRodney W. Grimes {
654df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
65500999cd6SAndrey A. Chernov 	register uid_t ruid, euid;
656611d721eSAndrey A. Chernov 	int error;
657df8bae1dSRodney W. Grimes 
65800999cd6SAndrey A. Chernov 	ruid = uap->ruid;
65900999cd6SAndrey A. Chernov 	euid = uap->euid;
66000999cd6SAndrey A. Chernov 	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
661b79c6a86SPeter Wemm 	     euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
662b79c6a86SPeter Wemm 	     euid != pc->p_ruid && euid != pc->p_svuid) &&
663611d721eSAndrey A. Chernov 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
664611d721eSAndrey A. Chernov 		return (error);
66500999cd6SAndrey A. Chernov 
666a89a5370SPeter Wemm 	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
66700999cd6SAndrey A. Chernov 		pc->pc_ucred = crcopy(pc->pc_ucred);
66800999cd6SAndrey A. Chernov 		pc->pc_ucred->cr_uid = euid;
669a89a5370SPeter Wemm 		p->p_flag |= P_SUGID;
670a89a5370SPeter Wemm 	}
671a89a5370SPeter Wemm 	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
6724bc8f31fSAndrey A. Chernov 		(void)chgproccnt(pc->p_ruid, -1);
67300999cd6SAndrey A. Chernov 		(void)chgproccnt(ruid, 1);
67400999cd6SAndrey A. Chernov 		pc->p_ruid = ruid;
675a89a5370SPeter Wemm 		p->p_flag |= P_SUGID;
67600999cd6SAndrey A. Chernov 	}
677b79c6a86SPeter Wemm 	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
678b79c6a86SPeter Wemm 	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6794bc8f31fSAndrey A. Chernov 		pc->p_svuid = pc->pc_ucred->cr_uid;
6804bc8f31fSAndrey A. Chernov 		p->p_flag |= P_SUGID;
681a89a5370SPeter Wemm 	}
682611d721eSAndrey A. Chernov 	return (0);
683df8bae1dSRodney W. Grimes }
684df8bae1dSRodney W. Grimes 
685d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
686df8bae1dSRodney W. Grimes struct setregid_args {
68700999cd6SAndrey A. Chernov 	gid_t	rgid;
68800999cd6SAndrey A. Chernov 	gid_t	egid;
689df8bae1dSRodney W. Grimes };
690d2d3e875SBruce Evans #endif
691df8bae1dSRodney W. Grimes /* ARGSUSED */
69226f9a767SRodney W. Grimes int
693e876c909SAndrey A. Chernov setregid(p, uap, retval)
694df8bae1dSRodney W. Grimes 	register struct proc *p;
695df8bae1dSRodney W. Grimes 	struct setregid_args *uap;
696df8bae1dSRodney W. Grimes 	int *retval;
697df8bae1dSRodney W. Grimes {
698df8bae1dSRodney W. Grimes 	register struct pcred *pc = p->p_cred;
69900999cd6SAndrey A. Chernov 	register gid_t rgid, egid;
700611d721eSAndrey A. Chernov 	int error;
701df8bae1dSRodney W. Grimes 
70200999cd6SAndrey A. Chernov 	rgid = uap->rgid;
70300999cd6SAndrey A. Chernov 	egid = uap->egid;
70400999cd6SAndrey A. Chernov 	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
705b79c6a86SPeter Wemm 	     egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
706b79c6a86SPeter Wemm 	     egid != pc->p_rgid && egid != pc->p_svgid) &&
707611d721eSAndrey A. Chernov 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
708611d721eSAndrey A. Chernov 		return (error);
70900999cd6SAndrey A. Chernov 
710a89a5370SPeter Wemm 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
71100999cd6SAndrey A. Chernov 		pc->pc_ucred = crcopy(pc->pc_ucred);
71200999cd6SAndrey A. Chernov 		pc->pc_ucred->cr_groups[0] = egid;
713a89a5370SPeter Wemm 		p->p_flag |= P_SUGID;
714a89a5370SPeter Wemm 	}
715a89a5370SPeter Wemm 	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
71600999cd6SAndrey A. Chernov 		pc->p_rgid = rgid;
717a89a5370SPeter Wemm 		p->p_flag |= P_SUGID;
718a89a5370SPeter Wemm 	}
719b79c6a86SPeter Wemm 	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
720b79c6a86SPeter Wemm 	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7214bc8f31fSAndrey A. Chernov 		pc->p_svgid = pc->pc_ucred->cr_groups[0];
7224bc8f31fSAndrey A. Chernov 		p->p_flag |= P_SUGID;
723a89a5370SPeter Wemm 	}
724611d721eSAndrey A. Chernov 	return (0);
725df8bae1dSRodney W. Grimes }
726df8bae1dSRodney W. Grimes 
727b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_
728b67cbc65SPeter Wemm struct issetugid_args {
729b67cbc65SPeter Wemm 	int dummy;
730b67cbc65SPeter Wemm };
731b67cbc65SPeter Wemm #endif
732b67cbc65SPeter Wemm /* ARGSUSED */
733b67cbc65SPeter Wemm int
734b67cbc65SPeter Wemm issetugid(p, uap, retval)
735b67cbc65SPeter Wemm 	register struct proc *p;
736b67cbc65SPeter Wemm 	struct issetugid_args *uap;
737b67cbc65SPeter Wemm 	int *retval;
738b67cbc65SPeter Wemm {
739b67cbc65SPeter Wemm 	/*
740b67cbc65SPeter Wemm 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
741b67cbc65SPeter Wemm 	 * we use P_SUGID because we consider changing the owners as
742b67cbc65SPeter Wemm 	 * "tainting" as well.
743b67cbc65SPeter Wemm 	 * This is significant for procs that start as root and "become"
744b67cbc65SPeter Wemm 	 * a user without an exec - programs cannot know *everything*
745b67cbc65SPeter Wemm 	 * that libc *might* have put in their data segment.
746b67cbc65SPeter Wemm 	 */
747b67cbc65SPeter Wemm 	if (p->p_flag & P_SUGID)
748b67cbc65SPeter Wemm 		return (1);
749b67cbc65SPeter Wemm 	return (0);
750b67cbc65SPeter Wemm }
751b67cbc65SPeter Wemm 
752df8bae1dSRodney W. Grimes /*
753df8bae1dSRodney W. Grimes  * Check if gid is a member of the group set.
754df8bae1dSRodney W. Grimes  */
75526f9a767SRodney W. Grimes int
756df8bae1dSRodney W. Grimes groupmember(gid, cred)
757df8bae1dSRodney W. Grimes 	gid_t gid;
758df8bae1dSRodney W. Grimes 	register struct ucred *cred;
759df8bae1dSRodney W. Grimes {
760df8bae1dSRodney W. Grimes 	register gid_t *gp;
761df8bae1dSRodney W. Grimes 	gid_t *egp;
762df8bae1dSRodney W. Grimes 
763df8bae1dSRodney W. Grimes 	egp = &(cred->cr_groups[cred->cr_ngroups]);
764df8bae1dSRodney W. Grimes 	for (gp = cred->cr_groups; gp < egp; gp++)
765df8bae1dSRodney W. Grimes 		if (*gp == gid)
766df8bae1dSRodney W. Grimes 			return (1);
767df8bae1dSRodney W. Grimes 	return (0);
768df8bae1dSRodney W. Grimes }
769df8bae1dSRodney W. Grimes 
770df8bae1dSRodney W. Grimes /*
771df8bae1dSRodney W. Grimes  * Test whether the specified credentials imply "super-user"
772df8bae1dSRodney W. Grimes  * privilege; if so, and we have accounting info, set the flag
773df8bae1dSRodney W. Grimes  * indicating use of super-powers.
774df8bae1dSRodney W. Grimes  * Returns 0 or error.
775df8bae1dSRodney W. Grimes  */
77626f9a767SRodney W. Grimes int
777df8bae1dSRodney W. Grimes suser(cred, acflag)
778df8bae1dSRodney W. Grimes 	struct ucred *cred;
779453de7daSBruce Evans 	u_short *acflag;
780df8bae1dSRodney W. Grimes {
781df8bae1dSRodney W. Grimes 	if (cred->cr_uid == 0) {
782df8bae1dSRodney W. Grimes 		if (acflag)
783df8bae1dSRodney W. Grimes 			*acflag |= ASU;
784df8bae1dSRodney W. Grimes 		return (0);
785df8bae1dSRodney W. Grimes 	}
786df8bae1dSRodney W. Grimes 	return (EPERM);
787df8bae1dSRodney W. Grimes }
788df8bae1dSRodney W. Grimes 
789df8bae1dSRodney W. Grimes /*
790df8bae1dSRodney W. Grimes  * Allocate a zeroed cred structure.
791df8bae1dSRodney W. Grimes  */
792df8bae1dSRodney W. Grimes struct ucred *
793df8bae1dSRodney W. Grimes crget()
794df8bae1dSRodney W. Grimes {
795df8bae1dSRodney W. Grimes 	register struct ucred *cr;
796df8bae1dSRodney W. Grimes 
797df8bae1dSRodney W. Grimes 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
798df8bae1dSRodney W. Grimes 	bzero((caddr_t)cr, sizeof(*cr));
799df8bae1dSRodney W. Grimes 	cr->cr_ref = 1;
800df8bae1dSRodney W. Grimes 	return (cr);
801df8bae1dSRodney W. Grimes }
802df8bae1dSRodney W. Grimes 
803df8bae1dSRodney W. Grimes /*
804df8bae1dSRodney W. Grimes  * Free a cred structure.
805df8bae1dSRodney W. Grimes  * Throws away space when ref count gets to 0.
806df8bae1dSRodney W. Grimes  */
80726f9a767SRodney W. Grimes void
808df8bae1dSRodney W. Grimes crfree(cr)
809df8bae1dSRodney W. Grimes 	struct ucred *cr;
810df8bae1dSRodney W. Grimes {
811df8bae1dSRodney W. Grimes 	int s;
812df8bae1dSRodney W. Grimes 
813df8bae1dSRodney W. Grimes 	s = splimp();				/* ??? */
814df8bae1dSRodney W. Grimes 	if (--cr->cr_ref == 0)
815df8bae1dSRodney W. Grimes 		FREE((caddr_t)cr, M_CRED);
816df8bae1dSRodney W. Grimes 	(void) splx(s);
817df8bae1dSRodney W. Grimes }
818df8bae1dSRodney W. Grimes 
819df8bae1dSRodney W. Grimes /*
820df8bae1dSRodney W. Grimes  * Copy cred structure to a new one and free the old one.
821df8bae1dSRodney W. Grimes  */
822df8bae1dSRodney W. Grimes struct ucred *
823df8bae1dSRodney W. Grimes crcopy(cr)
824df8bae1dSRodney W. Grimes 	struct ucred *cr;
825df8bae1dSRodney W. Grimes {
826df8bae1dSRodney W. Grimes 	struct ucred *newcr;
827df8bae1dSRodney W. Grimes 
828df8bae1dSRodney W. Grimes 	if (cr->cr_ref == 1)
829df8bae1dSRodney W. Grimes 		return (cr);
830df8bae1dSRodney W. Grimes 	newcr = crget();
831df8bae1dSRodney W. Grimes 	*newcr = *cr;
832df8bae1dSRodney W. Grimes 	crfree(cr);
833df8bae1dSRodney W. Grimes 	newcr->cr_ref = 1;
834df8bae1dSRodney W. Grimes 	return (newcr);
835df8bae1dSRodney W. Grimes }
836df8bae1dSRodney W. Grimes 
837df8bae1dSRodney W. Grimes /*
838df8bae1dSRodney W. Grimes  * Dup cred struct to a new held one.
839df8bae1dSRodney W. Grimes  */
840df8bae1dSRodney W. Grimes struct ucred *
841df8bae1dSRodney W. Grimes crdup(cr)
842df8bae1dSRodney W. Grimes 	struct ucred *cr;
843df8bae1dSRodney W. Grimes {
844df8bae1dSRodney W. Grimes 	struct ucred *newcr;
845df8bae1dSRodney W. Grimes 
846df8bae1dSRodney W. Grimes 	newcr = crget();
847df8bae1dSRodney W. Grimes 	*newcr = *cr;
848df8bae1dSRodney W. Grimes 	newcr->cr_ref = 1;
849df8bae1dSRodney W. Grimes 	return (newcr);
850df8bae1dSRodney W. Grimes }
851df8bae1dSRodney W. Grimes 
852df8bae1dSRodney W. Grimes /*
853df8bae1dSRodney W. Grimes  * Get login name, if available.
854df8bae1dSRodney W. Grimes  */
855d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
856df8bae1dSRodney W. Grimes struct getlogin_args {
857df8bae1dSRodney W. Grimes 	char	*namebuf;
858df8bae1dSRodney W. Grimes 	u_int	namelen;
859df8bae1dSRodney W. Grimes };
860d2d3e875SBruce Evans #endif
861df8bae1dSRodney W. Grimes /* ARGSUSED */
86226f9a767SRodney W. Grimes int
863df8bae1dSRodney W. Grimes getlogin(p, uap, retval)
864df8bae1dSRodney W. Grimes 	struct proc *p;
865df8bae1dSRodney W. Grimes 	struct getlogin_args *uap;
866df8bae1dSRodney W. Grimes 	int *retval;
867df8bae1dSRodney W. Grimes {
868df8bae1dSRodney W. Grimes 
86930cf3ac4SAndrey A. Chernov 	if (uap->namelen > MAXLOGNAME)
87053490b76SAndrey A. Chernov 		uap->namelen = MAXLOGNAME;
871df8bae1dSRodney W. Grimes 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
872df8bae1dSRodney W. Grimes 	    (caddr_t) uap->namebuf, uap->namelen));
873df8bae1dSRodney W. Grimes }
874df8bae1dSRodney W. Grimes 
875df8bae1dSRodney W. Grimes /*
876df8bae1dSRodney W. Grimes  * Set login name.
877df8bae1dSRodney W. Grimes  */
878d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
879df8bae1dSRodney W. Grimes struct setlogin_args {
880df8bae1dSRodney W. Grimes 	char	*namebuf;
881df8bae1dSRodney W. Grimes };
882d2d3e875SBruce Evans #endif
883df8bae1dSRodney W. Grimes /* ARGSUSED */
88426f9a767SRodney W. Grimes int
885df8bae1dSRodney W. Grimes setlogin(p, uap, retval)
886df8bae1dSRodney W. Grimes 	struct proc *p;
887df8bae1dSRodney W. Grimes 	struct setlogin_args *uap;
888df8bae1dSRodney W. Grimes 	int *retval;
889df8bae1dSRodney W. Grimes {
890df8bae1dSRodney W. Grimes 	int error;
891964ca0caSAndrey A. Chernov 	char logintmp[MAXLOGNAME];
892df8bae1dSRodney W. Grimes 
893bb56ec4aSPoul-Henning Kamp 	if ((error = suser(p->p_ucred, &p->p_acflag)))
894df8bae1dSRodney W. Grimes 		return (error);
895184989c2SDavid Nugent 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
896184989c2SDavid Nugent 	    sizeof(logintmp), (u_int *)0);
897df8bae1dSRodney W. Grimes 	if (error == ENAMETOOLONG)
898df8bae1dSRodney W. Grimes 		error = EINVAL;
899184989c2SDavid Nugent 	else if (!error)
900184989c2SDavid Nugent 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
901964ca0caSAndrey A. Chernov 		    sizeof(logintmp));
902df8bae1dSRodney W. Grimes 	return (error);
903df8bae1dSRodney W. Grimes }
904