1139804Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3165897Srwatson *	The Regents of the University of California.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
5165897Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson.
6165897Srwatson * All rights reserved.
7165897Srwatson *
81541Srgrimes * All or some portions of this file are derived from material licensed
91541Srgrimes * to the University of California by American Telephone and Telegraph
101541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
111541Srgrimes * the permission of UNIX System Laboratories, Inc.
121541Srgrimes *
131541Srgrimes * Redistribution and use in source and binary forms, with or without
141541Srgrimes * modification, are permitted provided that the following conditions
151541Srgrimes * are met:
161541Srgrimes * 1. Redistributions of source code must retain the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer.
181541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191541Srgrimes *    notice, this list of conditions and the following disclaimer in the
201541Srgrimes *    documentation and/or other materials provided with the distribution.
211541Srgrimes * 4. Neither the name of the University nor the names of its contributors
221541Srgrimes *    may be used to endorse or promote products derived from this software
231541Srgrimes *    without specific prior written permission.
241541Srgrimes *
251541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351541Srgrimes * SUCH DAMAGE.
361541Srgrimes *
371541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
381541Srgrimes */
391541Srgrimes
401541Srgrimes/*
411541Srgrimes * System calls related to processes and protection
421541Srgrimes */
431541Srgrimes
44116182Sobrien#include <sys/cdefs.h>
45116182Sobrien__FBSDID("$FreeBSD$");
46116182Sobrien
4731778Seivind#include "opt_compat.h"
48183982Sbz#include "opt_inet.h"
49183982Sbz#include "opt_inet6.h"
5031778Seivind
511541Srgrimes#include <sys/param.h>
5276166Smarkm#include <sys/systm.h>
531541Srgrimes#include <sys/acct.h>
54132548Srwatson#include <sys/kdb.h>
5541059Speter#include <sys/kernel.h>
5670317Sjake#include <sys/lock.h>
57219304Strasz#include <sys/loginclass.h>
5891140Stanimura#include <sys/malloc.h>
5976166Smarkm#include <sys/mutex.h>
60150634Sjhb#include <sys/refcount.h>
6191140Stanimura#include <sys/sx.h>
62164032Srwatson#include <sys/priv.h>
631541Srgrimes#include <sys/proc.h>
6476166Smarkm#include <sys/sysproto.h>
6587218Srwatson#include <sys/jail.h>
6631891Ssef#include <sys/pioctl.h>
67220212Strasz#include <sys/racct.h>
6865495Struckman#include <sys/resourcevar.h>
6992976Srwatson#include <sys/socket.h>
7092976Srwatson#include <sys/socketvar.h>
71160139Sjhb#include <sys/syscallsubr.h>
7261287Srwatson#include <sys/sysctl.h>
731541Srgrimes
74219028Snetchild#ifdef REGRESSION
75219028SnetchildFEATURE(regression,
76229818Shrs    "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
77219028Snetchild#endif
78219028Snetchild
79183982Sbz#if defined(INET) || defined(INET6)
80183982Sbz#include <netinet/in.h>
81183982Sbz#include <netinet/in_pcb.h>
82183982Sbz#endif
83183982Sbz
84155370Swsalamon#include <security/audit/audit.h>
85163606Srwatson#include <security/mac/mac_framework.h>
86155370Swsalamon
8730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
8830354Sphk
89162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy");
9087138Srwatson
91194498Sbrooksstatic void crsetgroups_locked(struct ucred *cr, int ngrp,
92194498Sbrooks    gid_t *groups);
93194498Sbrooks
9412221Sbde#ifndef _SYS_SYSPROTO_H_
9511332Sswallacestruct getpid_args {
961541Srgrimes	int	dummy;
971541Srgrimes};
9812221Sbde#endif
991541Srgrimes/* ARGSUSED */
1001549Srgrimesint
101225617Skmacysys_getpid(struct thread *td, struct getpid_args *uap)
1021541Srgrimes{
10383366Sjulian	struct proc *p = td->td_proc;
1041541Srgrimes
10583366Sjulian	td->td_retval[0] = p->p_pid;
106130344Sphk#if defined(COMPAT_43)
10774728Sjhb	PROC_LOCK(p);
10883366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
10974728Sjhb	PROC_UNLOCK(p);
1101541Srgrimes#endif
1111541Srgrimes	return (0);
1121541Srgrimes}
1131541Srgrimes
11412221Sbde#ifndef _SYS_SYSPROTO_H_
11511332Sswallacestruct getppid_args {
11611332Sswallace        int     dummy;
11711332Sswallace};
11812221Sbde#endif
1191541Srgrimes/* ARGSUSED */
1201549Srgrimesint
121225617Skmacysys_getppid(struct thread *td, struct getppid_args *uap)
1221541Srgrimes{
12383366Sjulian	struct proc *p = td->td_proc;
1241541Srgrimes
12574728Sjhb	PROC_LOCK(p);
12683366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
12774728Sjhb	PROC_UNLOCK(p);
1281541Srgrimes	return (0);
1291541Srgrimes}
1301541Srgrimes
13187466Srwatson/*
13287218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
13358717Sdillon */
13412221Sbde#ifndef _SYS_SYSPROTO_H_
13511332Sswallacestruct getpgrp_args {
13611332Sswallace        int     dummy;
13711332Sswallace};
13812221Sbde#endif
1391549Srgrimesint
140225617Skmacysys_getpgrp(struct thread *td, struct getpgrp_args *uap)
1411541Srgrimes{
14283366Sjulian	struct proc *p = td->td_proc;
1431541Srgrimes
14491140Stanimura	PROC_LOCK(p);
14583366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
14691140Stanimura	PROC_UNLOCK(p);
1471541Srgrimes	return (0);
1481541Srgrimes}
1491541Srgrimes
150302234Sbdrewery/* Get an arbitrary pid's process group id */
15112221Sbde#ifndef _SYS_SYSPROTO_H_
15228401Speterstruct getpgid_args {
15328401Speter	pid_t	pid;
15428401Speter};
15528401Speter#endif
15628401Speterint
157225617Skmacysys_getpgid(struct thread *td, struct getpgid_args *uap)
15828401Speter{
159114031Sjhb	struct proc *p;
16092985Sjhb	int error;
16141726Struckman
16291140Stanimura	if (uap->pid == 0) {
163114031Sjhb		p = td->td_proc;
16491140Stanimura		PROC_LOCK(p);
165114031Sjhb	} else {
166114031Sjhb		p = pfind(uap->pid);
167114031Sjhb		if (p == NULL)
168114031Sjhb			return (ESRCH);
169114031Sjhb		error = p_cansee(td, p);
170114031Sjhb		if (error) {
171114031Sjhb			PROC_UNLOCK(p);
172114031Sjhb			return (error);
173114031Sjhb		}
17475893Sjhb	}
175114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
176114031Sjhb	PROC_UNLOCK(p);
177114031Sjhb	return (0);
17828401Speter}
17928401Speter
18028401Speter/*
181302234Sbdrewery * Get an arbitrary pid's session id.
18228401Speter */
18328401Speter#ifndef _SYS_SYSPROTO_H_
18428401Speterstruct getsid_args {
18528401Speter	pid_t	pid;
18628401Speter};
18728401Speter#endif
18828401Speterint
189225617Skmacysys_getsid(struct thread *td, struct getsid_args *uap)
19028401Speter{
191114031Sjhb	struct proc *p;
19287218Srwatson	int error;
19341726Struckman
19491140Stanimura	if (uap->pid == 0) {
195114031Sjhb		p = td->td_proc;
19691140Stanimura		PROC_LOCK(p);
197114031Sjhb	} else {
198114031Sjhb		p = pfind(uap->pid);
199114031Sjhb		if (p == NULL)
200114031Sjhb			return (ESRCH);
201114031Sjhb		error = p_cansee(td, p);
202114031Sjhb		if (error) {
203114031Sjhb			PROC_UNLOCK(p);
204114031Sjhb			return (error);
205114031Sjhb		}
20675893Sjhb	}
207114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
208114031Sjhb	PROC_UNLOCK(p);
209114031Sjhb	return (0);
21028401Speter}
21128401Speter
21228401Speter#ifndef _SYS_SYSPROTO_H_
21311332Sswallacestruct getuid_args {
21411332Sswallace        int     dummy;
21511332Sswallace};
21612221Sbde#endif
2171541Srgrimes/* ARGSUSED */
2181549Srgrimesint
219225617Skmacysys_getuid(struct thread *td, struct getuid_args *uap)
2201541Srgrimes{
2211541Srgrimes
22292987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
223130344Sphk#if defined(COMPAT_43)
22492987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2251541Srgrimes#endif
2261541Srgrimes	return (0);
2271541Srgrimes}
2281541Srgrimes
22912221Sbde#ifndef _SYS_SYSPROTO_H_
23011332Sswallacestruct geteuid_args {
23111332Sswallace        int     dummy;
23211332Sswallace};
23312221Sbde#endif
2341541Srgrimes/* ARGSUSED */
2351549Srgrimesint
236225617Skmacysys_geteuid(struct thread *td, struct geteuid_args *uap)
2371541Srgrimes{
23892987Sjhb
23992987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2401541Srgrimes	return (0);
2411541Srgrimes}
2421541Srgrimes
24312221Sbde#ifndef _SYS_SYSPROTO_H_
24411332Sswallacestruct getgid_args {
24511332Sswallace        int     dummy;
24611332Sswallace};
24712221Sbde#endif
2481541Srgrimes/* ARGSUSED */
2491549Srgrimesint
250225617Skmacysys_getgid(struct thread *td, struct getgid_args *uap)
2511541Srgrimes{
2521541Srgrimes
25392987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
254130344Sphk#if defined(COMPAT_43)
25592987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2561541Srgrimes#endif
2571541Srgrimes	return (0);
2581541Srgrimes}
2591541Srgrimes
2601541Srgrimes/*
2611541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2621541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2631541Srgrimes * correctly in a library function.
2641541Srgrimes */
26512221Sbde#ifndef _SYS_SYSPROTO_H_
26611332Sswallacestruct getegid_args {
26711332Sswallace        int     dummy;
26811332Sswallace};
26912221Sbde#endif
2701541Srgrimes/* ARGSUSED */
2711549Srgrimesint
272225617Skmacysys_getegid(struct thread *td, struct getegid_args *uap)
2731541Srgrimes{
2741541Srgrimes
27592987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2761541Srgrimes	return (0);
2771541Srgrimes}
2781541Srgrimes
27912221Sbde#ifndef _SYS_SYSPROTO_H_
2801541Srgrimesstruct getgroups_args {
2811541Srgrimes	u_int	gidsetsize;
2821541Srgrimes	gid_t	*gidset;
2831541Srgrimes};
28412221Sbde#endif
2851549Srgrimesint
286225617Skmacysys_getgroups(struct thread *td, register struct getgroups_args *uap)
2871541Srgrimes{
288194498Sbrooks	gid_t *groups;
28977183Srwatson	u_int ngrp;
29087218Srwatson	int error;
2911541Srgrimes
292202342Sbrooks	if (uap->gidsetsize < td->td_ucred->cr_ngroups) {
293202342Sbrooks		if (uap->gidsetsize == 0)
294202342Sbrooks			ngrp = 0;
295202342Sbrooks		else
296202342Sbrooks			return (EINVAL);
297202342Sbrooks	} else
298202342Sbrooks		ngrp = td->td_ucred->cr_ngroups;
299194498Sbrooks	groups = malloc(ngrp * sizeof(*groups), M_TEMP, M_WAITOK);
300160139Sjhb	error = kern_getgroups(td, &ngrp, groups);
301160139Sjhb	if (error)
302194498Sbrooks		goto out;
303160139Sjhb	if (uap->gidsetsize > 0)
304160139Sjhb		error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t));
305160139Sjhb	if (error == 0)
306160139Sjhb		td->td_retval[0] = ngrp;
307194498Sbrooksout:
308194498Sbrooks	free(groups, M_TEMP);
309160139Sjhb	return (error);
310160139Sjhb}
311160139Sjhb
312160139Sjhbint
313160139Sjhbkern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups)
314160139Sjhb{
315160139Sjhb	struct ucred *cred;
316160139Sjhb
31792987Sjhb	cred = td->td_ucred;
318160139Sjhb	if (*ngrp == 0) {
319160139Sjhb		*ngrp = cred->cr_ngroups;
32092987Sjhb		return (0);
3211541Srgrimes	}
322160139Sjhb	if (*ngrp < cred->cr_ngroups)
32392987Sjhb		return (EINVAL);
324160139Sjhb	*ngrp = cred->cr_ngroups;
325160139Sjhb	bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t));
326160139Sjhb	return (0);
3271541Srgrimes}
3281541Srgrimes
32912221Sbde#ifndef _SYS_SYSPROTO_H_
33012207Sbdestruct setsid_args {
33111332Sswallace        int     dummy;
33211332Sswallace};
33312221Sbde#endif
3341541Srgrimes/* ARGSUSED */
3351549Srgrimesint
336225617Skmacysys_setsid(register struct thread *td, struct setsid_args *uap)
3371541Srgrimes{
33891140Stanimura	struct pgrp *pgrp;
33982749Sdillon	int error;
34083366Sjulian	struct proc *p = td->td_proc;
34191140Stanimura	struct pgrp *newpgrp;
34291140Stanimura	struct session *newsess;
3431541Srgrimes
34491140Stanimura	error = 0;
34591140Stanimura	pgrp = NULL;
34691140Stanimura
347184205Sdes	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
348184205Sdes	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
34991140Stanimura
35094859Sjhb	sx_xlock(&proctree_lock);
35191140Stanimura
35291140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
35391140Stanimura		if (pgrp != NULL)
35491140Stanimura			PGRP_UNLOCK(pgrp);
35582749Sdillon		error = EPERM;
35691140Stanimura	} else {
35791140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
35883366Sjulian		td->td_retval[0] = p->p_pid;
35994859Sjhb		newpgrp = NULL;
36094859Sjhb		newsess = NULL;
3611541Srgrimes	}
36291140Stanimura
36394859Sjhb	sx_xunlock(&proctree_lock);
36491140Stanimura
36595973Stanimura	if (newpgrp != NULL)
366184205Sdes		free(newpgrp, M_PGRP);
36795973Stanimura	if (newsess != NULL)
368184205Sdes		free(newsess, M_SESSION);
36991140Stanimura
37094859Sjhb	return (error);
3711541Srgrimes}
3721541Srgrimes
3731541Srgrimes/*
3741541Srgrimes * set process group (setpgid/old setpgrp)
3751541Srgrimes *
3761541Srgrimes * caller does setpgid(targpid, targpgid)
3771541Srgrimes *
3781541Srgrimes * pid must be caller or child of caller (ESRCH)
3791541Srgrimes * if a child
3801541Srgrimes *	pid must be in same session (EPERM)
3811541Srgrimes *	pid can't have done an exec (EACCES)
3821541Srgrimes * if pgid != pid
3831541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3841541Srgrimes * pid must not be session leader (EPERM)
3851541Srgrimes */
38612221Sbde#ifndef _SYS_SYSPROTO_H_
3871541Srgrimesstruct setpgid_args {
38887218Srwatson	int	pid;		/* target process id */
38987218Srwatson	int	pgid;		/* target pgrp id */
3901541Srgrimes};
39112221Sbde#endif
3921541Srgrimes/* ARGSUSED */
3931549Srgrimesint
394225617Skmacysys_setpgid(struct thread *td, register struct setpgid_args *uap)
3951541Srgrimes{
39683366Sjulian	struct proc *curp = td->td_proc;
39787218Srwatson	register struct proc *targp;	/* target process */
39887218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
39975448Srwatson	int error;
40091140Stanimura	struct pgrp *newpgrp;
4011541Srgrimes
40220677Sbde	if (uap->pgid < 0)
40320677Sbde		return (EINVAL);
40491140Stanimura
40591140Stanimura	error = 0;
40691140Stanimura
407184205Sdes	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
40891140Stanimura
40994859Sjhb	sx_xlock(&proctree_lock);
4101541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
41191140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
41282749Sdillon			error = ESRCH;
41394859Sjhb			goto done;
41475893Sjhb		}
41591140Stanimura		if (!inferior(targp)) {
41691140Stanimura			PROC_UNLOCK(targp);
41791371Stanimura			error = ESRCH;
41894859Sjhb			goto done;
41991140Stanimura		}
420132568Srwatson		if ((error = p_cansee(td, targp))) {
42175893Sjhb			PROC_UNLOCK(targp);
42294859Sjhb			goto done;
42375893Sjhb		}
42475893Sjhb		if (targp->p_pgrp == NULL ||
42575893Sjhb		    targp->p_session != curp->p_session) {
42675893Sjhb			PROC_UNLOCK(targp);
42782749Sdillon			error = EPERM;
42894859Sjhb			goto done;
42975893Sjhb		}
43075893Sjhb		if (targp->p_flag & P_EXEC) {
43175893Sjhb			PROC_UNLOCK(targp);
43282749Sdillon			error = EACCES;
43394859Sjhb			goto done;
43475893Sjhb		}
43591140Stanimura		PROC_UNLOCK(targp);
43691140Stanimura	} else
4371541Srgrimes		targp = curp;
43875893Sjhb	if (SESS_LEADER(targp)) {
43982749Sdillon		error = EPERM;
44094859Sjhb		goto done;
44175893Sjhb	}
44287218Srwatson	if (uap->pgid == 0)
4431541Srgrimes		uap->pgid = targp->p_pid;
444117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
445117214Scognet		if (uap->pgid == targp->p_pid) {
446117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
447117214Scognet			    NULL);
448117214Scognet			if (error == 0)
449117214Scognet				newpgrp = NULL;
450117214Scognet		} else
451117214Scognet			error = EPERM;
45291140Stanimura	} else {
453117214Scognet		if (pgrp == targp->p_pgrp) {
454117214Scognet			PGRP_UNLOCK(pgrp);
45594859Sjhb			goto done;
45675893Sjhb		}
457117214Scognet		if (pgrp->pg_id != targp->p_pid &&
458117214Scognet		    pgrp->pg_session != curp->p_session) {
45991140Stanimura			PGRP_UNLOCK(pgrp);
460117214Scognet			error = EPERM;
46191140Stanimura			goto done;
46291140Stanimura		}
46391140Stanimura		PGRP_UNLOCK(pgrp);
46491140Stanimura		error = enterthispgrp(targp, pgrp);
46582749Sdillon	}
46691140Stanimuradone:
46794859Sjhb	sx_xunlock(&proctree_lock);
46894859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
46994859Sjhb	    ("setpgid failed and newpgrp is NULL"));
47095973Stanimura	if (newpgrp != NULL)
471184205Sdes		free(newpgrp, M_PGRP);
47282749Sdillon	return (error);
4731541Srgrimes}
4741541Srgrimes
47524448Speter/*
47624448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
47772093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47824448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
47924448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
48024448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
48124448Speter * does not set the saved id - this is dangerous for traditional BSD
48224448Speter * programs.  For this reason, we *really* do not want to set
48324448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
48424448Speter */
48524448Speter#define POSIX_APPENDIX_B_4_2_2
48624448Speter
48712221Sbde#ifndef _SYS_SYSPROTO_H_
4881541Srgrimesstruct setuid_args {
4891541Srgrimes	uid_t	uid;
4901541Srgrimes};
49112221Sbde#endif
4921541Srgrimes/* ARGSUSED */
4931549Srgrimesint
494225617Skmacysys_setuid(struct thread *td, struct setuid_args *uap)
4951541Srgrimes{
49683366Sjulian	struct proc *p = td->td_proc;
49777183Srwatson	struct ucred *newcred, *oldcred;
49877183Srwatson	uid_t uid;
49998417Salfred	struct uidinfo *uip;
50087218Srwatson	int error;
5011541Srgrimes
50277183Srwatson	uid = uap->uid;
503195104Srwatson	AUDIT_ARG_UID(uid);
50494619Sjhb	newcred = crget();
50598417Salfred	uip = uifind(uid);
50694619Sjhb	PROC_LOCK(p);
507194498Sbrooks	/*
508194498Sbrooks	 * Copy credentials so other references do not see our changes.
509194498Sbrooks	 */
510194498Sbrooks	oldcred = crcopysafe(p, newcred);
51187466Srwatson
512145147Srwatson#ifdef MAC
513189529Srwatson	error = mac_cred_check_setuid(oldcred, uid);
514145147Srwatson	if (error)
515145147Srwatson		goto fail;
516145147Srwatson#endif
517145147Srwatson
51824448Speter	/*
51924448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
52024448Speter	 *
52187218Srwatson	 * Note that setuid(geteuid()) is a special case of
52224448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52372093Sasmodai	 * to use this clause to be compatible with traditional BSD
52424448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
52524448Speter	 * three id's (assuming you have privs).
52624448Speter	 *
52724448Speter	 * Notes on the logic.  We do things in three steps.
52824448Speter	 * 1: We determine if the euid is going to change, and do EPERM
52924448Speter	 *    right away.  We unconditionally change the euid later if this
53024448Speter	 *    test is satisfied, simplifying that part of the logic.
53187218Srwatson	 * 2: We determine if the real and/or saved uids are going to
53224448Speter	 *    change.  Determined by compile options.
53324448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
53424448Speter	 */
53577183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
53617994Sache#ifdef _POSIX_SAVED_IDS
53777183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
53817994Sache#endif
53924448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
54077183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
54124448Speter#endif
542170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0)
543145147Srwatson		goto fail;
54424448Speter
54524448Speter#ifdef _POSIX_SAVED_IDS
5461541Srgrimes	/*
54724448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
54824448Speter	 * If so, we are changing the real uid and/or saved uid.
5491541Srgrimes	 */
55017994Sache	if (
55124448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
55277183Srwatson	    uid == oldcred->cr_uid ||
55317994Sache#endif
554164032Srwatson	    /* We are using privs. */
555170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0)
55617994Sache#endif
55724448Speter	{
55824448Speter		/*
55965495Struckman		 * Set the real uid and transfer proc count to new user.
56024448Speter		 */
56177183Srwatson		if (uid != oldcred->cr_ruid) {
56298417Salfred			change_ruid(newcred, uip);
56365495Struckman			setsugid(p);
56424448Speter		}
56524448Speter		/*
56624448Speter		 * Set saved uid
56724448Speter		 *
56824448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
56924448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
57024448Speter		 * is important that we should do this.
57124448Speter		 */
57277183Srwatson		if (uid != oldcred->cr_svuid) {
57377183Srwatson			change_svuid(newcred, uid);
57431891Ssef			setsugid(p);
57524448Speter		}
5768141Sache	}
57724448Speter
57824448Speter	/*
57924448Speter	 * In all permitted cases, we are changing the euid.
58024448Speter	 */
58177183Srwatson	if (uid != oldcred->cr_uid) {
58298417Salfred		change_euid(newcred, uip);
58331891Ssef		setsugid(p);
58424448Speter	}
585302229Sbdrewery	proc_set_cred(p, newcred);
58694619Sjhb	PROC_UNLOCK(p);
587220212Strasz#ifdef RACCT
588220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
589220212Strasz#endif
59098417Salfred	uifree(uip);
59177183Srwatson	crfree(oldcred);
59294619Sjhb	return (0);
593145147Srwatson
594145147Srwatsonfail:
595145147Srwatson	PROC_UNLOCK(p);
596145147Srwatson	uifree(uip);
597145147Srwatson	crfree(newcred);
598145147Srwatson	return (error);
5991541Srgrimes}
6001541Srgrimes
60112221Sbde#ifndef _SYS_SYSPROTO_H_
6021541Srgrimesstruct seteuid_args {
6031541Srgrimes	uid_t	euid;
6041541Srgrimes};
60512221Sbde#endif
6061541Srgrimes/* ARGSUSED */
6071549Srgrimesint
608225617Skmacysys_seteuid(struct thread *td, struct seteuid_args *uap)
6091541Srgrimes{
61083366Sjulian	struct proc *p = td->td_proc;
61177183Srwatson	struct ucred *newcred, *oldcred;
61277183Srwatson	uid_t euid;
61398417Salfred	struct uidinfo *euip;
61487218Srwatson	int error;
6151541Srgrimes
6161541Srgrimes	euid = uap->euid;
617195104Srwatson	AUDIT_ARG_EUID(euid);
61894619Sjhb	newcred = crget();
61998417Salfred	euip = uifind(euid);
62094619Sjhb	PROC_LOCK(p);
621194498Sbrooks	/*
622194498Sbrooks	 * Copy credentials so other references do not see our changes.
623194498Sbrooks	 */
624194498Sbrooks	oldcred = crcopysafe(p, newcred);
625145147Srwatson
626145147Srwatson#ifdef MAC
627189529Srwatson	error = mac_cred_check_seteuid(oldcred, euid);
628145147Srwatson	if (error)
629145147Srwatson		goto fail;
630145147Srwatson#endif
631145147Srwatson
63277183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
63377183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
634170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0)
635145147Srwatson		goto fail;
636145147Srwatson
6371541Srgrimes	/*
638194498Sbrooks	 * Everything's okay, do it.
6391541Srgrimes	 */
64077183Srwatson	if (oldcred->cr_uid != euid) {
64198417Salfred		change_euid(newcred, euip);
64231891Ssef		setsugid(p);
64324449Speter	}
644302229Sbdrewery	proc_set_cred(p, newcred);
64594619Sjhb	PROC_UNLOCK(p);
64698417Salfred	uifree(euip);
64777183Srwatson	crfree(oldcred);
64894619Sjhb	return (0);
649145147Srwatson
650145147Srwatsonfail:
651145147Srwatson	PROC_UNLOCK(p);
652145147Srwatson	uifree(euip);
653145147Srwatson	crfree(newcred);
654145147Srwatson	return (error);
6551541Srgrimes}
6561541Srgrimes
65712221Sbde#ifndef _SYS_SYSPROTO_H_
6581541Srgrimesstruct setgid_args {
6591541Srgrimes	gid_t	gid;
6601541Srgrimes};
66112221Sbde#endif
6621541Srgrimes/* ARGSUSED */
6631549Srgrimesint
664225617Skmacysys_setgid(struct thread *td, struct setgid_args *uap)
6651541Srgrimes{
66683366Sjulian	struct proc *p = td->td_proc;
66777183Srwatson	struct ucred *newcred, *oldcred;
66877183Srwatson	gid_t gid;
66987218Srwatson	int error;
6701541Srgrimes
67177183Srwatson	gid = uap->gid;
672195104Srwatson	AUDIT_ARG_GID(gid);
67394619Sjhb	newcred = crget();
67494619Sjhb	PROC_LOCK(p);
675194498Sbrooks	oldcred = crcopysafe(p, newcred);
67687466Srwatson
677145147Srwatson#ifdef MAC
678189529Srwatson	error = mac_cred_check_setgid(oldcred, gid);
679145147Srwatson	if (error)
680145147Srwatson		goto fail;
681145147Srwatson#endif
682145147Srwatson
68324448Speter	/*
68424448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
68524448Speter	 *
68624448Speter	 * Note that setgid(getegid()) is a special case of
68724448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
68872093Sasmodai	 * to use this clause to be compatible with traditional BSD
68924448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
69024448Speter	 * three id's (assuming you have privs).
69124448Speter	 *
69224448Speter	 * For notes on the logic here, see setuid() above.
69324448Speter	 */
69477183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
69517994Sache#ifdef _POSIX_SAVED_IDS
69677183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
69717994Sache#endif
69824448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
69977183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
70024448Speter#endif
701170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0)
702145147Srwatson		goto fail;
70324448Speter
70417994Sache#ifdef _POSIX_SAVED_IDS
70524448Speter	/*
70624448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
70724448Speter	 * If so, we are changing the real uid and saved gid.
70824448Speter	 */
70924448Speter	if (
71024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
71177183Srwatson	    gid == oldcred->cr_groups[0] ||
71217994Sache#endif
713164032Srwatson	    /* We are using privs. */
714170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0)
71524448Speter#endif
71624448Speter	{
71724448Speter		/*
71824448Speter		 * Set real gid
71924448Speter		 */
72077183Srwatson		if (oldcred->cr_rgid != gid) {
72177183Srwatson			change_rgid(newcred, gid);
72231891Ssef			setsugid(p);
72324448Speter		}
72424448Speter		/*
72524448Speter		 * Set saved gid
72624448Speter		 *
72724448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
72824448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
72924448Speter		 * is important that we should do this.
73024448Speter		 */
73177183Srwatson		if (oldcred->cr_svgid != gid) {
73277183Srwatson			change_svgid(newcred, gid);
73331891Ssef			setsugid(p);
73424448Speter		}
7358141Sache	}
73624448Speter	/*
73724448Speter	 * In all cases permitted cases, we are changing the egid.
73824448Speter	 * Copy credentials so other references do not see our changes.
73924448Speter	 */
74077183Srwatson	if (oldcred->cr_groups[0] != gid) {
74177183Srwatson		change_egid(newcred, gid);
74231891Ssef		setsugid(p);
74324448Speter	}
744302229Sbdrewery	proc_set_cred(p, newcred);
74594619Sjhb	PROC_UNLOCK(p);
74677183Srwatson	crfree(oldcred);
74794619Sjhb	return (0);
748145147Srwatson
749145147Srwatsonfail:
750145147Srwatson	PROC_UNLOCK(p);
751145147Srwatson	crfree(newcred);
752145147Srwatson	return (error);
7531541Srgrimes}
7541541Srgrimes
75512221Sbde#ifndef _SYS_SYSPROTO_H_
7561541Srgrimesstruct setegid_args {
7571541Srgrimes	gid_t	egid;
7581541Srgrimes};
75912221Sbde#endif
7601541Srgrimes/* ARGSUSED */
7611549Srgrimesint
762225617Skmacysys_setegid(struct thread *td, struct setegid_args *uap)
7631541Srgrimes{
76483366Sjulian	struct proc *p = td->td_proc;
76577183Srwatson	struct ucred *newcred, *oldcred;
76677183Srwatson	gid_t egid;
76787218Srwatson	int error;
7681541Srgrimes
7691541Srgrimes	egid = uap->egid;
770195104Srwatson	AUDIT_ARG_EGID(egid);
77194619Sjhb	newcred = crget();
77294619Sjhb	PROC_LOCK(p);
773194498Sbrooks	oldcred = crcopysafe(p, newcred);
774145147Srwatson
775145147Srwatson#ifdef MAC
776189529Srwatson	error = mac_cred_check_setegid(oldcred, egid);
777145147Srwatson	if (error)
778145147Srwatson		goto fail;
779145147Srwatson#endif
780145147Srwatson
78177183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
78277183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
783170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0)
784145147Srwatson		goto fail;
785145147Srwatson
78677183Srwatson	if (oldcred->cr_groups[0] != egid) {
78777183Srwatson		change_egid(newcred, egid);
78831891Ssef		setsugid(p);
78924449Speter	}
790302229Sbdrewery	proc_set_cred(p, newcred);
79194619Sjhb	PROC_UNLOCK(p);
79277183Srwatson	crfree(oldcred);
79394619Sjhb	return (0);
794145147Srwatson
795145147Srwatsonfail:
796145147Srwatson	PROC_UNLOCK(p);
797145147Srwatson	crfree(newcred);
798145147Srwatson	return (error);
7991541Srgrimes}
8001541Srgrimes
80112221Sbde#ifndef _SYS_SYSPROTO_H_
8021541Srgrimesstruct setgroups_args {
8031541Srgrimes	u_int	gidsetsize;
8041541Srgrimes	gid_t	*gidset;
8051541Srgrimes};
80612221Sbde#endif
8071541Srgrimes/* ARGSUSED */
8081549Srgrimesint
809225617Skmacysys_setgroups(struct thread *td, struct setgroups_args *uap)
8101541Srgrimes{
811194498Sbrooks	gid_t *groups = NULL;
812160139Sjhb	int error;
813160139Sjhb
814202143Sbrooks	if (uap->gidsetsize > ngroups_max + 1)
815160139Sjhb		return (EINVAL);
816194498Sbrooks	groups = malloc(uap->gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
817160139Sjhb	error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t));
818160139Sjhb	if (error)
819194498Sbrooks		goto out;
820194498Sbrooks	error = kern_setgroups(td, uap->gidsetsize, groups);
821194498Sbrooksout:
822194498Sbrooks	free(groups, M_TEMP);
823194498Sbrooks	return (error);
824160139Sjhb}
825160139Sjhb
826160139Sjhbint
827160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
828160139Sjhb{
82983366Sjulian	struct proc *p = td->td_proc;
830160139Sjhb	struct ucred *newcred, *oldcred;
8311541Srgrimes	int error;
8321541Srgrimes
833202143Sbrooks	if (ngrp > ngroups_max + 1)
83494619Sjhb		return (EINVAL);
835195104Srwatson	AUDIT_ARG_GROUPSET(groups, ngrp);
83694619Sjhb	newcred = crget();
837194498Sbrooks	crextend(newcred, ngrp);
83894619Sjhb	PROC_LOCK(p);
839194498Sbrooks	oldcred = crcopysafe(p, newcred);
840145147Srwatson
841145147Srwatson#ifdef MAC
842189529Srwatson	error = mac_cred_check_setgroups(oldcred, ngrp, groups);
843145147Srwatson	if (error)
844145147Srwatson		goto fail;
845145147Srwatson#endif
846145147Srwatson
847170587Srwatson	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0);
848145147Srwatson	if (error)
849145147Srwatson		goto fail;
850145147Srwatson
85124447Speter	if (ngrp < 1) {
85224447Speter		/*
85324447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
85424447Speter		 * groups vector on non-BSD systems (which generally do not
85524447Speter		 * have the egid in the groups[0]).  We risk security holes
85624447Speter		 * when running non-BSD software if we do not do the same.
85724447Speter		 */
85877183Srwatson		newcred->cr_ngroups = 1;
85924447Speter	} else {
860194498Sbrooks		crsetgroups_locked(newcred, ngrp, groups);
86124447Speter	}
86231891Ssef	setsugid(p);
863302229Sbdrewery	proc_set_cred(p, newcred);
86494619Sjhb	PROC_UNLOCK(p);
86577183Srwatson	crfree(oldcred);
86694619Sjhb	return (0);
867145147Srwatson
868145147Srwatsonfail:
869145147Srwatson	PROC_UNLOCK(p);
870145147Srwatson	crfree(newcred);
871145147Srwatson	return (error);
8721541Srgrimes}
8731541Srgrimes
87412221Sbde#ifndef _SYS_SYSPROTO_H_
8751541Srgrimesstruct setreuid_args {
8769238Sache	uid_t	ruid;
8779238Sache	uid_t	euid;
8781541Srgrimes};
87912221Sbde#endif
8801541Srgrimes/* ARGSUSED */
8811549Srgrimesint
882225617Skmacysys_setreuid(register struct thread *td, struct setreuid_args *uap)
8831541Srgrimes{
88483366Sjulian	struct proc *p = td->td_proc;
88577183Srwatson	struct ucred *newcred, *oldcred;
88687218Srwatson	uid_t euid, ruid;
88798417Salfred	struct uidinfo *euip, *ruip;
88887218Srwatson	int error;
8891541Srgrimes
89087218Srwatson	euid = uap->euid;
8919238Sache	ruid = uap->ruid;
892195104Srwatson	AUDIT_ARG_EUID(euid);
893195104Srwatson	AUDIT_ARG_RUID(ruid);
89494619Sjhb	newcred = crget();
89598417Salfred	euip = uifind(euid);
89698417Salfred	ruip = uifind(ruid);
89794619Sjhb	PROC_LOCK(p);
898194498Sbrooks	oldcred = crcopysafe(p, newcred);
899145147Srwatson
900145147Srwatson#ifdef MAC
901189529Srwatson	error = mac_cred_check_setreuid(oldcred, ruid, euid);
902145147Srwatson	if (error)
903145147Srwatson		goto fail;
904145147Srwatson#endif
905145147Srwatson
90677183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
90777183Srwatson	      ruid != oldcred->cr_svuid) ||
90877183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
90977183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
910170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0)
911145147Srwatson		goto fail;
912145147Srwatson
91377183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
91498417Salfred		change_euid(newcred, euip);
91531891Ssef		setsugid(p);
91624450Speter	}
91777183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
91898417Salfred		change_ruid(newcred, ruip);
91931891Ssef		setsugid(p);
9208135Sache	}
92177183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
92277183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
92377183Srwatson		change_svuid(newcred, newcred->cr_uid);
92431891Ssef		setsugid(p);
92524450Speter	}
926302229Sbdrewery	proc_set_cred(p, newcred);
92794619Sjhb	PROC_UNLOCK(p);
928220212Strasz#ifdef RACCT
929220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
930220212Strasz#endif
93198417Salfred	uifree(ruip);
93298417Salfred	uifree(euip);
93377183Srwatson	crfree(oldcred);
93494619Sjhb	return (0);
935145147Srwatson
936145147Srwatsonfail:
937145147Srwatson	PROC_UNLOCK(p);
938145147Srwatson	uifree(ruip);
939145147Srwatson	uifree(euip);
940145147Srwatson	crfree(newcred);
941145147Srwatson	return (error);
9421541Srgrimes}
9431541Srgrimes
94412221Sbde#ifndef _SYS_SYSPROTO_H_
9451541Srgrimesstruct setregid_args {
9469238Sache	gid_t	rgid;
9479238Sache	gid_t	egid;
9481541Srgrimes};
94912221Sbde#endif
9501541Srgrimes/* ARGSUSED */
9511549Srgrimesint
952225617Skmacysys_setregid(register struct thread *td, struct setregid_args *uap)
9531541Srgrimes{
95483366Sjulian	struct proc *p = td->td_proc;
95577183Srwatson	struct ucred *newcred, *oldcred;
95687218Srwatson	gid_t egid, rgid;
95787218Srwatson	int error;
9581541Srgrimes
95987218Srwatson	egid = uap->egid;
9609238Sache	rgid = uap->rgid;
961195104Srwatson	AUDIT_ARG_EGID(egid);
962195104Srwatson	AUDIT_ARG_RGID(rgid);
96394619Sjhb	newcred = crget();
96494619Sjhb	PROC_LOCK(p);
965194498Sbrooks	oldcred = crcopysafe(p, newcred);
966145147Srwatson
967145147Srwatson#ifdef MAC
968189529Srwatson	error = mac_cred_check_setregid(oldcred, rgid, egid);
969145147Srwatson	if (error)
970145147Srwatson		goto fail;
971145147Srwatson#endif
972145147Srwatson
97377183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
97477183Srwatson	    rgid != oldcred->cr_svgid) ||
97577183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
97677183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
977170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0)
978145147Srwatson		goto fail;
97994619Sjhb
98077183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
98177183Srwatson		change_egid(newcred, egid);
98231891Ssef		setsugid(p);
98324450Speter	}
98477183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
98577183Srwatson		change_rgid(newcred, rgid);
98631891Ssef		setsugid(p);
98724450Speter	}
98877183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
98977183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
99077183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
99131891Ssef		setsugid(p);
99224450Speter	}
993302229Sbdrewery	proc_set_cred(p, newcred);
99494619Sjhb	PROC_UNLOCK(p);
99577812Sru	crfree(oldcred);
99694619Sjhb	return (0);
997145147Srwatson
998145147Srwatsonfail:
999145147Srwatson	PROC_UNLOCK(p);
1000145147Srwatson	crfree(newcred);
1001145147Srwatson	return (error);
10021541Srgrimes}
10031541Srgrimes
100456115Speter/*
1005167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1006167232Srwatson * uid is explicit.
100756115Speter */
100824453Speter#ifndef _SYS_SYSPROTO_H_
100956115Speterstruct setresuid_args {
101056115Speter	uid_t	ruid;
101156115Speter	uid_t	euid;
101256115Speter	uid_t	suid;
101356115Speter};
101456115Speter#endif
101556115Speter/* ARGSUSED */
101656115Speterint
1017225617Skmacysys_setresuid(register struct thread *td, struct setresuid_args *uap)
101856115Speter{
101983366Sjulian	struct proc *p = td->td_proc;
102077183Srwatson	struct ucred *newcred, *oldcred;
102187218Srwatson	uid_t euid, ruid, suid;
102298417Salfred	struct uidinfo *euip, *ruip;
102356115Speter	int error;
102456115Speter
102587218Srwatson	euid = uap->euid;
102656115Speter	ruid = uap->ruid;
102756115Speter	suid = uap->suid;
1028195104Srwatson	AUDIT_ARG_EUID(euid);
1029195104Srwatson	AUDIT_ARG_RUID(ruid);
1030195104Srwatson	AUDIT_ARG_SUID(suid);
103194619Sjhb	newcred = crget();
103298417Salfred	euip = uifind(euid);
103398417Salfred	ruip = uifind(ruid);
103494619Sjhb	PROC_LOCK(p);
1035194498Sbrooks	oldcred = crcopysafe(p, newcred);
1036145147Srwatson
1037145147Srwatson#ifdef MAC
1038189529Srwatson	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1039145147Srwatson	if (error)
1040145147Srwatson		goto fail;
1041145147Srwatson#endif
1042145147Srwatson
104377183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
104477183Srwatson	     ruid != oldcred->cr_svuid &&
104577183Srwatson	      ruid != oldcred->cr_uid) ||
104677183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
104777183Srwatson	    euid != oldcred->cr_svuid &&
104877183Srwatson	      euid != oldcred->cr_uid) ||
104977183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
105077183Srwatson	    suid != oldcred->cr_svuid &&
105177183Srwatson	      suid != oldcred->cr_uid)) &&
1052170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0)
1053145147Srwatson		goto fail;
105494619Sjhb
105577183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
105698417Salfred		change_euid(newcred, euip);
105756115Speter		setsugid(p);
105856115Speter	}
105977183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
106098417Salfred		change_ruid(newcred, ruip);
106156115Speter		setsugid(p);
106256115Speter	}
106377183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
106477183Srwatson		change_svuid(newcred, suid);
106556115Speter		setsugid(p);
106656115Speter	}
1067302229Sbdrewery	proc_set_cred(p, newcred);
106894619Sjhb	PROC_UNLOCK(p);
1069220212Strasz#ifdef RACCT
1070220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
1071220212Strasz#endif
107298417Salfred	uifree(ruip);
107398417Salfred	uifree(euip);
107477183Srwatson	crfree(oldcred);
107594619Sjhb	return (0);
1076145147Srwatson
1077145147Srwatsonfail:
1078145147Srwatson	PROC_UNLOCK(p);
1079145147Srwatson	uifree(ruip);
1080145147Srwatson	uifree(euip);
1081145147Srwatson	crfree(newcred);
1082145147Srwatson	return (error);
1083145147Srwatson
108456115Speter}
108556115Speter
108656115Speter/*
1087167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1088167232Srwatson * gid is explicit.
108956115Speter */
109056115Speter#ifndef _SYS_SYSPROTO_H_
109156115Speterstruct setresgid_args {
109256115Speter	gid_t	rgid;
109356115Speter	gid_t	egid;
109456115Speter	gid_t	sgid;
109556115Speter};
109656115Speter#endif
109756115Speter/* ARGSUSED */
109856115Speterint
1099225617Skmacysys_setresgid(register struct thread *td, struct setresgid_args *uap)
110056115Speter{
110183366Sjulian	struct proc *p = td->td_proc;
110277183Srwatson	struct ucred *newcred, *oldcred;
110387218Srwatson	gid_t egid, rgid, sgid;
110456115Speter	int error;
110556115Speter
110687218Srwatson	egid = uap->egid;
110756115Speter	rgid = uap->rgid;
110856115Speter	sgid = uap->sgid;
1109195104Srwatson	AUDIT_ARG_EGID(egid);
1110195104Srwatson	AUDIT_ARG_RGID(rgid);
1111195104Srwatson	AUDIT_ARG_SGID(sgid);
111294619Sjhb	newcred = crget();
111394619Sjhb	PROC_LOCK(p);
1114194498Sbrooks	oldcred = crcopysafe(p, newcred);
1115145147Srwatson
1116145147Srwatson#ifdef MAC
1117189529Srwatson	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1118145147Srwatson	if (error)
1119145147Srwatson		goto fail;
1120145147Srwatson#endif
1121145147Srwatson
112277183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
112377183Srwatson	      rgid != oldcred->cr_svgid &&
112477183Srwatson	      rgid != oldcred->cr_groups[0]) ||
112577183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
112677183Srwatson	      egid != oldcred->cr_svgid &&
112777183Srwatson	      egid != oldcred->cr_groups[0]) ||
112877183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
112977183Srwatson	      sgid != oldcred->cr_svgid &&
113077183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1131170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0)
1132145147Srwatson		goto fail;
113394619Sjhb
113477183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
113577183Srwatson		change_egid(newcred, egid);
113656115Speter		setsugid(p);
113756115Speter	}
113877183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
113977183Srwatson		change_rgid(newcred, rgid);
114056115Speter		setsugid(p);
114156115Speter	}
114277183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
114377183Srwatson		change_svgid(newcred, sgid);
114456115Speter		setsugid(p);
114556115Speter	}
1146302229Sbdrewery	proc_set_cred(p, newcred);
114794619Sjhb	PROC_UNLOCK(p);
114877183Srwatson	crfree(oldcred);
114994619Sjhb	return (0);
1150145147Srwatson
1151145147Srwatsonfail:
1152145147Srwatson	PROC_UNLOCK(p);
1153145147Srwatson	crfree(newcred);
1154145147Srwatson	return (error);
115556115Speter}
115656115Speter
115756115Speter#ifndef _SYS_SYSPROTO_H_
115856115Speterstruct getresuid_args {
115956115Speter	uid_t	*ruid;
116056115Speter	uid_t	*euid;
116156115Speter	uid_t	*suid;
116256115Speter};
116356115Speter#endif
116456115Speter/* ARGSUSED */
116556115Speterint
1166225617Skmacysys_getresuid(register struct thread *td, struct getresuid_args *uap)
116756115Speter{
116882749Sdillon	struct ucred *cred;
116956115Speter	int error1 = 0, error2 = 0, error3 = 0;
117056115Speter
117193264Sdillon	cred = td->td_ucred;
117256115Speter	if (uap->ruid)
117399009Salfred		error1 = copyout(&cred->cr_ruid,
117499009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
117556115Speter	if (uap->euid)
117699009Salfred		error2 = copyout(&cred->cr_uid,
117799009Salfred		    uap->euid, sizeof(cred->cr_uid));
117856115Speter	if (uap->suid)
117999009Salfred		error3 = copyout(&cred->cr_svuid,
118099009Salfred		    uap->suid, sizeof(cred->cr_svuid));
118187218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
118256115Speter}
118356115Speter
118456115Speter#ifndef _SYS_SYSPROTO_H_
118556115Speterstruct getresgid_args {
118656115Speter	gid_t	*rgid;
118756115Speter	gid_t	*egid;
118856115Speter	gid_t	*sgid;
118956115Speter};
119056115Speter#endif
119156115Speter/* ARGSUSED */
119256115Speterint
1193225617Skmacysys_getresgid(register struct thread *td, struct getresgid_args *uap)
119456115Speter{
119582749Sdillon	struct ucred *cred;
119656115Speter	int error1 = 0, error2 = 0, error3 = 0;
119756115Speter
119893264Sdillon	cred = td->td_ucred;
119956115Speter	if (uap->rgid)
120099009Salfred		error1 = copyout(&cred->cr_rgid,
120199009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
120256115Speter	if (uap->egid)
120399009Salfred		error2 = copyout(&cred->cr_groups[0],
120499009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
120556115Speter	if (uap->sgid)
120699009Salfred		error3 = copyout(&cred->cr_svgid,
120799009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
120887218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
120956115Speter}
121056115Speter
121156115Speter#ifndef _SYS_SYSPROTO_H_
121224453Speterstruct issetugid_args {
121324453Speter	int dummy;
121424453Speter};
121524453Speter#endif
121624453Speter/* ARGSUSED */
121724453Speterint
1218225617Skmacysys_issetugid(register struct thread *td, struct issetugid_args *uap)
121924453Speter{
122083366Sjulian	struct proc *p = td->td_proc;
122183366Sjulian
122224453Speter	/*
122324453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
122424453Speter	 * we use P_SUGID because we consider changing the owners as
122524453Speter	 * "tainting" as well.
122624453Speter	 * This is significant for procs that start as root and "become"
122724453Speter	 * a user without an exec - programs cannot know *everything*
122824453Speter	 * that libc *might* have put in their data segment.
122924453Speter	 */
123091140Stanimura	PROC_LOCK(p);
123183366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
123291140Stanimura	PROC_UNLOCK(p);
123324453Speter	return (0);
123424453Speter}
123524453Speter
123675426Srwatsonint
1237225617Skmacysys___setugid(struct thread *td, struct __setugid_args *uap)
123875426Srwatson{
123982749Sdillon#ifdef REGRESSION
124094619Sjhb	struct proc *p;
124175426Srwatson
124294619Sjhb	p = td->td_proc;
124375426Srwatson	switch (uap->flag) {
124475426Srwatson	case 0:
124594619Sjhb		PROC_LOCK(p);
124694619Sjhb		p->p_flag &= ~P_SUGID;
124794619Sjhb		PROC_UNLOCK(p);
124894619Sjhb		return (0);
124975426Srwatson	case 1:
125094619Sjhb		PROC_LOCK(p);
125194619Sjhb		p->p_flag |= P_SUGID;
125294619Sjhb		PROC_UNLOCK(p);
125394619Sjhb		return (0);
125475426Srwatson	default:
125594619Sjhb		return (EINVAL);
125675426Srwatson	}
125775426Srwatson#else /* !REGRESSION */
125887218Srwatson
125975426Srwatson	return (ENOSYS);
126087218Srwatson#endif /* REGRESSION */
126175426Srwatson}
126275426Srwatson
12631541Srgrimes/*
12641541Srgrimes * Check if gid is a member of the group set.
12651541Srgrimes */
12661549Srgrimesint
126793580Sjhbgroupmember(gid_t gid, struct ucred *cred)
12681541Srgrimes{
1269194556Sbrooks	int l;
1270194556Sbrooks	int h;
1271194556Sbrooks	int m;
12721541Srgrimes
1273194556Sbrooks	if (cred->cr_groups[0] == gid)
1274194556Sbrooks		return(1);
1275194556Sbrooks
1276194556Sbrooks	/*
1277194556Sbrooks	 * If gid was not our primary group, perform a binary search
1278194556Sbrooks	 * of the supplemental groups.  This is possible because we
1279194556Sbrooks	 * sort the groups in crsetgroups().
1280194556Sbrooks	 */
1281194556Sbrooks	l = 1;
1282194556Sbrooks	h = cred->cr_ngroups;
1283194556Sbrooks	while (l < h) {
1284194556Sbrooks		m = l + ((h - l) / 2);
1285194556Sbrooks		if (cred->cr_groups[m] < gid)
1286194556Sbrooks			l = m + 1;
1287194556Sbrooks		else
1288194556Sbrooks			h = m;
1289194556Sbrooks	}
1290194556Sbrooks	if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid))
1291194556Sbrooks		return (1);
1292194556Sbrooks
12931541Srgrimes	return (0);
12941541Srgrimes}
12951541Srgrimes
129682424Srwatson/*
129787218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
129887218Srwatson * implements (securelevel > level).  securelevel_ge() implements
129987218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
130087218Srwatson * functions return EPERM on "success" and 0 on "failure".
130183639Srwatson *
1302192895Sjamie * Due to care taken when setting the securelevel, we know that no jail will
1303192895Sjamie * be less secure that its parent (or the physical system), so it is sufficient
1304192895Sjamie * to test the current jail only.
1305192895Sjamie *
1306164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to
1307164032Srwatson * kern_priv.c.
130883639Srwatson */
130983639Srwatsonint
131083639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
131183639Srwatson{
131283639Srwatson
1313192895Sjamie	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
131483639Srwatson}
131583639Srwatson
131683639Srwatsonint
131783639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
131883639Srwatson{
131983639Srwatson
1320192895Sjamie	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
132183639Srwatson}
132283639Srwatson
132384736Srwatson/*
132487144Srwatson * 'see_other_uids' determines whether or not visibility of processes
132587218Srwatson * and sockets with credentials holding different real uids is possible
132687138Srwatson * using a variety of system MIBs.
132787218Srwatson * XXX: data declarations should be together near the beginning of the file.
132884736Srwatson */
132987144Srwatsonstatic int	see_other_uids = 1;
133089414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
133187218Srwatson    &see_other_uids, 0,
133284736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
133384736Srwatson
1334210226Strasz/*-
133592923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
133692923Srwatson * 'see_other_uids' policy.
133792923Srwatson * Returns: 0 for permitted, ESRCH otherwise
133892923Srwatson * Locks: none
133992923Srwatson * References: *u1 and *u2 must not change during the call
134092923Srwatson *             u1 may equal u2, in which case only one reference is required
134192923Srwatson */
134292923Srwatsonstatic int
134392923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
134492923Srwatson{
134592923Srwatson
134692923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1347170587Srwatson		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0)
134892923Srwatson			return (ESRCH);
134992923Srwatson	}
135092923Srwatson	return (0);
135192923Srwatson}
135292923Srwatson
1353122869Srwatson/*
1354122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1355122869Srwatson * and sockets with credentials holding different real gids is possible
1356122869Srwatson * using a variety of system MIBs.
1357122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1358122869Srwatson */
1359122869Srwatsonstatic int	see_other_gids = 1;
1360122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1361122869Srwatson    &see_other_gids, 0,
1362122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1363122869Srwatson
1364122869Srwatson/*
1365122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1366122869Srwatson * 'see_other_gids' policy.
1367122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1368122869Srwatson * Locks: none
1369122869Srwatson * References: *u1 and *u2 must not change during the call
1370122869Srwatson *             u1 may equal u2, in which case only one reference is required
1371122869Srwatson */
1372122869Srwatsonstatic int
1373122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1374122869Srwatson{
1375122869Srwatson	int i, match;
1376122869Srwatson
1377122869Srwatson	if (!see_other_gids) {
1378122869Srwatson		match = 0;
1379122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1380122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1381122869Srwatson				match = 1;
1382122869Srwatson			if (match)
1383122869Srwatson				break;
1384122869Srwatson		}
1385122869Srwatson		if (!match) {
1386170587Srwatson			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0)
1387122869Srwatson				return (ESRCH);
1388122869Srwatson		}
1389122869Srwatson	}
1390122869Srwatson	return (0);
1391122869Srwatson}
1392122869Srwatson
1393210226Strasz/*-
139482466Srwatson * Determine if u1 "can see" the subject specified by u2.
139574956Srwatson * Returns: 0 for permitted, an errno value otherwise
139674956Srwatson * Locks: none
139787218Srwatson * References: *u1 and *u2 must not change during the call
139874956Srwatson *             u1 may equal u2, in which case only one reference is required
139974956Srwatson */
140074956Srwatsonint
140183742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
140265237Srwatson{
140372786Srwatson	int error;
140453518Sphk
140574956Srwatson	if ((error = prison_check(u1, u2)))
140672786Srwatson		return (error);
1407101003Srwatson#ifdef MAC
1408172930Srwatson	if ((error = mac_cred_check_visible(u1, u2)))
1409101003Srwatson		return (error);
1410101003Srwatson#endif
141192923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
141292923Srwatson		return (error);
1413122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1414122869Srwatson		return (error);
141565237Srwatson	return (0);
141665237Srwatson}
141765237Srwatson
1418210226Strasz/*-
141996886Sjhb * Determine if td "can see" the subject specified by p.
142082424Srwatson * Returns: 0 for permitted, an errno value otherwise
142196886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
142296886Sjhb *        should be curthread.
142396886Sjhb * References: td and p must be valid for the lifetime of the call
142482424Srwatson */
142579335Srwatsonint
142696886Sjhbp_cansee(struct thread *td, struct proc *p)
142774956Srwatson{
142874956Srwatson
142983742Srwatson	/* Wrap cr_cansee() for all functionality. */
143096886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
143196886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
143296886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
143374956Srwatson}
143474956Srwatson
1435120052Srwatson/*
1436120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1437120052Srwatson * signals by unprivileged processes to processes that have changed their
1438120052Srwatson * credentials since the last invocation of execve().  This can prevent
1439120052Srwatson * the leakage of cached information or retained privileges as a result
1440120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1441120052Srwatson * may interfere with some applications that expect to be able to
1442120052Srwatson * deliver these signals to peer processes after having given up
1443120052Srwatson * privilege.
1444120052Srwatson */
1445120052Srwatsonstatic int	conservative_signals = 1;
1446120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1447120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1448120052Srwatson    "sending certain signals to processes whose credentials have changed");
1449210226Strasz/*-
145088943Srwatson * Determine whether cred may deliver the specified signal to proc.
145188943Srwatson * Returns: 0 for permitted, an errno value otherwise.
145288943Srwatson * Locks: A lock must be held for proc.
145388943Srwatson * References: cred and proc must be valid for the lifetime of the call.
145475437Srwatson */
145575437Srwatsonint
1456141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum)
145753518Sphk{
145882466Srwatson	int error;
145984826Sjhb
146096886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
146175437Srwatson	/*
146288943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
146388943Srwatson	 * same jail as cred, if cred is in jail.
146475437Srwatson	 */
146588943Srwatson	error = prison_check(cred, proc->p_ucred);
146688943Srwatson	if (error)
146772786Srwatson		return (error);
1468101003Srwatson#ifdef MAC
1469172930Srwatson	if ((error = mac_proc_check_signal(cred, proc, signum)))
1470101003Srwatson		return (error);
1471101003Srwatson#endif
1472122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
147392923Srwatson		return (error);
1474122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1475122869Srwatson		return (error);
147665237Srwatson
147765237Srwatson	/*
147882424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
147982424Srwatson	 * bit on the target process.  If the bit is set, then additional
148082424Srwatson	 * restrictions are placed on the set of available signals.
148175437Srwatson	 */
1482141815Ssobomax	if (conservative_signals && (proc->p_flag & P_SUGID)) {
148375437Srwatson		switch (signum) {
148475437Srwatson		case 0:
148575437Srwatson		case SIGKILL:
148675437Srwatson		case SIGINT:
148775437Srwatson		case SIGTERM:
1488120052Srwatson		case SIGALRM:
148975437Srwatson		case SIGSTOP:
149075437Srwatson		case SIGTTIN:
149175437Srwatson		case SIGTTOU:
149275437Srwatson		case SIGTSTP:
149375437Srwatson		case SIGHUP:
149475437Srwatson		case SIGUSR1:
149575437Srwatson		case SIGUSR2:
149682466Srwatson			/*
149782466Srwatson			 * Generally, permit job and terminal control
149882466Srwatson			 * signals.
149982466Srwatson			 */
150075437Srwatson			break;
150175437Srwatson		default:
150288943Srwatson			/* Not permitted without privilege. */
1503170587Srwatson			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0);
150475437Srwatson			if (error)
150575437Srwatson				return (error);
150675437Srwatson		}
150765237Srwatson	}
150865237Srwatson
150975480Srwatson	/*
151082424Srwatson	 * Generally, the target credential's ruid or svuid must match the
151175480Srwatson	 * subject credential's ruid or euid.
151275480Srwatson	 */
151388943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
151488943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
151588943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
151688943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1517170587Srwatson		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0);
151875480Srwatson		if (error)
151975480Srwatson			return (error);
152075480Srwatson	}
152175480Srwatson
152287218Srwatson	return (0);
152353518Sphk}
152453518Sphk
1525210226Strasz/*-
152696886Sjhb * Determine whether td may deliver the specified signal to p.
152788943Srwatson * Returns: 0 for permitted, an errno value otherwise
152896886Sjhb * Locks: Sufficient locks to protect various components of td and p
152996886Sjhb *        must be held.  td must be curthread, and a lock must be
153096886Sjhb *        held for p.
153196886Sjhb * References: td and p must be valid for the lifetime of the call
153288943Srwatson */
153388943Srwatsonint
1534141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum)
153588943Srwatson{
153688943Srwatson
153796886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
153896886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
153996886Sjhb	if (td->td_proc == p)
154088943Srwatson		return (0);
154188943Srwatson
154288943Srwatson	/*
154388943Srwatson	 * UNIX signalling semantics require that processes in the same
154488943Srwatson	 * session always be able to deliver SIGCONT to one another,
154588943Srwatson	 * overriding the remaining protections.
154688943Srwatson	 */
154796886Sjhb	/* XXX: This will require an additional lock of some sort. */
154896886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
154988943Srwatson		return (0);
1550143108Ssobomax	/*
1551143800Ssobomax	 * Some compat layers use SIGTHR and higher signals for
1552143800Ssobomax	 * communication between different kernel threads of the same
1553143800Ssobomax	 * process, so that they expect that it's always possible to
1554143800Ssobomax	 * deliver them, even for suid applications where cr_cansignal() can
1555143108Ssobomax	 * deny such ability for security consideration.  It should be
1556143108Ssobomax	 * pretty safe to do since the only way to create two processes
1557143108Ssobomax	 * with the same p_leader is via rfork(2).
1558143108Ssobomax	 */
1559143805Ssobomax	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
1560143805Ssobomax	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
1561143108Ssobomax		return (0);
156288943Srwatson
1563141815Ssobomax	return (cr_cansignal(td->td_ucred, p, signum));
156488943Srwatson}
156588943Srwatson
1566210226Strasz/*-
156796886Sjhb * Determine whether td may reschedule p.
156882466Srwatson * Returns: 0 for permitted, an errno value otherwise
156996886Sjhb * Locks: Sufficient locks to protect various components of td and p
157096886Sjhb *        must be held.  td must be curthread, and a lock must
157196886Sjhb *        be held for p.
157296886Sjhb * References: td and p must be valid for the lifetime of the call
157382424Srwatson */
157479335Srwatsonint
157596886Sjhbp_cansched(struct thread *td, struct proc *p)
157665237Srwatson{
157772786Srwatson	int error;
157865237Srwatson
157996886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
158096886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
158196886Sjhb	if (td->td_proc == p)
158265237Srwatson		return (0);
158396886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
158472786Srwatson		return (error);
1585101003Srwatson#ifdef MAC
1586172930Srwatson	if ((error = mac_proc_check_sched(td->td_ucred, p)))
1587101003Srwatson		return (error);
1588101003Srwatson#endif
158996886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
159092923Srwatson		return (error);
1591122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1592122869Srwatson		return (error);
1593164032Srwatson	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1594164032Srwatson	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
1595170587Srwatson		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1596164032Srwatson		if (error)
1597164032Srwatson			return (error);
1598164032Srwatson	}
1599164032Srwatson	return (0);
160065237Srwatson}
160165237Srwatson
160282424Srwatson/*
160387280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
160487280Srwatson * unprivileged inter-process debugging services, including some procfs
160587280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
160687280Srwatson * debugging has been involved in a variety of security problems, and sites
160787280Srwatson * not requiring the service might choose to disable it when hardening
160887280Srwatson * systems.
160982424Srwatson *
161082424Srwatson * XXX: Should modifying and reading this variable require locking?
161187218Srwatson * XXX: data declarations should be together near the beginning of the file.
161282424Srwatson */
161387144Srwatsonstatic int	unprivileged_proc_debug = 1;
161489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
161587218Srwatson    &unprivileged_proc_debug, 0,
161680735Srwatson    "Unprivileged processes may use process debugging facilities");
161780735Srwatson
1618210226Strasz/*-
161996886Sjhb * Determine whether td may debug p.
162082466Srwatson * Returns: 0 for permitted, an errno value otherwise
162196886Sjhb * Locks: Sufficient locks to protect various components of td and p
162296886Sjhb *        must be held.  td must be curthread, and a lock must
162396886Sjhb *        be held for p.
162496886Sjhb * References: td and p must be valid for the lifetime of the call
162582424Srwatson */
162679335Srwatsonint
162796886Sjhbp_candebug(struct thread *td, struct proc *p)
162865237Srwatson{
162987218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
163065237Srwatson
163196886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
163296886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
163387144Srwatson	if (!unprivileged_proc_debug) {
1634170587Srwatson		error = priv_check(td, PRIV_DEBUG_UNPRIV);
163584727Srwatson		if (error)
163684727Srwatson			return (error);
163784727Srwatson	}
163896886Sjhb	if (td->td_proc == p)
163984636Sdes		return (0);
164096886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
164172786Srwatson		return (error);
1642101003Srwatson#ifdef MAC
1643172930Srwatson	if ((error = mac_proc_check_debug(td->td_ucred, p)))
1644101003Srwatson		return (error);
1645101003Srwatson#endif
164696886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
164792923Srwatson		return (error);
1648122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1649122869Srwatson		return (error);
165065237Srwatson
165182466Srwatson	/*
165296886Sjhb	 * Is p's group set a subset of td's effective group set?  This
165396886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
165482466Srwatson	 */
165585895Srwatson	grpsubset = 1;
165696886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
165796886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
165885895Srwatson			grpsubset = 0;
165985895Srwatson			break;
166085895Srwatson		}
166185895Srwatson	}
166285895Srwatson	grpsubset = grpsubset &&
166396886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
166496886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
166585895Srwatson
166685895Srwatson	/*
166796886Sjhb	 * Are the uids present in p's credential equal to td's
166896886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
166985895Srwatson	 */
167096886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
167196886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
167296886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
167385895Srwatson
167485895Srwatson	/*
167585895Srwatson	 * Has the credential of the process changed since the last exec()?
167685895Srwatson	 */
167796886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
167885895Srwatson
167985895Srwatson	/*
168096886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
168185895Srwatson	 * or the credential has changed, require appropriate privilege
1682164032Srwatson	 * for td to debug p.
168385895Srwatson	 */
1684164032Srwatson	if (!grpsubset || !uidsubset) {
1685170587Srwatson		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
168684727Srwatson		if (error)
168765237Srwatson			return (error);
168882466Srwatson	}
168965237Srwatson
1690164032Srwatson	if (credentialchanged) {
1691170587Srwatson		error = priv_check(td, PRIV_DEBUG_SUGID);
1692164032Srwatson		if (error)
1693164032Srwatson			return (error);
1694164032Srwatson	}
1695164032Srwatson
169687218Srwatson	/* Can't trace init when securelevel > 0. */
169796886Sjhb	if (p == initproc) {
169896886Sjhb		error = securelevel_gt(td->td_ucred, 0);
169983639Srwatson		if (error)
170083639Srwatson			return (error);
170183639Srwatson	}
170265237Srwatson
170385880Srwatson	/*
170485880Srwatson	 * Can't trace a process that's currently exec'ing.
1705164032Srwatson	 *
170685880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
170785880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
170885880Srwatson	 * should be moved to the caller's of p_candebug().
170985880Srwatson	 */
171096886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
1711185983Skib		return (EBUSY);
171287466Srwatson
1713277698Skib	/* Denied explicitely */
1714277698Skib	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1715277698Skib		error = priv_check(td, PRIV_DEBUG_DENIED);
1716277698Skib		if (error != 0)
1717277698Skib			return (error);
1718277698Skib	}
1719277698Skib
172065237Srwatson	return (0);
172165237Srwatson}
172265237Srwatson
1723210226Strasz/*-
172492976Srwatson * Determine whether the subject represented by cred can "see" a socket.
172592976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
172692976Srwatson */
172792976Srwatsonint
172892976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
172992976Srwatson{
173092976Srwatson	int error;
173192976Srwatson
173292976Srwatson	error = prison_check(cred, so->so_cred);
173392976Srwatson	if (error)
173492976Srwatson		return (ENOENT);
1735101003Srwatson#ifdef MAC
1736172930Srwatson	error = mac_socket_check_visible(cred, so);
1737101003Srwatson	if (error)
1738101003Srwatson		return (error);
1739101003Srwatson#endif
174092976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
174192976Srwatson		return (ENOENT);
1742122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1743122869Srwatson		return (ENOENT);
174492976Srwatson
174592976Srwatson	return (0);
174692976Srwatson}
174792976Srwatson
1748183982Sbz#if defined(INET) || defined(INET6)
1749210226Strasz/*-
1750183982Sbz * Determine whether the subject represented by cred can "see" a socket.
1751183982Sbz * Returns: 0 for permitted, ENOENT otherwise.
1752183982Sbz */
1753183982Sbzint
1754183982Sbzcr_canseeinpcb(struct ucred *cred, struct inpcb *inp)
1755183982Sbz{
1756183982Sbz	int error;
1757183982Sbz
1758183982Sbz	error = prison_check(cred, inp->inp_cred);
1759183982Sbz	if (error)
1760183982Sbz		return (ENOENT);
1761183982Sbz#ifdef MAC
1762183982Sbz	INP_LOCK_ASSERT(inp);
1763183982Sbz	error = mac_inpcb_check_visible(cred, inp);
1764183982Sbz	if (error)
1765183982Sbz		return (error);
1766183982Sbz#endif
1767183982Sbz	if (cr_seeotheruids(cred, inp->inp_cred))
1768183982Sbz		return (ENOENT);
1769183982Sbz	if (cr_seeothergids(cred, inp->inp_cred))
1770183982Sbz		return (ENOENT);
1771183982Sbz
1772183982Sbz	return (0);
1773183982Sbz}
1774183982Sbz#endif
1775183982Sbz
1776210226Strasz/*-
1777145234Srwatson * Determine whether td can wait for the exit of p.
1778145234Srwatson * Returns: 0 for permitted, an errno value otherwise
1779145234Srwatson * Locks: Sufficient locks to protect various components of td and p
1780145234Srwatson *        must be held.  td must be curthread, and a lock must
1781145234Srwatson *        be held for p.
1782145234Srwatson * References: td and p must be valid for the lifetime of the call
1783145234Srwatson
1784145234Srwatson */
1785145234Srwatsonint
1786145234Srwatsonp_canwait(struct thread *td, struct proc *p)
1787145234Srwatson{
1788145234Srwatson	int error;
1789145234Srwatson
1790145234Srwatson	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1791145234Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
1792195741Sjamie	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1793145234Srwatson		return (error);
1794145234Srwatson#ifdef MAC
1795172930Srwatson	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1796145234Srwatson		return (error);
1797145234Srwatson#endif
1798145234Srwatson#if 0
1799145234Srwatson	/* XXXMAC: This could have odd effects on some shells. */
1800145234Srwatson	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
1801145234Srwatson		return (error);
1802145234Srwatson#endif
1803145234Srwatson
1804145234Srwatson	return (0);
1805145234Srwatson}
1806145234Srwatson
180753518Sphk/*
18081541Srgrimes * Allocate a zeroed cred structure.
18091541Srgrimes */
18101541Srgrimesstruct ucred *
181193580Sjhbcrget(void)
18121541Srgrimes{
18131541Srgrimes	register struct ucred *cr;
18141541Srgrimes
1815184205Sdes	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1816150634Sjhb	refcount_init(&cr->cr_ref, 1);
1817170407Srwatson#ifdef AUDIT
1818170407Srwatson	audit_cred_init(cr);
1819170407Srwatson#endif
1820101001Srwatson#ifdef MAC
1821172930Srwatson	mac_cred_init(cr);
1822101001Srwatson#endif
1823194498Sbrooks	crextend(cr, XU_NGROUPS);
18241541Srgrimes	return (cr);
18251541Srgrimes}
18261541Srgrimes
18271541Srgrimes/*
182882466Srwatson * Claim another reference to a ucred structure.
182969401Salfred */
183084827Sjhbstruct ucred *
183193580Sjhbcrhold(struct ucred *cr)
183269401Salfred{
183369401Salfred
1834150634Sjhb	refcount_acquire(&cr->cr_ref);
183584827Sjhb	return (cr);
183669401Salfred}
183769401Salfred
183869401Salfred/*
1839167211Srwatson * Free a cred structure.  Throws away space when ref count gets to 0.
18401541Srgrimes */
18411549Srgrimesvoid
184293580Sjhbcrfree(struct ucred *cr)
18431541Srgrimes{
184469239Salfred
184575632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1846150634Sjhb	KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred"));
1847150634Sjhb	if (refcount_release(&cr->cr_ref)) {
184865495Struckman		/*
184965495Struckman		 * Some callers of crget(), such as nfs_statfs(),
185065495Struckman		 * allocate a temporary credential, but don't
185165495Struckman		 * allocate a uidinfo structure.
185265495Struckman		 */
185365495Struckman		if (cr->cr_uidinfo != NULL)
185465495Struckman			uifree(cr->cr_uidinfo);
185577277Srwatson		if (cr->cr_ruidinfo != NULL)
185677277Srwatson			uifree(cr->cr_ruidinfo);
185772786Srwatson		/*
185872786Srwatson		 * Free a prison, if any.
185972786Srwatson		 */
1860192895Sjamie		if (cr->cr_prison != NULL)
186172786Srwatson			prison_free(cr->cr_prison);
1862219304Strasz		if (cr->cr_loginclass != NULL)
1863219304Strasz			loginclass_free(cr->cr_loginclass);
1864170407Srwatson#ifdef AUDIT
1865170407Srwatson		audit_cred_destroy(cr);
1866170407Srwatson#endif
1867101001Srwatson#ifdef MAC
1868172930Srwatson		mac_cred_destroy(cr);
1869101001Srwatson#endif
1870194498Sbrooks		free(cr->cr_groups, M_CRED);
1871184205Sdes		free(cr, M_CRED);
187290756Sdillon	}
18731541Srgrimes}
18741541Srgrimes
18751541Srgrimes/*
187684827Sjhb * Check to see if this ucred is shared.
18771541Srgrimes */
187884827Sjhbint
187993580Sjhbcrshared(struct ucred *cr)
18801541Srgrimes{
18811541Srgrimes
1882150634Sjhb	return (cr->cr_ref > 1);
18831541Srgrimes}
18841541Srgrimes
18851541Srgrimes/*
188684827Sjhb * Copy a ucred's contents from a template.  Does not block.
188784827Sjhb */
188884827Sjhbvoid
188993580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
189084827Sjhb{
189184827Sjhb
189284827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
189384827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
189487218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
189584827Sjhb		(caddr_t)&src->cr_startcopy));
1896194498Sbrooks	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
189784827Sjhb	uihold(dest->cr_uidinfo);
189884827Sjhb	uihold(dest->cr_ruidinfo);
1899192895Sjamie	prison_hold(dest->cr_prison);
1900219304Strasz	loginclass_hold(dest->cr_loginclass);
1901170407Srwatson#ifdef AUDIT
1902170407Srwatson	audit_cred_copy(src, dest);
1903170407Srwatson#endif
1904101001Srwatson#ifdef MAC
1905172930Srwatson	mac_cred_copy(src, dest);
1906101001Srwatson#endif
190784827Sjhb}
190884827Sjhb
190984827Sjhb/*
19101541Srgrimes * Dup cred struct to a new held one.
19111541Srgrimes */
19121541Srgrimesstruct ucred *
191393580Sjhbcrdup(struct ucred *cr)
19141541Srgrimes{
19151541Srgrimes	struct ucred *newcr;
19161541Srgrimes
191784827Sjhb	newcr = crget();
191884827Sjhb	crcopy(newcr, cr);
19191541Srgrimes	return (newcr);
19201541Srgrimes}
19211541Srgrimes
19221541Srgrimes/*
192391354Sdd * Fill in a struct xucred based on a struct ucred.
192491354Sdd */
192591354Sddvoid
192693580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
192791354Sdd{
1928194498Sbrooks	int ngroups;
192991354Sdd
193091354Sdd	bzero(xcr, sizeof(*xcr));
193191354Sdd	xcr->cr_version = XUCRED_VERSION;
193291354Sdd	xcr->cr_uid = cr->cr_uid;
1933194498Sbrooks
1934194498Sbrooks	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
1935194498Sbrooks	xcr->cr_ngroups = ngroups;
1936194498Sbrooks	bcopy(cr->cr_groups, xcr->cr_groups,
1937194498Sbrooks	    ngroups * sizeof(*cr->cr_groups));
193891354Sdd}
193991354Sdd
194091354Sdd/*
1941167211Srwatson * small routine to swap a thread's current ucred for the correct one taken
1942167211Srwatson * from the process.
194390748Sjulian */
194490748Sjulianvoid
194590748Sjuliancred_update_thread(struct thread *td)
194690748Sjulian{
194790748Sjulian	struct proc *p;
194891405Sjhb	struct ucred *cred;
194990748Sjulian
195090748Sjulian	p = td->td_proc;
195191405Sjhb	cred = td->td_ucred;
195290748Sjulian	PROC_LOCK(p);
195390748Sjulian	td->td_ucred = crhold(p->p_ucred);
195490748Sjulian	PROC_UNLOCK(p);
195591405Sjhb	if (cred != NULL)
195691405Sjhb		crfree(cred);
195790748Sjulian}
195890748Sjulian
1959302229Sbdrewery/*
1960303846Sbdrewery * Set initial process credentials.
1961303846Sbdrewery * Callers are responsible for providing the reference for provided credentials.
1962303846Sbdrewery */
1963303846Sbdreweryvoid
1964303846Sbdreweryproc_set_cred_init(struct proc *p, struct ucred *newcred)
1965303846Sbdrewery{
1966303846Sbdrewery
1967303846Sbdrewery	p->p_ucred = newcred;
1968303846Sbdrewery}
1969303846Sbdrewery
1970303846Sbdrewery/*
1971302229Sbdrewery * Change process credentials.
1972303846Sbdrewery * Callers are responsible for providing the reference for passed credentials
1973302229Sbdrewery * and for freeing old ones.
1974302229Sbdrewery *
1975302229Sbdrewery * Process has to be locked except when it does not have credentials (as it
1976302229Sbdrewery * should not be visible just yet) or when newcred is NULL (as this can be
1977302229Sbdrewery * only used when the process is about to be freed, at which point it should
1978302229Sbdrewery * not be visible anymore).
1979302229Sbdrewery */
1980194498Sbrooksstruct ucred *
1981302229Sbdreweryproc_set_cred(struct proc *p, struct ucred *newcred)
1982302229Sbdrewery{
1983302229Sbdrewery	struct ucred *oldcred;
1984302229Sbdrewery
1985303846Sbdrewery	MPASS(p->p_ucred != NULL);
1986302229Sbdrewery	if (newcred == NULL)
1987302229Sbdrewery		MPASS(p->p_state == PRS_ZOMBIE);
1988303846Sbdrewery	else
1989302229Sbdrewery		PROC_LOCK_ASSERT(p, MA_OWNED);
1990302229Sbdrewery
1991302229Sbdrewery	oldcred = p->p_ucred;
1992302229Sbdrewery	p->p_ucred = newcred;
1993302229Sbdrewery	return (oldcred);
1994302229Sbdrewery}
1995302229Sbdrewery
1996302229Sbdrewerystruct ucred *
1997194498Sbrookscrcopysafe(struct proc *p, struct ucred *cr)
1998194498Sbrooks{
1999194498Sbrooks	struct ucred *oldcred;
2000194498Sbrooks	int groups;
2001194498Sbrooks
2002194498Sbrooks	PROC_LOCK_ASSERT(p, MA_OWNED);
2003194498Sbrooks
2004194498Sbrooks	oldcred = p->p_ucred;
2005194498Sbrooks	while (cr->cr_agroups < oldcred->cr_agroups) {
2006194498Sbrooks		groups = oldcred->cr_agroups;
2007194498Sbrooks		PROC_UNLOCK(p);
2008194498Sbrooks		crextend(cr, groups);
2009194498Sbrooks		PROC_LOCK(p);
2010194498Sbrooks		oldcred = p->p_ucred;
2011194498Sbrooks	}
2012194498Sbrooks	crcopy(cr, oldcred);
2013194498Sbrooks
2014194498Sbrooks	return (oldcred);
2015194498Sbrooks}
2016194498Sbrooks
201790748Sjulian/*
2018194498Sbrooks * Extend the passed in credential to hold n items.
2019194498Sbrooks */
2020293897Sglebiusvoid
2021194498Sbrookscrextend(struct ucred *cr, int n)
2022194498Sbrooks{
2023194498Sbrooks	int cnt;
2024194498Sbrooks
2025194498Sbrooks	/* Truncate? */
2026194498Sbrooks	if (n <= cr->cr_agroups)
2027194498Sbrooks		return;
2028194498Sbrooks
2029194498Sbrooks	/*
2030194498Sbrooks	 * We extend by 2 each time since we're using a power of two
2031194498Sbrooks	 * allocator until we need enough groups to fill a page.
2032194498Sbrooks	 * Once we're allocating multiple pages, only allocate as many
2033194498Sbrooks	 * as we actually need.  The case of processes needing a
2034194498Sbrooks	 * non-power of two number of pages seems more likely than
2035194498Sbrooks	 * a real world process that adds thousands of groups one at a
2036194498Sbrooks	 * time.
2037194498Sbrooks	 */
2038194498Sbrooks	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2039194498Sbrooks		if (cr->cr_agroups == 0)
2040194498Sbrooks			cnt = MINALLOCSIZE / sizeof(gid_t);
2041194498Sbrooks		else
2042194498Sbrooks			cnt = cr->cr_agroups * 2;
2043194498Sbrooks
2044194498Sbrooks		while (cnt < n)
2045194498Sbrooks			cnt *= 2;
2046194498Sbrooks	} else
2047194498Sbrooks		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2048194498Sbrooks
2049194498Sbrooks	/* Free the old array. */
2050194498Sbrooks	if (cr->cr_groups)
2051194498Sbrooks		free(cr->cr_groups, M_CRED);
2052194498Sbrooks
2053194498Sbrooks	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2054194498Sbrooks	cr->cr_agroups = cnt;
2055194498Sbrooks}
2056194498Sbrooks
2057194498Sbrooks/*
2058194556Sbrooks * Copy groups in to a credential, preserving any necessary invariants.
2059194556Sbrooks * Currently this includes the sorting of all supplemental gids.
2060194556Sbrooks * crextend() must have been called before hand to ensure sufficient
2061194556Sbrooks * space is available.
2062194498Sbrooks */
2063194498Sbrooksstatic void
2064194498Sbrookscrsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
2065194498Sbrooks{
2066194556Sbrooks	int i;
2067194556Sbrooks	int j;
2068194556Sbrooks	gid_t g;
2069194498Sbrooks
2070194498Sbrooks	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
2071194498Sbrooks
2072194498Sbrooks	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2073194498Sbrooks	cr->cr_ngroups = ngrp;
2074194556Sbrooks
2075194556Sbrooks	/*
2076194556Sbrooks	 * Sort all groups except cr_groups[0] to allow groupmember to
2077194556Sbrooks	 * perform a binary search.
2078194556Sbrooks	 *
2079194556Sbrooks	 * XXX: If large numbers of groups become common this should
2080194556Sbrooks	 * be replaced with shell sort like linux uses or possibly
2081194556Sbrooks	 * heap sort.
2082194556Sbrooks	 */
2083194556Sbrooks	for (i = 2; i < ngrp; i++) {
2084194556Sbrooks		g = cr->cr_groups[i];
2085194556Sbrooks		for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--)
2086194556Sbrooks			cr->cr_groups[j + 1] = cr->cr_groups[j];
2087194556Sbrooks		cr->cr_groups[j + 1] = g;
2088194556Sbrooks	}
2089194498Sbrooks}
2090194498Sbrooks
2091194498Sbrooks/*
2092194498Sbrooks * Copy groups in to a credential after expanding it if required.
2093202143Sbrooks * Truncate the list to (ngroups_max + 1) if it is too large.
2094194498Sbrooks */
2095194498Sbrooksvoid
2096194498Sbrookscrsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
2097194498Sbrooks{
2098194498Sbrooks
2099202143Sbrooks	if (ngrp > ngroups_max + 1)
2100202143Sbrooks		ngrp = ngroups_max + 1;
2101194498Sbrooks
2102194498Sbrooks	crextend(cr, ngrp);
2103194498Sbrooks	crsetgroups_locked(cr, ngrp, groups);
2104194498Sbrooks}
2105194498Sbrooks
2106194498Sbrooks/*
21071541Srgrimes * Get login name, if available.
21081541Srgrimes */
210912221Sbde#ifndef _SYS_SYSPROTO_H_
21101541Srgrimesstruct getlogin_args {
21111541Srgrimes	char	*namebuf;
21121541Srgrimes	u_int	namelen;
21131541Srgrimes};
211412221Sbde#endif
21151541Srgrimes/* ARGSUSED */
21161549Srgrimesint
2117225617Skmacysys_getlogin(struct thread *td, struct getlogin_args *uap)
21181541Srgrimes{
211991140Stanimura	char login[MAXLOGNAME];
212083366Sjulian	struct proc *p = td->td_proc;
2121274107Sdes	size_t len;
21221541Srgrimes
212323358Sache	if (uap->namelen > MAXLOGNAME)
212423359Sache		uap->namelen = MAXLOGNAME;
212591140Stanimura	PROC_LOCK(p);
212691140Stanimura	SESS_LOCK(p->p_session);
2127274107Sdes	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
212891140Stanimura	SESS_UNLOCK(p->p_session);
212991140Stanimura	PROC_UNLOCK(p);
2130274107Sdes	if (len > uap->namelen)
2131243021Sbapt		return (ERANGE);
2132274107Sdes	return (copyout(login, uap->namebuf, len));
21331541Srgrimes}
21341541Srgrimes
21351541Srgrimes/*
21361541Srgrimes * Set login name.
21371541Srgrimes */
213812221Sbde#ifndef _SYS_SYSPROTO_H_
21391541Srgrimesstruct setlogin_args {
21401541Srgrimes	char	*namebuf;
21411541Srgrimes};
214212221Sbde#endif
21431541Srgrimes/* ARGSUSED */
21441549Srgrimesint
2145225617Skmacysys_setlogin(struct thread *td, struct setlogin_args *uap)
21461541Srgrimes{
214783366Sjulian	struct proc *p = td->td_proc;
21481541Srgrimes	int error;
214923330Sache	char logintmp[MAXLOGNAME];
21501541Srgrimes
2151274107Sdes	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2152274107Sdes
2153170587Srwatson	error = priv_check(td, PRIV_PROC_SETLOGIN);
215494619Sjhb	if (error)
215594619Sjhb		return (error);
215699009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2157274107Sdes	if (error != 0) {
2158274107Sdes		if (error == ENAMETOOLONG)
2159274107Sdes			error = EINVAL;
2160274107Sdes		return (error);
216191140Stanimura	}
2162274107Sdes	PROC_LOCK(p);
2163274107Sdes	SESS_LOCK(p->p_session);
2164274107Sdes	strcpy(p->p_session->s_login, logintmp);
2165274107Sdes	SESS_UNLOCK(p->p_session);
2166274107Sdes	PROC_UNLOCK(p);
2167274107Sdes	return (0);
21681541Srgrimes}
216931891Ssef
217031891Ssefvoid
217193580Sjhbsetsugid(struct proc *p)
217231891Ssef{
217398403Salfred
217498403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
217531891Ssef	p->p_flag |= P_SUGID;
217655707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
217731891Ssef		p->p_stops = 0;
217831891Ssef}
217965495Struckman
2180210226Strasz/*-
218182466Srwatson * Change a process's effective uid.
218277183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
218377183Srwatson * References: newcred must be an exclusive credential reference for the
218477183Srwatson *             duration of the call.
218565495Struckman */
218665495Struckmanvoid
218798417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
218865495Struckman{
218965495Struckman
219098417Salfred	newcred->cr_uid = euip->ui_uid;
219198417Salfred	uihold(euip);
219277183Srwatson	uifree(newcred->cr_uidinfo);
219398417Salfred	newcred->cr_uidinfo = euip;
219465495Struckman}
219565495Struckman
2196210226Strasz/*-
219782466Srwatson * Change a process's effective gid.
219877183Srwatson * Side effects: newcred->cr_gid will be modified.
219977183Srwatson * References: newcred must be an exclusive credential reference for the
220077183Srwatson *             duration of the call.
220165495Struckman */
220267629Sgallatinvoid
220393580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
220465495Struckman{
220565495Struckman
220677183Srwatson	newcred->cr_groups[0] = egid;
220765495Struckman}
220877183Srwatson
2209210226Strasz/*-
221082466Srwatson * Change a process's real uid.
221177183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
221277183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
221377183Srwatson *               counts will be updated.
221477183Srwatson * References: newcred must be an exclusive credential reference for the
221577183Srwatson *             duration of the call.
221677183Srwatson */
221777183Srwatsonvoid
221898417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
221977183Srwatson{
222077183Srwatson
222177183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
222298417Salfred	newcred->cr_ruid = ruip->ui_uid;
222398417Salfred	uihold(ruip);
222477183Srwatson	uifree(newcred->cr_ruidinfo);
222598417Salfred	newcred->cr_ruidinfo = ruip;
222677183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
222777183Srwatson}
222877183Srwatson
2229210226Strasz/*-
223082466Srwatson * Change a process's real gid.
223177183Srwatson * Side effects: newcred->cr_rgid will be updated.
223277183Srwatson * References: newcred must be an exclusive credential reference for the
223377183Srwatson *             duration of the call.
223477183Srwatson */
223577183Srwatsonvoid
223693580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
223777183Srwatson{
223877183Srwatson
223977183Srwatson	newcred->cr_rgid = rgid;
224077183Srwatson}
224177183Srwatson
2242210226Strasz/*-
224382466Srwatson * Change a process's saved uid.
224477183Srwatson * Side effects: newcred->cr_svuid will be updated.
224577183Srwatson * References: newcred must be an exclusive credential reference for the
224677183Srwatson *             duration of the call.
224777183Srwatson */
224877183Srwatsonvoid
224993580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
225077183Srwatson{
225177183Srwatson
225277183Srwatson	newcred->cr_svuid = svuid;
225377183Srwatson}
225477183Srwatson
2255210226Strasz/*-
225682466Srwatson * Change a process's saved gid.
225777183Srwatson * Side effects: newcred->cr_svgid will be updated.
225877183Srwatson * References: newcred must be an exclusive credential reference for the
225977183Srwatson *             duration of the call.
226077183Srwatson */
226177183Srwatsonvoid
226293580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
226377183Srwatson{
226477183Srwatson
226577183Srwatson	newcred->cr_svgid = svgid;
226677183Srwatson}
2267