kern_prot.c revision 89414
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
987218Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson.  All rights reserved.
101541Srgrimes *
111541Srgrimes * Redistribution and use in source and binary forms, with or without
121541Srgrimes * modification, are permitted provided that the following conditions
131541Srgrimes * are met:
141541Srgrimes * 1. Redistributions of source code must retain the above copyright
151541Srgrimes *    notice, this list of conditions and the following disclaimer.
161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer in the
181541Srgrimes *    documentation and/or other materials provided with the distribution.
191541Srgrimes * 3. All advertising materials mentioning features or use of this software
201541Srgrimes *    must display the following acknowledgement:
211541Srgrimes *	This product includes software developed by the University of
221541Srgrimes *	California, Berkeley and its contributors.
231541Srgrimes * 4. Neither the name of the University nor the names of its contributors
241541Srgrimes *    may be used to endorse or promote products derived from this software
251541Srgrimes *    without specific prior written permission.
261541Srgrimes *
271541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
281541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
291541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
301541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
311541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
321541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
331541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
341541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
351541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
361541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
371541Srgrimes * SUCH DAMAGE.
381541Srgrimes *
391541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
4050477Speter * $FreeBSD: head/sys/kern/kern_prot.c 89414 2002-01-16 06:55:30Z arr $
411541Srgrimes */
421541Srgrimes
431541Srgrimes/*
441541Srgrimes * System calls related to processes and protection
451541Srgrimes */
461541Srgrimes
4731778Seivind#include "opt_compat.h"
4831778Seivind
491541Srgrimes#include <sys/param.h>
5076166Smarkm#include <sys/systm.h>
511541Srgrimes#include <sys/acct.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
5476166Smarkm#include <sys/mutex.h>
551541Srgrimes#include <sys/proc.h>
5686304Sjhb#include <sys/sx.h>
5776166Smarkm#include <sys/sysproto.h>
5887218Srwatson#include <sys/jail.h>
591541Srgrimes#include <sys/malloc.h>
6031891Ssef#include <sys/pioctl.h>
6165495Struckman#include <sys/resourcevar.h>
6261287Srwatson#include <sys/sysctl.h>
631541Srgrimes
6430354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6530354Sphk
6689414SarrSYSCTL_DECL(_security);
6789414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0,
6887138Srwatson    "BSD security policy");
6987138Srwatson
7012221Sbde#ifndef _SYS_SYSPROTO_H_
7111332Sswallacestruct getpid_args {
721541Srgrimes	int	dummy;
731541Srgrimes};
7412221Sbde#endif
7558717Sdillon/*
7682749Sdillon * MPSAFE
7782749Sdillon */
781541Srgrimes/* ARGSUSED */
791549Srgrimesint
8083366Sjuliangetpid(td, uap)
8183366Sjulian	struct thread *td;
8211332Sswallace	struct getpid_args *uap;
831541Srgrimes{
8483366Sjulian	struct proc *p = td->td_proc;
8585564Sdillon	int s;
861541Srgrimes
8785564Sdillon	s = mtx_lock_giant(kern_giant_proc);
8883366Sjulian	td->td_retval[0] = p->p_pid;
891541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9074728Sjhb	PROC_LOCK(p);
9183366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
9274728Sjhb	PROC_UNLOCK(p);
931541Srgrimes#endif
9485564Sdillon	mtx_unlock_giant(s);
951541Srgrimes	return (0);
961541Srgrimes}
971541Srgrimes
9812221Sbde#ifndef _SYS_SYSPROTO_H_
9911332Sswallacestruct getppid_args {
10011332Sswallace        int     dummy;
10111332Sswallace};
10212221Sbde#endif
10382749Sdillon/*
10482749Sdillon * MPSAFE
10582749Sdillon */
1061541Srgrimes/* ARGSUSED */
1071549Srgrimesint
10883366Sjuliangetppid(td, uap)
10983366Sjulian	struct thread *td;
11011332Sswallace	struct getppid_args *uap;
1111541Srgrimes{
11283366Sjulian	struct proc *p = td->td_proc;
11385564Sdillon	int s;
1141541Srgrimes
11585564Sdillon	s = mtx_lock_giant(kern_giant_proc);
11674728Sjhb	PROC_LOCK(p);
11783366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
11874728Sjhb	PROC_UNLOCK(p);
11985564Sdillon	mtx_unlock_giant(s);
1201541Srgrimes	return (0);
1211541Srgrimes}
1221541Srgrimes
12387466Srwatson/*
12487218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
12558717Sdillon */
12612221Sbde#ifndef _SYS_SYSPROTO_H_
12711332Sswallacestruct getpgrp_args {
12811332Sswallace        int     dummy;
12911332Sswallace};
13012221Sbde#endif
13182749Sdillon/*
13282749Sdillon * MPSAFE
13382749Sdillon */
1341549Srgrimesint
13583366Sjuliangetpgrp(td, uap)
13683366Sjulian	struct thread *td;
13711332Sswallace	struct getpgrp_args *uap;
1381541Srgrimes{
13983366Sjulian	struct proc *p = td->td_proc;
1401541Srgrimes
14182749Sdillon	mtx_lock(&Giant);
14283366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
14382749Sdillon	mtx_unlock(&Giant);
1441541Srgrimes	return (0);
1451541Srgrimes}
1461541Srgrimes
14728401Speter/* Get an arbitary pid's process group id */
14812221Sbde#ifndef _SYS_SYSPROTO_H_
14928401Speterstruct getpgid_args {
15028401Speter	pid_t	pid;
15128401Speter};
15228401Speter#endif
15382749Sdillon/*
15482749Sdillon * MPSAFE
15582749Sdillon */
15628401Speterint
15783366Sjuliangetpgid(td, uap)
15883366Sjulian	struct thread *td;
15928401Speter	struct getpgid_args *uap;
16028401Speter{
16183366Sjulian	struct proc *p = td->td_proc;
16241726Struckman	struct proc *pt;
16387218Srwatson	int error, s;
16441726Struckman
16585564Sdillon	s = mtx_lock_giant(kern_giant_proc);
16687218Srwatson	error = 0;
16728401Speter	if (uap->pid == 0)
16883366Sjulian		td->td_retval[0] = p->p_pgrp->pg_id;
16984825Sjhb	else if ((pt = pfind(uap->pid)) == NULL)
17084825Sjhb		error = ESRCH;
17175893Sjhb	else {
17284825Sjhb		error = p_cansee(p, pt);
17384825Sjhb		if (error == 0)
17484825Sjhb			td->td_retval[0] = pt->p_pgrp->pg_id;
17575893Sjhb		PROC_UNLOCK(pt);
17675893Sjhb	}
17785564Sdillon	mtx_unlock_giant(s);
17882749Sdillon	return (error);
17928401Speter}
18028401Speter
18128401Speter/*
18228401Speter * Get an arbitary pid's session id.
18328401Speter */
18428401Speter#ifndef _SYS_SYSPROTO_H_
18528401Speterstruct getsid_args {
18628401Speter	pid_t	pid;
18728401Speter};
18828401Speter#endif
18982749Sdillon/*
19082749Sdillon * MPSAFE
19182749Sdillon */
19228401Speterint
19383366Sjuliangetsid(td, uap)
19483366Sjulian	struct thread *td;
19528401Speter	struct getsid_args *uap;
19628401Speter{
19783366Sjulian	struct proc *p = td->td_proc;
19841726Struckman	struct proc *pt;
19987218Srwatson	int error;
20041726Struckman
20182749Sdillon	mtx_lock(&Giant);
20287218Srwatson	error = 0;
20384825Sjhb	if (uap->pid == 0)
20483366Sjulian		td->td_retval[0] = p->p_session->s_sid;
20584825Sjhb	else if ((pt = pfind(uap->pid)) == NULL)
20684825Sjhb		error = ESRCH;
20784825Sjhb	else {
20884825Sjhb		error = p_cansee(p, pt);
20984825Sjhb		if (error == 0)
21084825Sjhb			td->td_retval[0] = pt->p_session->s_sid;
21175893Sjhb		PROC_UNLOCK(pt);
21275893Sjhb	}
21382749Sdillon	mtx_unlock(&Giant);
21482749Sdillon	return (error);
21528401Speter}
21628401Speter
21728401Speter#ifndef _SYS_SYSPROTO_H_
21811332Sswallacestruct getuid_args {
21911332Sswallace        int     dummy;
22011332Sswallace};
22112221Sbde#endif
22282749Sdillon/*
22382749Sdillon * MPSAFE
22482749Sdillon */
2251541Srgrimes/* ARGSUSED */
2261549Srgrimesint
22783366Sjuliangetuid(td, uap)
22883366Sjulian	struct thread *td;
22911332Sswallace	struct getuid_args *uap;
2301541Srgrimes{
23183366Sjulian	struct proc *p = td->td_proc;
2321541Srgrimes
23382749Sdillon	mtx_lock(&Giant);
23483366Sjulian	td->td_retval[0] = p->p_ucred->cr_ruid;
2351541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
23683366Sjulian	td->td_retval[1] = p->p_ucred->cr_uid;
2371541Srgrimes#endif
23882749Sdillon	mtx_unlock(&Giant);
2391541Srgrimes	return (0);
2401541Srgrimes}
2411541Srgrimes
24212221Sbde#ifndef _SYS_SYSPROTO_H_
24311332Sswallacestruct geteuid_args {
24411332Sswallace        int     dummy;
24511332Sswallace};
24612221Sbde#endif
24787218Srwatson/*
24887218Srwatson * MPSAFE
24987218Srwatson */
2501541Srgrimes/* ARGSUSED */
2511549Srgrimesint
25283366Sjuliangeteuid(td, uap)
25383366Sjulian	struct thread *td;
25411332Sswallace	struct geteuid_args *uap;
2551541Srgrimes{
25682749Sdillon	mtx_lock(&Giant);
25783366Sjulian	td->td_retval[0] = td->td_proc->p_ucred->cr_uid;
25882749Sdillon	mtx_unlock(&Giant);
2591541Srgrimes	return (0);
2601541Srgrimes}
2611541Srgrimes
26212221Sbde#ifndef _SYS_SYSPROTO_H_
26311332Sswallacestruct getgid_args {
26411332Sswallace        int     dummy;
26511332Sswallace};
26612221Sbde#endif
26782749Sdillon/*
26882749Sdillon * MPSAFE
26982749Sdillon */
2701541Srgrimes/* ARGSUSED */
2711549Srgrimesint
27283366Sjuliangetgid(td, uap)
27383366Sjulian	struct thread *td;
27411332Sswallace	struct getgid_args *uap;
2751541Srgrimes{
27683366Sjulian	struct proc *p = td->td_proc;
2771541Srgrimes
27882749Sdillon	mtx_lock(&Giant);
27983366Sjulian	td->td_retval[0] = p->p_ucred->cr_rgid;
2801541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
28183366Sjulian	td->td_retval[1] = p->p_ucred->cr_groups[0];
2821541Srgrimes#endif
28382749Sdillon	mtx_unlock(&Giant);
2841541Srgrimes	return (0);
2851541Srgrimes}
2861541Srgrimes
2871541Srgrimes/*
2881541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2891541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2901541Srgrimes * correctly in a library function.
2911541Srgrimes */
29212221Sbde#ifndef _SYS_SYSPROTO_H_
29311332Sswallacestruct getegid_args {
29411332Sswallace        int     dummy;
29511332Sswallace};
29612221Sbde#endif
29782749Sdillon/*
29882749Sdillon * MPSAFE
29982749Sdillon */
3001541Srgrimes/* ARGSUSED */
3011549Srgrimesint
30283366Sjuliangetegid(td, uap)
30383366Sjulian	struct thread *td;
30411332Sswallace	struct getegid_args *uap;
3051541Srgrimes{
30683366Sjulian	struct proc *p = td->td_proc;
3071541Srgrimes
30882749Sdillon	mtx_lock(&Giant);
30983366Sjulian	td->td_retval[0] = p->p_ucred->cr_groups[0];
31082749Sdillon	mtx_unlock(&Giant);
3111541Srgrimes	return (0);
3121541Srgrimes}
3131541Srgrimes
31412221Sbde#ifndef _SYS_SYSPROTO_H_
3151541Srgrimesstruct getgroups_args {
3161541Srgrimes	u_int	gidsetsize;
3171541Srgrimes	gid_t	*gidset;
3181541Srgrimes};
31912221Sbde#endif
32082749Sdillon/*
32182749Sdillon * MPSAFE
32282749Sdillon */
3231549Srgrimesint
32483366Sjuliangetgroups(td, uap)
32583366Sjulian	struct thread *td;
32687218Srwatson	register struct getgroups_args *uap;
3271541Srgrimes{
32882749Sdillon	struct ucred *cred;
32983366Sjulian	struct proc *p = td->td_proc;
33077183Srwatson	u_int ngrp;
33187218Srwatson	int error;
3321541Srgrimes
33382749Sdillon	mtx_lock(&Giant);
33487218Srwatson	error = 0;
33582749Sdillon	cred = p->p_ucred;
3361541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
33783366Sjulian		td->td_retval[0] = cred->cr_ngroups;
33882749Sdillon		goto done2;
3391541Srgrimes	}
34082749Sdillon	if (ngrp < cred->cr_ngroups) {
34182749Sdillon		error = EINVAL;
34282749Sdillon		goto done2;
34382749Sdillon	}
34477183Srwatson	ngrp = cred->cr_ngroups;
34577183Srwatson	if ((error = copyout((caddr_t)cred->cr_groups,
34687218Srwatson	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
34782749Sdillon		goto done2;
34883366Sjulian	td->td_retval[0] = ngrp;
34982749Sdillondone2:
35082749Sdillon	mtx_unlock(&Giant);
35182749Sdillon	return (error);
3521541Srgrimes}
3531541Srgrimes
35412221Sbde#ifndef _SYS_SYSPROTO_H_
35512207Sbdestruct setsid_args {
35611332Sswallace        int     dummy;
35711332Sswallace};
35812221Sbde#endif
35982749Sdillon/*
36082749Sdillon * MPSAFE
36182749Sdillon */
3621541Srgrimes/* ARGSUSED */
3631549Srgrimesint
36483366Sjuliansetsid(td, uap)
36583366Sjulian	register struct thread *td;
36612207Sbde	struct setsid_args *uap;
3671541Srgrimes{
36882749Sdillon	int error;
36983366Sjulian	struct proc *p = td->td_proc;
3701541Srgrimes
37182749Sdillon	mtx_lock(&Giant);
37287218Srwatson	if (p->p_pgid == p->p_pid || pgfind(p->p_pid))
37382749Sdillon		error = EPERM;
37487218Srwatson	else {
3751541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
37683366Sjulian		td->td_retval[0] = p->p_pid;
37782749Sdillon		error = 0;
3781541Srgrimes	}
37982749Sdillon	mtx_unlock(&Giant);
38082749Sdillon	return (error);
3811541Srgrimes}
3821541Srgrimes
3831541Srgrimes/*
3841541Srgrimes * set process group (setpgid/old setpgrp)
3851541Srgrimes *
3861541Srgrimes * caller does setpgid(targpid, targpgid)
3871541Srgrimes *
3881541Srgrimes * pid must be caller or child of caller (ESRCH)
3891541Srgrimes * if a child
3901541Srgrimes *	pid must be in same session (EPERM)
3911541Srgrimes *	pid can't have done an exec (EACCES)
3921541Srgrimes * if pgid != pid
3931541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3941541Srgrimes * pid must not be session leader (EPERM)
3951541Srgrimes */
39612221Sbde#ifndef _SYS_SYSPROTO_H_
3971541Srgrimesstruct setpgid_args {
39887218Srwatson	int	pid;		/* target process id */
39987218Srwatson	int	pgid;		/* target pgrp id */
4001541Srgrimes};
40112221Sbde#endif
40282749Sdillon/*
40382749Sdillon * MPSAFE
40482749Sdillon */
4051541Srgrimes/* ARGSUSED */
4061549Srgrimesint
40783366Sjuliansetpgid(td, uap)
40883366Sjulian	struct thread *td;
4091541Srgrimes	register struct setpgid_args *uap;
4101541Srgrimes{
41183366Sjulian	struct proc *curp = td->td_proc;
41287218Srwatson	register struct proc *targp;	/* target process */
41387218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
41475448Srwatson	int error;
4151541Srgrimes
41620677Sbde	if (uap->pgid < 0)
41720677Sbde		return (EINVAL);
41882749Sdillon	mtx_lock(&Giant);
41986304Sjhb	sx_slock(&proctree_lock);
4201541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
42175893Sjhb		if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
42275893Sjhb			if (targp)
42375893Sjhb				PROC_UNLOCK(targp);
42482749Sdillon			error = ESRCH;
42582749Sdillon			goto done2;
42675893Sjhb		}
42779335Srwatson		if ((error = p_cansee(curproc, targp))) {
42875893Sjhb			PROC_UNLOCK(targp);
42982749Sdillon			goto done2;
43075893Sjhb		}
43175893Sjhb		if (targp->p_pgrp == NULL ||
43275893Sjhb		    targp->p_session != curp->p_session) {
43375893Sjhb			PROC_UNLOCK(targp);
43482749Sdillon			error = EPERM;
43582749Sdillon			goto done2;
43675893Sjhb		}
43775893Sjhb		if (targp->p_flag & P_EXEC) {
43875893Sjhb			PROC_UNLOCK(targp);
43982749Sdillon			error = EACCES;
44082749Sdillon			goto done2;
44175893Sjhb		}
44275893Sjhb	} else {
4431541Srgrimes		targp = curp;
44475893Sjhb		PROC_LOCK(curp);	/* XXX: not needed */
44575893Sjhb	}
44675893Sjhb	if (SESS_LEADER(targp)) {
44775893Sjhb		PROC_UNLOCK(targp);
44882749Sdillon		error = EPERM;
44982749Sdillon		goto done2;
45075893Sjhb	}
45187218Srwatson	if (uap->pgid == 0)
4521541Srgrimes		uap->pgid = targp->p_pid;
45387218Srwatson	else if (uap->pgid != targp->p_pid) {
4541541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
45587218Srwatson		    pgrp->pg_session != curp->p_session) {
45675893Sjhb			PROC_UNLOCK(targp);
45782749Sdillon			error = EPERM;
45882749Sdillon			goto done2;
45975893Sjhb		}
46082749Sdillon	}
46175893Sjhb	/* XXX: We should probably hold the lock across enterpgrp. */
46275893Sjhb	PROC_UNLOCK(targp);
46382749Sdillon	error = enterpgrp(targp, uap->pgid, 0);
46482749Sdillondone2:
46586304Sjhb	sx_sunlock(&proctree_lock);
46682749Sdillon	mtx_unlock(&Giant);
46782749Sdillon	return (error);
4681541Srgrimes}
4691541Srgrimes
47024448Speter/*
47124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
47272093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47324448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
47424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
47524448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
47624448Speter * does not set the saved id - this is dangerous for traditional BSD
47724448Speter * programs.  For this reason, we *really* do not want to set
47824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
47924448Speter */
48024448Speter#define POSIX_APPENDIX_B_4_2_2
48124448Speter
48212221Sbde#ifndef _SYS_SYSPROTO_H_
4831541Srgrimesstruct setuid_args {
4841541Srgrimes	uid_t	uid;
4851541Srgrimes};
48612221Sbde#endif
48782749Sdillon/*
48882749Sdillon * MPSAFE
48982749Sdillon */
4901541Srgrimes/* ARGSUSED */
4911549Srgrimesint
49283366Sjuliansetuid(td, uap)
49383366Sjulian	struct thread *td;
4941541Srgrimes	struct setuid_args *uap;
4951541Srgrimes{
49683366Sjulian	struct proc *p = td->td_proc;
49777183Srwatson	struct ucred *newcred, *oldcred;
49877183Srwatson	uid_t uid;
49987218Srwatson	int error;
5001541Srgrimes
50177183Srwatson	uid = uap->uid;
50282749Sdillon	mtx_lock(&Giant);
50387218Srwatson	error = 0;
50487219Srwatson	oldcred = p->p_ucred;
50587466Srwatson
50624448Speter	/*
50724448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
50824448Speter	 *
50987218Srwatson	 * Note that setuid(geteuid()) is a special case of
51024448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
51172093Sasmodai	 * to use this clause to be compatible with traditional BSD
51224448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
51324448Speter	 * three id's (assuming you have privs).
51424448Speter	 *
51524448Speter	 * Notes on the logic.  We do things in three steps.
51624448Speter	 * 1: We determine if the euid is going to change, and do EPERM
51724448Speter	 *    right away.  We unconditionally change the euid later if this
51824448Speter	 *    test is satisfied, simplifying that part of the logic.
51987218Srwatson	 * 2: We determine if the real and/or saved uids are going to
52024448Speter	 *    change.  Determined by compile options.
52124448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
52224448Speter	 */
52377183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
52417994Sache#ifdef _POSIX_SAVED_IDS
52577183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
52617994Sache#endif
52724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
52877183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
52924448Speter#endif
53087218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
53182749Sdillon		goto done2;
53224448Speter
53377183Srwatson	newcred = crdup(oldcred);
53424448Speter#ifdef _POSIX_SAVED_IDS
5351541Srgrimes	/*
53624448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
53724448Speter	 * If so, we are changing the real uid and/or saved uid.
5381541Srgrimes	 */
53917994Sache	if (
54024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
54177183Srwatson	    uid == oldcred->cr_uid ||
54217994Sache#endif
54377183Srwatson	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
54417994Sache#endif
54524448Speter	{
54624448Speter		/*
54765495Struckman		 * Set the real uid and transfer proc count to new user.
54824448Speter		 */
54977183Srwatson		if (uid != oldcred->cr_ruid) {
55077183Srwatson			change_ruid(newcred, uid);
55165495Struckman			setsugid(p);
55224448Speter		}
55324448Speter		/*
55424448Speter		 * Set saved uid
55524448Speter		 *
55624448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
55724448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
55824448Speter		 * is important that we should do this.
55924448Speter		 */
56077183Srwatson		if (uid != oldcred->cr_svuid) {
56177183Srwatson			change_svuid(newcred, uid);
56231891Ssef			setsugid(p);
56324448Speter		}
5648141Sache	}
56524448Speter
56624448Speter	/*
56724448Speter	 * In all permitted cases, we are changing the euid.
56824448Speter	 * Copy credentials so other references do not see our changes.
56924448Speter	 */
57077183Srwatson	if (uid != oldcred->cr_uid) {
57177183Srwatson		change_euid(newcred, uid);
57231891Ssef		setsugid(p);
57324448Speter	}
57477183Srwatson	p->p_ucred = newcred;
57577183Srwatson	crfree(oldcred);
57682749Sdillondone2:
57782749Sdillon	mtx_unlock(&Giant);
57882749Sdillon	return (error);
5791541Srgrimes}
5801541Srgrimes
58112221Sbde#ifndef _SYS_SYSPROTO_H_
5821541Srgrimesstruct seteuid_args {
5831541Srgrimes	uid_t	euid;
5841541Srgrimes};
58512221Sbde#endif
58682749Sdillon/*
58782749Sdillon * MPSAFE
58882749Sdillon */
5891541Srgrimes/* ARGSUSED */
5901549Srgrimesint
59183366Sjulianseteuid(td, uap)
59283366Sjulian	struct thread *td;
5931541Srgrimes	struct seteuid_args *uap;
5941541Srgrimes{
59583366Sjulian	struct proc *p = td->td_proc;
59677183Srwatson	struct ucred *newcred, *oldcred;
59777183Srwatson	uid_t euid;
59887218Srwatson	int error;
5991541Srgrimes
6001541Srgrimes	euid = uap->euid;
60182749Sdillon	mtx_lock(&Giant);
60287218Srwatson	error = 0;
60377183Srwatson	oldcred = p->p_ucred;
60477183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
60577183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
60687218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
60782749Sdillon		goto done2;
6081541Srgrimes	/*
6091541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
6101541Srgrimes	 * not see our changes.
6111541Srgrimes	 */
61277183Srwatson	newcred = crdup(oldcred);
61377183Srwatson	if (oldcred->cr_uid != euid) {
61477183Srwatson		change_euid(newcred, euid);
61531891Ssef		setsugid(p);
61624449Speter	}
61777183Srwatson	p->p_ucred = newcred;
61877183Srwatson	crfree(oldcred);
61982749Sdillondone2:
62082749Sdillon	mtx_unlock(&Giant);
62182749Sdillon	return (error);
6221541Srgrimes}
6231541Srgrimes
62412221Sbde#ifndef _SYS_SYSPROTO_H_
6251541Srgrimesstruct setgid_args {
6261541Srgrimes	gid_t	gid;
6271541Srgrimes};
62812221Sbde#endif
62982749Sdillon/*
63082749Sdillon * MPSAFE
63182749Sdillon */
6321541Srgrimes/* ARGSUSED */
6331549Srgrimesint
63483366Sjuliansetgid(td, uap)
63583366Sjulian	struct thread *td;
6361541Srgrimes	struct setgid_args *uap;
6371541Srgrimes{
63883366Sjulian	struct proc *p = td->td_proc;
63977183Srwatson	struct ucred *newcred, *oldcred;
64077183Srwatson	gid_t gid;
64187218Srwatson	int error;
6421541Srgrimes
64377183Srwatson	gid = uap->gid;
64482749Sdillon	mtx_lock(&Giant);
64587218Srwatson	error = 0;
64677183Srwatson	oldcred = p->p_ucred;
64787466Srwatson
64824448Speter	/*
64924448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
65024448Speter	 *
65124448Speter	 * Note that setgid(getegid()) is a special case of
65224448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
65372093Sasmodai	 * to use this clause to be compatible with traditional BSD
65424448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
65524448Speter	 * three id's (assuming you have privs).
65624448Speter	 *
65724448Speter	 * For notes on the logic here, see setuid() above.
65824448Speter	 */
65977183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
66017994Sache#ifdef _POSIX_SAVED_IDS
66177183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
66217994Sache#endif
66324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
66477183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
66524448Speter#endif
66687218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
66782749Sdillon		goto done2;
66824448Speter
66977183Srwatson	newcred = crdup(oldcred);
67017994Sache#ifdef _POSIX_SAVED_IDS
67124448Speter	/*
67224448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
67324448Speter	 * If so, we are changing the real uid and saved gid.
67424448Speter	 */
67524448Speter	if (
67624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
67777183Srwatson	    gid == oldcred->cr_groups[0] ||
67817994Sache#endif
67977183Srwatson	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
68024448Speter#endif
68124448Speter	{
68224448Speter		/*
68324448Speter		 * Set real gid
68424448Speter		 */
68577183Srwatson		if (oldcred->cr_rgid != gid) {
68677183Srwatson			change_rgid(newcred, gid);
68731891Ssef			setsugid(p);
68824448Speter		}
68924448Speter		/*
69024448Speter		 * Set saved gid
69124448Speter		 *
69224448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
69324448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
69424448Speter		 * is important that we should do this.
69524448Speter		 */
69677183Srwatson		if (oldcred->cr_svgid != gid) {
69777183Srwatson			change_svgid(newcred, gid);
69831891Ssef			setsugid(p);
69924448Speter		}
7008141Sache	}
70124448Speter	/*
70224448Speter	 * In all cases permitted cases, we are changing the egid.
70324448Speter	 * Copy credentials so other references do not see our changes.
70424448Speter	 */
70577183Srwatson	if (oldcred->cr_groups[0] != gid) {
70677183Srwatson		change_egid(newcred, gid);
70731891Ssef		setsugid(p);
70824448Speter	}
70977183Srwatson	p->p_ucred = newcred;
71077183Srwatson	crfree(oldcred);
71182749Sdillondone2:
71282749Sdillon	mtx_unlock(&Giant);
71382749Sdillon	return (error);
7141541Srgrimes}
7151541Srgrimes
71612221Sbde#ifndef _SYS_SYSPROTO_H_
7171541Srgrimesstruct setegid_args {
7181541Srgrimes	gid_t	egid;
7191541Srgrimes};
72012221Sbde#endif
72182749Sdillon/*
72282749Sdillon * MPSAFE
72382749Sdillon */
7241541Srgrimes/* ARGSUSED */
7251549Srgrimesint
72683366Sjuliansetegid(td, uap)
72783366Sjulian	struct thread *td;
7281541Srgrimes	struct setegid_args *uap;
7291541Srgrimes{
73083366Sjulian	struct proc *p = td->td_proc;
73177183Srwatson	struct ucred *newcred, *oldcred;
73277183Srwatson	gid_t egid;
73387218Srwatson	int error;
7341541Srgrimes
7351541Srgrimes	egid = uap->egid;
73682749Sdillon	mtx_lock(&Giant);
73787218Srwatson	error = 0;
73877183Srwatson	oldcred = p->p_ucred;
73977183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
74077183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
74187218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
74282749Sdillon		goto done2;
74377183Srwatson	newcred = crdup(oldcred);
74477183Srwatson	if (oldcred->cr_groups[0] != egid) {
74577183Srwatson		change_egid(newcred, egid);
74631891Ssef		setsugid(p);
74724449Speter	}
74877183Srwatson	p->p_ucred = newcred;
74977183Srwatson	crfree(oldcred);
75082749Sdillondone2:
75182749Sdillon	mtx_unlock(&Giant);
75282749Sdillon	return (error);
7531541Srgrimes}
7541541Srgrimes
75512221Sbde#ifndef _SYS_SYSPROTO_H_
7561541Srgrimesstruct setgroups_args {
7571541Srgrimes	u_int	gidsetsize;
7581541Srgrimes	gid_t	*gidset;
7591541Srgrimes};
76012221Sbde#endif
76182749Sdillon/*
76282749Sdillon * MPSAFE
76382749Sdillon */
7641541Srgrimes/* ARGSUSED */
7651549Srgrimesint
76683366Sjuliansetgroups(td, uap)
76783366Sjulian	struct thread *td;
7681541Srgrimes	struct setgroups_args *uap;
7691541Srgrimes{
77083366Sjulian	struct proc *p = td->td_proc;
77177183Srwatson	struct ucred *newcred, *oldcred;
77277183Srwatson	u_int ngrp;
7731541Srgrimes	int error;
7741541Srgrimes
77587220Srwatson	ngrp = uap->gidsetsize;
77682749Sdillon	mtx_lock(&Giant);
77777183Srwatson	oldcred = p->p_ucred;
77887218Srwatson	if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
77982749Sdillon		goto done2;
78082749Sdillon	if (ngrp > NGROUPS) {
78182749Sdillon		error = EINVAL;
78282749Sdillon		goto done2;
78382749Sdillon	}
78424447Speter	/*
78524447Speter	 * XXX A little bit lazy here.  We could test if anything has
78624447Speter	 * changed before crcopy() and setting P_SUGID.
78724447Speter	 */
78877183Srwatson	newcred = crdup(oldcred);
78924447Speter	if (ngrp < 1) {
79024447Speter		/*
79124447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
79224447Speter		 * groups vector on non-BSD systems (which generally do not
79324447Speter		 * have the egid in the groups[0]).  We risk security holes
79424447Speter		 * when running non-BSD software if we do not do the same.
79524447Speter		 */
79677183Srwatson		newcred->cr_ngroups = 1;
79724447Speter	} else {
79824447Speter		if ((error = copyin((caddr_t)uap->gidset,
79977183Srwatson		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
80077183Srwatson			crfree(newcred);
80182749Sdillon			goto done2;
80277183Srwatson		}
80377183Srwatson		newcred->cr_ngroups = ngrp;
80424447Speter	}
80531891Ssef	setsugid(p);
80677183Srwatson	p->p_ucred = newcred;
80777183Srwatson	crfree(oldcred);
80882749Sdillondone2:
80982749Sdillon	mtx_unlock(&Giant);
81082749Sdillon	return (error);
8111541Srgrimes}
8121541Srgrimes
81312221Sbde#ifndef _SYS_SYSPROTO_H_
8141541Srgrimesstruct setreuid_args {
8159238Sache	uid_t	ruid;
8169238Sache	uid_t	euid;
8171541Srgrimes};
81812221Sbde#endif
81982749Sdillon/*
82082749Sdillon * MPSAFE
82182749Sdillon */
8221541Srgrimes/* ARGSUSED */
8231549Srgrimesint
82483366Sjuliansetreuid(td, uap)
82583366Sjulian	register struct thread *td;
8261541Srgrimes	struct setreuid_args *uap;
8271541Srgrimes{
82883366Sjulian	struct proc *p = td->td_proc;
82977183Srwatson	struct ucred *newcred, *oldcred;
83087218Srwatson	uid_t euid, ruid;
83187218Srwatson	int error;
8321541Srgrimes
83387218Srwatson	euid = uap->euid;
8349238Sache	ruid = uap->ruid;
83582749Sdillon	mtx_lock(&Giant);
83687218Srwatson	error = 0;
83777183Srwatson	oldcred = p->p_ucred;
83877183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
83977183Srwatson	      ruid != oldcred->cr_svuid) ||
84077183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
84177183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
84287218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
84382749Sdillon		goto done2;
84477183Srwatson	newcred = crdup(oldcred);
84577183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
84677183Srwatson		change_euid(newcred, euid);
84731891Ssef		setsugid(p);
84824450Speter	}
84977183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
85077183Srwatson		change_ruid(newcred, ruid);
85131891Ssef		setsugid(p);
8528135Sache	}
85377183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
85477183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
85577183Srwatson		change_svuid(newcred, newcred->cr_uid);
85631891Ssef		setsugid(p);
85724450Speter	}
85877183Srwatson	p->p_ucred = newcred;
85977183Srwatson	crfree(oldcred);
86082749Sdillondone2:
86182749Sdillon	mtx_unlock(&Giant);
86282749Sdillon	return (error);
8631541Srgrimes}
8641541Srgrimes
86512221Sbde#ifndef _SYS_SYSPROTO_H_
8661541Srgrimesstruct setregid_args {
8679238Sache	gid_t	rgid;
8689238Sache	gid_t	egid;
8691541Srgrimes};
87012221Sbde#endif
87182749Sdillon/*
87282749Sdillon * MPSAFE
87382749Sdillon */
8741541Srgrimes/* ARGSUSED */
8751549Srgrimesint
87683366Sjuliansetregid(td, uap)
87783366Sjulian	register struct thread *td;
8781541Srgrimes	struct setregid_args *uap;
8791541Srgrimes{
88083366Sjulian	struct proc *p = td->td_proc;
88177183Srwatson	struct ucred *newcred, *oldcred;
88287218Srwatson	gid_t egid, rgid;
88387218Srwatson	int error;
8841541Srgrimes
88587218Srwatson	egid = uap->egid;
8869238Sache	rgid = uap->rgid;
88782749Sdillon	mtx_lock(&Giant);
88887218Srwatson	error = 0;
88977183Srwatson	oldcred = p->p_ucred;
89077183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
89177183Srwatson	    rgid != oldcred->cr_svgid) ||
89277183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
89377183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
89487218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
89582749Sdillon		goto done2;
89677183Srwatson	newcred = crdup(oldcred);
89777183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
89877183Srwatson		change_egid(newcred, egid);
89931891Ssef		setsugid(p);
90024450Speter	}
90177183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
90277183Srwatson		change_rgid(newcred, rgid);
90331891Ssef		setsugid(p);
90424450Speter	}
90577183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
90677183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
90777183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
90831891Ssef		setsugid(p);
90924450Speter	}
91077812Sru	p->p_ucred = newcred;
91177812Sru	crfree(oldcred);
91282749Sdillondone2:
91382749Sdillon	mtx_unlock(&Giant);
91482749Sdillon	return (error);
9151541Srgrimes}
9161541Srgrimes
91756115Speter/*
91856115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
91956115Speter * saved uid is explicit.
92056115Speter */
92156115Speter
92224453Speter#ifndef _SYS_SYSPROTO_H_
92356115Speterstruct setresuid_args {
92456115Speter	uid_t	ruid;
92556115Speter	uid_t	euid;
92656115Speter	uid_t	suid;
92756115Speter};
92856115Speter#endif
92982749Sdillon/*
93082749Sdillon * MPSAFE
93182749Sdillon */
93256115Speter/* ARGSUSED */
93356115Speterint
93483366Sjuliansetresuid(td, uap)
93583366Sjulian	register struct thread *td;
93656115Speter	struct setresuid_args *uap;
93756115Speter{
93883366Sjulian	struct proc *p = td->td_proc;
93977183Srwatson	struct ucred *newcred, *oldcred;
94087218Srwatson	uid_t euid, ruid, suid;
94156115Speter	int error;
94256115Speter
94387218Srwatson	euid = uap->euid;
94456115Speter	ruid = uap->ruid;
94556115Speter	suid = uap->suid;
94682749Sdillon	mtx_lock(&Giant);
94777183Srwatson	oldcred = p->p_ucred;
94877183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
94977183Srwatson	     ruid != oldcred->cr_svuid &&
95077183Srwatson	      ruid != oldcred->cr_uid) ||
95177183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
95277183Srwatson	    euid != oldcred->cr_svuid &&
95377183Srwatson	      euid != oldcred->cr_uid) ||
95477183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
95577183Srwatson	    suid != oldcred->cr_svuid &&
95677183Srwatson	      suid != oldcred->cr_uid)) &&
95787218Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
95882749Sdillon		goto done2;
95977183Srwatson	newcred = crdup(oldcred);
96077183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
96177183Srwatson		change_euid(newcred, euid);
96256115Speter		setsugid(p);
96356115Speter	}
96477183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
96577183Srwatson		change_ruid(newcred, ruid);
96656115Speter		setsugid(p);
96756115Speter	}
96877183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
96977183Srwatson		change_svuid(newcred, suid);
97056115Speter		setsugid(p);
97156115Speter	}
97277183Srwatson	p->p_ucred = newcred;
97377183Srwatson	crfree(oldcred);
97482749Sdillon	error = 0;
97582749Sdillondone2:
97682749Sdillon	mtx_unlock(&Giant);
97782749Sdillon	return (error);
97856115Speter}
97956115Speter
98056115Speter/*
98156115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
98256115Speter * saved gid is explicit.
98356115Speter */
98456115Speter
98556115Speter#ifndef _SYS_SYSPROTO_H_
98656115Speterstruct setresgid_args {
98756115Speter	gid_t	rgid;
98856115Speter	gid_t	egid;
98956115Speter	gid_t	sgid;
99056115Speter};
99156115Speter#endif
99287466Srwatson/*
99382749Sdillon * MPSAFE
99482749Sdillon */
99556115Speter/* ARGSUSED */
99656115Speterint
99783366Sjuliansetresgid(td, uap)
99883366Sjulian	register struct thread *td;
99956115Speter	struct setresgid_args *uap;
100056115Speter{
100183366Sjulian	struct proc *p = td->td_proc;
100277183Srwatson	struct ucred *newcred, *oldcred;
100387218Srwatson	gid_t egid, rgid, sgid;
100456115Speter	int error;
100556115Speter
100687218Srwatson	egid = uap->egid;
100756115Speter	rgid = uap->rgid;
100856115Speter	sgid = uap->sgid;
100982749Sdillon	mtx_lock(&Giant);
101077183Srwatson	oldcred = p->p_ucred;
101177183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
101277183Srwatson	      rgid != oldcred->cr_svgid &&
101377183Srwatson	      rgid != oldcred->cr_groups[0]) ||
101477183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
101577183Srwatson	      egid != oldcred->cr_svgid &&
101677183Srwatson	      egid != oldcred->cr_groups[0]) ||
101777183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
101877183Srwatson	      sgid != oldcred->cr_svgid &&
101977183Srwatson	      sgid != oldcred->cr_groups[0])) &&
102087466Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
102182749Sdillon		goto done2;
102277183Srwatson	newcred = crdup(oldcred);
102377183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
102477183Srwatson		change_egid(newcred, egid);
102556115Speter		setsugid(p);
102656115Speter	}
102777183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
102877183Srwatson		change_rgid(newcred, rgid);
102956115Speter		setsugid(p);
103056115Speter	}
103177183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
103277183Srwatson		change_svgid(newcred, sgid);
103356115Speter		setsugid(p);
103456115Speter	}
103577183Srwatson	p->p_ucred = newcred;
103677183Srwatson	crfree(oldcred);
103782749Sdillon	error = 0;
103882749Sdillondone2:
103982749Sdillon	mtx_unlock(&Giant);
104082749Sdillon	return (error);
104156115Speter}
104256115Speter
104356115Speter#ifndef _SYS_SYSPROTO_H_
104456115Speterstruct getresuid_args {
104556115Speter	uid_t	*ruid;
104656115Speter	uid_t	*euid;
104756115Speter	uid_t	*suid;
104856115Speter};
104956115Speter#endif
105082749Sdillon/*
105182749Sdillon * MPSAFE
105282749Sdillon */
105356115Speter/* ARGSUSED */
105456115Speterint
105583366Sjuliangetresuid(td, uap)
105683366Sjulian	register struct thread *td;
105756115Speter	struct getresuid_args *uap;
105856115Speter{
105982749Sdillon	struct ucred *cred;
106083366Sjulian	struct proc *p = td->td_proc;
106156115Speter	int error1 = 0, error2 = 0, error3 = 0;
106256115Speter
106382749Sdillon	mtx_lock(&Giant);
106482749Sdillon	cred = p->p_ucred;
106556115Speter	if (uap->ruid)
106677183Srwatson		error1 = copyout((caddr_t)&cred->cr_ruid,
106777183Srwatson		    (caddr_t)uap->ruid, sizeof(cred->cr_ruid));
106856115Speter	if (uap->euid)
106977183Srwatson		error2 = copyout((caddr_t)&cred->cr_uid,
107077183Srwatson		    (caddr_t)uap->euid, sizeof(cred->cr_uid));
107156115Speter	if (uap->suid)
107277183Srwatson		error3 = copyout((caddr_t)&cred->cr_svuid,
107377183Srwatson		    (caddr_t)uap->suid, sizeof(cred->cr_svuid));
107482749Sdillon	mtx_unlock(&Giant);
107587218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
107656115Speter}
107756115Speter
107856115Speter#ifndef _SYS_SYSPROTO_H_
107956115Speterstruct getresgid_args {
108056115Speter	gid_t	*rgid;
108156115Speter	gid_t	*egid;
108256115Speter	gid_t	*sgid;
108356115Speter};
108456115Speter#endif
108582749Sdillon/*
108682749Sdillon * MPSAFE
108782749Sdillon */
108856115Speter/* ARGSUSED */
108956115Speterint
109083366Sjuliangetresgid(td, uap)
109183366Sjulian	register struct thread *td;
109256115Speter	struct getresgid_args *uap;
109356115Speter{
109482749Sdillon	struct ucred *cred;
109583366Sjulian	struct proc *p = td->td_proc;
109656115Speter	int error1 = 0, error2 = 0, error3 = 0;
109756115Speter
109882749Sdillon	mtx_lock(&Giant);
109982749Sdillon	cred = p->p_ucred;
110056115Speter	if (uap->rgid)
110177183Srwatson		error1 = copyout((caddr_t)&cred->cr_rgid,
110277183Srwatson		    (caddr_t)uap->rgid, sizeof(cred->cr_rgid));
110356115Speter	if (uap->egid)
110477183Srwatson		error2 = copyout((caddr_t)&cred->cr_groups[0],
110577183Srwatson		    (caddr_t)uap->egid, sizeof(cred->cr_groups[0]));
110656115Speter	if (uap->sgid)
110777183Srwatson		error3 = copyout((caddr_t)&cred->cr_svgid,
110877183Srwatson		    (caddr_t)uap->sgid, sizeof(cred->cr_svgid));
110982749Sdillon	mtx_unlock(&Giant);
111087218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
111156115Speter}
111256115Speter
111356115Speter#ifndef _SYS_SYSPROTO_H_
111424453Speterstruct issetugid_args {
111524453Speter	int dummy;
111624453Speter};
111724453Speter#endif
111887218Srwatson/*
111987218Srwatson * NOT MPSAFE?
112087218Srwatson */
112124453Speter/* ARGSUSED */
112224453Speterint
112383366Sjulianissetugid(td, uap)
112483366Sjulian	register struct thread *td;
112524453Speter	struct issetugid_args *uap;
112624453Speter{
112783366Sjulian	struct proc *p = td->td_proc;
112883366Sjulian
112924453Speter	/*
113024453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
113124453Speter	 * we use P_SUGID because we consider changing the owners as
113224453Speter	 * "tainting" as well.
113324453Speter	 * This is significant for procs that start as root and "become"
113424453Speter	 * a user without an exec - programs cannot know *everything*
113524453Speter	 * that libc *might* have put in their data segment.
113624453Speter	 */
113783366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
113824453Speter	return (0);
113924453Speter}
114024453Speter
114182749Sdillon/*
114282749Sdillon * MPSAFE
114382749Sdillon */
114475426Srwatsonint
114583366Sjulian__setugid(td, uap)
114683366Sjulian	struct thread *td;
114775426Srwatson	struct __setugid_args *uap;
114875426Srwatson{
114982749Sdillon#ifdef REGRESSION
115087218Srwatson	int error;
115175426Srwatson
115282749Sdillon	mtx_lock(&Giant);
115387218Srwatson	error = 0;
115475426Srwatson	switch (uap->flag) {
115575426Srwatson	case 0:
115683366Sjulian		td->td_proc->p_flag &= ~P_SUGID;
115782749Sdillon		break;
115875426Srwatson	case 1:
115983366Sjulian		td->td_proc->p_flag |= P_SUGID;
116082749Sdillon		break;
116175426Srwatson	default:
116282749Sdillon		error = EINVAL;
116382749Sdillon		break;
116475426Srwatson	}
116582749Sdillon	mtx_unlock(&Giant);
116682749Sdillon	return (error);
116775426Srwatson#else /* !REGRESSION */
116887218Srwatson
116975426Srwatson	return (ENOSYS);
117087218Srwatson#endif /* REGRESSION */
117175426Srwatson}
117275426Srwatson
11731541Srgrimes/*
11741541Srgrimes * Check if gid is a member of the group set.
11751541Srgrimes */
11761549Srgrimesint
11771541Srgrimesgroupmember(gid, cred)
11781541Srgrimes	gid_t gid;
117977183Srwatson	struct ucred *cred;
11801541Srgrimes{
11811541Srgrimes	register gid_t *gp;
11821541Srgrimes	gid_t *egp;
11831541Srgrimes
11841541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
11851541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
11861541Srgrimes		if (*gp == gid)
11871541Srgrimes			return (1);
11881541Srgrimes	return (0);
11891541Srgrimes}
11901541Srgrimes
119182424Srwatson/*
119289414Sarr * `suser_enabled' (which can be set by the security.suser_enabled
119382466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect.
119482466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege,
119582466Srwatson * overriding many mandatory and discretionary protections.  If it is zero,
119682466Srwatson * uid 0 is offered no special privilege in the kernel security policy.
119782466Srwatson * Setting it to zero may seriously impact the functionality of many
119882466Srwatson * existing userland programs, and should not be done without careful
119982466Srwatson * consideration of the consequences.
120082424Srwatson */
120182693Srwatsonint	suser_enabled = 1;
120289414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW,
120382693Srwatson    &suser_enabled, 0, "processes with uid 0 have privilege");
120489414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled);
120561287Srwatson
12061541Srgrimes/*
120782466Srwatson * Test whether the specified credentials imply "super-user" privilege.
120882466Srwatson * Return 0 or EPERM.
12091541Srgrimes */
12101549Srgrimesint
121146112Sphksuser(p)
121272786Srwatson	struct proc *p;
121346112Sphk{
121487218Srwatson
121587218Srwatson	return (suser_xxx(0, p, 0));
121646112Sphk}
121746112Sphk
121883366Sjulian/*
121983366Sjulian * version for when the thread pointer is available and not the proc.
122083366Sjulian * (saves having to include proc.h into every file that needs to do the change.)
122183366Sjulian */
122246112Sphkint
122383366Sjuliansuser_td(td)
122483366Sjulian	struct thread *td;
122583366Sjulian{
122687466Srwatson	return (suser_xxx(0, td->td_proc, 0));
122783366Sjulian}
122883366Sjulian
122983366Sjulian/*
123083366Sjulian * wrapper to use if you have the thread on hand but not the proc.
123183366Sjulian */
123283366Sjulianint
123383366Sjuliansuser_xxx_td(cred, td, flag)
123483366Sjulian	struct ucred *cred;
123583366Sjulian	struct thread *td;
123683366Sjulian	int flag;
123783366Sjulian{
123883366Sjulian	return(suser_xxx(cred, td->td_proc, flag));
123983366Sjulian}
124083366Sjulian
124183366Sjulianint
124246155Sphksuser_xxx(cred, proc, flag)
124372786Srwatson	struct ucred *cred;
124472786Srwatson	struct proc *proc;
124546155Sphk	int flag;
12461541Srgrimes{
124782693Srwatson	if (!suser_enabled)
124861282Srwatson		return (EPERM);
124946155Sphk	if (!cred && !proc) {
125046155Sphk		printf("suser_xxx(): THINK!\n");
125146155Sphk		return (EPERM);
12521541Srgrimes	}
125387218Srwatson	if (cred == NULL)
125446155Sphk		cred = proc->p_ucred;
125587218Srwatson	if (cred->cr_uid != 0)
125646155Sphk		return (EPERM);
125772786Srwatson	if (jailed(cred) && !(flag & PRISON_ROOT))
125846155Sphk		return (EPERM);
125946155Sphk	return (0);
12601541Srgrimes}
12611541Srgrimes
126283639Srwatson/*
126387218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
126487218Srwatson * implements (securelevel > level).  securelevel_ge() implements
126587218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
126687218Srwatson * functions return EPERM on "success" and 0 on "failure".
126783639Srwatson *
126883639Srwatson * cr is permitted to be NULL for the time being, as there were some
126983639Srwatson * existing securelevel checks that occurred without a process/credential
127087218Srwatson * context.  In the future this will be disallowed, so a kernel message
127187218Srwatson * is displayed.
127283639Srwatson */
127383639Srwatsonint
127483639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
127583639Srwatson{
127687218Srwatson	int active_securelevel;
127783639Srwatson
127887218Srwatson	active_securelevel = securelevel;
127987218Srwatson	if (cr == NULL)
128083639Srwatson		printf("securelevel_gt: cr is NULL\n");
128187275Srwatson	if (cr->cr_prison != NULL) {
128287275Srwatson		mtx_lock(&cr->cr_prison->pr_mtx);
128387218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
128487218Srwatson		    active_securelevel);
128587275Srwatson		mtx_unlock(&cr->cr_prison->pr_mtx);
128687275Srwatson	}
128787218Srwatson	return (active_securelevel > level ? EPERM : 0);
128883639Srwatson}
128983639Srwatson
129083639Srwatsonint
129183639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
129283639Srwatson{
129387218Srwatson	int active_securelevel;
129483639Srwatson
129587218Srwatson	active_securelevel = securelevel;
129687218Srwatson	if (cr == NULL)
129787218Srwatson		printf("securelevel_gt: cr is NULL\n");
129887275Srwatson	if (cr->cr_prison != NULL) {
129987275Srwatson		mtx_lock(&cr->cr_prison->pr_mtx);
130087218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
130187218Srwatson		    active_securelevel);
130287275Srwatson		mtx_unlock(&cr->cr_prison->pr_mtx);
130387275Srwatson	}
130487218Srwatson	return (active_securelevel >= level ? EPERM : 0);
130583639Srwatson}
130683639Srwatson
130784736Srwatson/*
130887144Srwatson * 'see_other_uids' determines whether or not visibility of processes
130987218Srwatson * and sockets with credentials holding different real uids is possible
131087138Srwatson * using a variety of system MIBs.
131187218Srwatson * XXX: data declarations should be together near the beginning of the file.
131284736Srwatson */
131387144Srwatsonstatic int	see_other_uids = 1;
131489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
131587218Srwatson    &see_other_uids, 0,
131684736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
131784736Srwatson
131882466Srwatson/*-
131982466Srwatson * Determine if u1 "can see" the subject specified by u2.
132074956Srwatson * Returns: 0 for permitted, an errno value otherwise
132174956Srwatson * Locks: none
132287218Srwatson * References: *u1 and *u2 must not change during the call
132374956Srwatson *             u1 may equal u2, in which case only one reference is required
132474956Srwatson */
132574956Srwatsonint
132683742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
132765237Srwatson{
132872786Srwatson	int error;
132953518Sphk
133074956Srwatson	if ((error = prison_check(u1, u2)))
133172786Srwatson		return (error);
133287144Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
133375005Srwatson		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
133474956Srwatson			return (ESRCH);
133565293Srwatson	}
133665237Srwatson	return (0);
133765237Srwatson}
133865237Srwatson
133982466Srwatson/*-
134082466Srwatson * Determine if p1 "can see" the subject specified by p2.
134182424Srwatson * Returns: 0 for permitted, an errno value otherwise
134282466Srwatson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must
134382424Srwatson *        be held.  Normally, p1 will be curproc, and a lock must be held
134482424Srwatson *        for p2.
134582424Srwatson * References: p1 and p2 must be valid for the lifetime of the call
134682424Srwatson */
134779335Srwatsonint
134879335Srwatsonp_cansee(struct proc *p1, struct proc *p2)
134974956Srwatson{
135074956Srwatson
135183742Srwatson	/* Wrap cr_cansee() for all functionality. */
135283742Srwatson	return (cr_cansee(p1->p_ucred, p2->p_ucred));
135374956Srwatson}
135474956Srwatson
135582466Srwatson/*-
135688943Srwatson * Determine whether cred may deliver the specified signal to proc.
135788943Srwatson * Returns: 0 for permitted, an errno value otherwise.
135888943Srwatson * Locks: A lock must be held for proc.
135988943Srwatson * References: cred and proc must be valid for the lifetime of the call.
136075437Srwatson */
136175437Srwatsonint
136288943Srwatsoncr_cansignal(struct ucred *cred, struct proc *proc, int signum)
136353518Sphk{
136482466Srwatson	int error;
136584826Sjhb
136675437Srwatson	/*
136788943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
136888943Srwatson	 * same jail as cred, if cred is in jail.
136975437Srwatson	 */
137088943Srwatson	error = prison_check(cred, proc->p_ucred);
137188943Srwatson	if (error)
137272786Srwatson		return (error);
137365237Srwatson
137465237Srwatson	/*
137582424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
137682424Srwatson	 * bit on the target process.  If the bit is set, then additional
137782424Srwatson	 * restrictions are placed on the set of available signals.
137875437Srwatson	 */
137988943Srwatson	if (proc->p_flag & P_SUGID) {
138075437Srwatson		switch (signum) {
138175437Srwatson		case 0:
138275437Srwatson		case SIGKILL:
138375437Srwatson		case SIGINT:
138475437Srwatson		case SIGTERM:
138575437Srwatson		case SIGSTOP:
138675437Srwatson		case SIGTTIN:
138775437Srwatson		case SIGTTOU:
138875437Srwatson		case SIGTSTP:
138975437Srwatson		case SIGHUP:
139075437Srwatson		case SIGUSR1:
139175437Srwatson		case SIGUSR2:
139282466Srwatson			/*
139382466Srwatson			 * Generally, permit job and terminal control
139482466Srwatson			 * signals.
139582466Srwatson			 */
139675437Srwatson			break;
139775437Srwatson		default:
139888943Srwatson			/* Not permitted without privilege. */
139988943Srwatson			error = suser_xxx(cred, NULL, PRISON_ROOT);
140075437Srwatson			if (error)
140175437Srwatson				return (error);
140275437Srwatson		}
140365237Srwatson	}
140465237Srwatson
140575480Srwatson	/*
140682424Srwatson	 * Generally, the target credential's ruid or svuid must match the
140775480Srwatson	 * subject credential's ruid or euid.
140875480Srwatson	 */
140988943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
141088943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
141188943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
141288943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
141388943Srwatson		/* Not permitted without privilege. */
141488943Srwatson		error = suser_xxx(cred, NULL, PRISON_ROOT);
141575480Srwatson		if (error)
141675480Srwatson			return (error);
141775480Srwatson	}
141875480Srwatson
141987218Srwatson	return (0);
142053518Sphk}
142153518Sphk
142288943Srwatson
142382466Srwatson/*-
142488943Srwatson * Determine whether p1 may deliver the specified signal to p2.
142588943Srwatson * Returns: 0 for permitted, an errno value otherwise
142688943Srwatson * Locks: Sufficient locks to protect various components of p1 and p2
142788943Srwatson *        must be held.  Normally, p1 will be curproc, and a lock must
142888943Srwatson *        be held for p2.
142988943Srwatson * References: p1 and p2 must be valid for the lifetime of the call
143088943Srwatson */
143188943Srwatsonint
143288943Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum)
143388943Srwatson{
143488943Srwatson
143588943Srwatson	if (p1 == p2)
143688943Srwatson		return (0);
143788943Srwatson
143888943Srwatson	/*
143988943Srwatson	 * UNIX signalling semantics require that processes in the same
144088943Srwatson	 * session always be able to deliver SIGCONT to one another,
144188943Srwatson	 * overriding the remaining protections.
144288943Srwatson	 */
144388943Srwatson	if (signum == SIGCONT && p1->p_session == p2->p_session)
144488943Srwatson		return (0);
144588943Srwatson
144688943Srwatson	return (cr_cansignal(p1->p_ucred, p2, signum));
144788943Srwatson}
144888943Srwatson
144988943Srwatson/*-
145087218Srwatson * Determine whether p1 may reschedule p2.
145182466Srwatson * Returns: 0 for permitted, an errno value otherwise
145282424Srwatson * Locks: Sufficient locks to protect various components of p1 and p2
145382424Srwatson *        must be held.  Normally, p1 will be curproc, and a lock must
145482466Srwatson *        be held for p2.
145582424Srwatson * References: p1 and p2 must be valid for the lifetime of the call
145682424Srwatson */
145779335Srwatsonint
145879335Srwatsonp_cansched(struct proc *p1, struct proc *p2)
145965237Srwatson{
146072786Srwatson	int error;
146165237Srwatson
146265237Srwatson	if (p1 == p2)
146365237Srwatson		return (0);
146472786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
146572786Srwatson		return (error);
146677183Srwatson	if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid)
146765237Srwatson		return (0);
146877183Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid)
146965237Srwatson		return (0);
147082466Srwatson	if (suser_xxx(0, p1, PRISON_ROOT) == 0)
147165237Srwatson		return (0);
147265237Srwatson
147365237Srwatson#ifdef CAPABILITIES
147485874Srwatson	if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT))
147565237Srwatson		return (0);
147665237Srwatson#endif
147765237Srwatson
147865237Srwatson	return (EPERM);
147965237Srwatson}
148065237Srwatson
148182424Srwatson/*
148287280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
148387280Srwatson * unprivileged inter-process debugging services, including some procfs
148487280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
148587280Srwatson * debugging has been involved in a variety of security problems, and sites
148687280Srwatson * not requiring the service might choose to disable it when hardening
148787280Srwatson * systems.
148882424Srwatson *
148982424Srwatson * XXX: Should modifying and reading this variable require locking?
149087218Srwatson * XXX: data declarations should be together near the beginning of the file.
149182424Srwatson */
149287144Srwatsonstatic int	unprivileged_proc_debug = 1;
149389414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
149487218Srwatson    &unprivileged_proc_debug, 0,
149580735Srwatson    "Unprivileged processes may use process debugging facilities");
149680735Srwatson
149782466Srwatson/*-
149882466Srwatson * Determine whether p1 may debug p2.
149982466Srwatson * Returns: 0 for permitted, an errno value otherwise
150082466Srwatson * Locks: Sufficient locks to protect various components of p1 and p2
150182466Srwatson *        must be held.  Normally, p1 will be curproc, and a lock must
150282466Srwatson *        be held for p2.
150382424Srwatson * References: p1 and p2 must be valid for the lifetime of the call
150482424Srwatson */
150579335Srwatsonint
150679335Srwatsonp_candebug(struct proc *p1, struct proc *p2)
150765237Srwatson{
150887218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
150965237Srwatson
151087144Srwatson	if (!unprivileged_proc_debug) {
151184727Srwatson		error = suser_xxx(NULL, p1, PRISON_ROOT);
151284727Srwatson		if (error)
151384727Srwatson			return (error);
151484727Srwatson	}
151584636Sdes	if (p1 == p2)
151684636Sdes		return (0);
151772786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
151872786Srwatson		return (error);
151965237Srwatson
152082466Srwatson	/*
152185895Srwatson	 * Is p2's group set a subset of p1's effective group set?  This
152285895Srwatson	 * includes p2's egid, group access list, rgid, and svgid.
152382466Srwatson	 */
152485895Srwatson	grpsubset = 1;
152585895Srwatson	for (i = 0; i < p2->p_ucred->cr_ngroups; i++) {
152685895Srwatson		if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) {
152785895Srwatson			grpsubset = 0;
152885895Srwatson			break;
152985895Srwatson		}
153085895Srwatson	}
153185895Srwatson	grpsubset = grpsubset &&
153285895Srwatson	    groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) &&
153385895Srwatson	    groupmember(p2->p_ucred->cr_svgid, p1->p_ucred);
153485895Srwatson
153585895Srwatson	/*
153685895Srwatson	 * Are the uids present in p2's credential equal to p1's
153785895Srwatson	 * effective uid?  This includes p2's euid, svuid, and ruid.
153885895Srwatson	 */
153985895Srwatson	uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid &&
154085895Srwatson	    p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid &&
154185895Srwatson	    p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid);
154285895Srwatson
154385895Srwatson	/*
154485895Srwatson	 * Has the credential of the process changed since the last exec()?
154585895Srwatson	 */
154685895Srwatson	credentialchanged = (p2->p_flag & P_SUGID);
154785895Srwatson
154885895Srwatson	/*
154985895Srwatson	 * If p2's gids aren't a subset, or the uids aren't a subset,
155085895Srwatson	 * or the credential has changed, require appropriate privilege
155185895Srwatson	 * for p1 to debug p2.  For POSIX.1e capabilities, this will
155285895Srwatson	 * require CAP_SYS_PTRACE.
155385895Srwatson	 */
155485895Srwatson	if (!grpsubset || !uidsubset || credentialchanged) {
155584727Srwatson		error = suser_xxx(NULL, p1, PRISON_ROOT);
155684727Srwatson		if (error)
155765237Srwatson			return (error);
155882466Srwatson	}
155965237Srwatson
156087218Srwatson	/* Can't trace init when securelevel > 0. */
156187218Srwatson	if (p2 == initproc) {
156283639Srwatson		error = securelevel_gt(p1->p_ucred, 0);
156383639Srwatson		if (error)
156483639Srwatson			return (error);
156583639Srwatson	}
156665237Srwatson
156785880Srwatson	/*
156885880Srwatson	 * Can't trace a process that's currently exec'ing.
156985880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
157085880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
157185880Srwatson	 * should be moved to the caller's of p_candebug().
157285880Srwatson	 */
157385598Sdes	if ((p2->p_flag & P_INEXEC) != 0)
157485598Sdes		return (EAGAIN);
157587466Srwatson
157665237Srwatson	return (0);
157765237Srwatson}
157865237Srwatson
157953518Sphk/*
15801541Srgrimes * Allocate a zeroed cred structure.
15811541Srgrimes */
15821541Srgrimesstruct ucred *
15831541Srgrimescrget()
15841541Srgrimes{
15851541Srgrimes	register struct ucred *cr;
15861541Srgrimes
158784826Sjhb	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
15881541Srgrimes	cr->cr_ref = 1;
158969239Salfred	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
15901541Srgrimes	return (cr);
15911541Srgrimes}
15921541Srgrimes
15931541Srgrimes/*
159482466Srwatson * Claim another reference to a ucred structure.
159569401Salfred */
159684827Sjhbstruct ucred *
159769401Salfredcrhold(cr)
159869401Salfred	struct ucred *cr;
159969401Salfred{
160069401Salfred
160172200Sbmilekic	mtx_lock(&cr->cr_mtx);
160269401Salfred	cr->cr_ref++;
160384827Sjhb	mtx_unlock(&cr->cr_mtx);
160484827Sjhb	return (cr);
160569401Salfred}
160669401Salfred
160769401Salfred/*
16081541Srgrimes * Free a cred structure.
16091541Srgrimes * Throws away space when ref count gets to 0.
16101541Srgrimes */
16111549Srgrimesvoid
16121541Srgrimescrfree(cr)
16131541Srgrimes	struct ucred *cr;
16141541Srgrimes{
161569239Salfred
161672200Sbmilekic	mtx_lock(&cr->cr_mtx);
161775632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
161865495Struckman	if (--cr->cr_ref == 0) {
161969239Salfred		mtx_destroy(&cr->cr_mtx);
162065495Struckman		/*
162165495Struckman		 * Some callers of crget(), such as nfs_statfs(),
162265495Struckman		 * allocate a temporary credential, but don't
162365495Struckman		 * allocate a uidinfo structure.
162465495Struckman		 */
162565495Struckman		if (cr->cr_uidinfo != NULL)
162665495Struckman			uifree(cr->cr_uidinfo);
162777277Srwatson		if (cr->cr_ruidinfo != NULL)
162877277Srwatson			uifree(cr->cr_ruidinfo);
162972786Srwatson		/*
163072786Srwatson		 * Free a prison, if any.
163172786Srwatson		 */
163272786Srwatson		if (jailed(cr))
163372786Srwatson			prison_free(cr->cr_prison);
16341541Srgrimes		FREE((caddr_t)cr, M_CRED);
163587218Srwatson	} else
163672200Sbmilekic		mtx_unlock(&cr->cr_mtx);
16371541Srgrimes}
16381541Srgrimes
16391541Srgrimes/*
164084827Sjhb * Check to see if this ucred is shared.
16411541Srgrimes */
164284827Sjhbint
164384827Sjhbcrshared(cr)
16441541Srgrimes	struct ucred *cr;
16451541Srgrimes{
164684827Sjhb	int shared;
16471541Srgrimes
164872200Sbmilekic	mtx_lock(&cr->cr_mtx);
164984827Sjhb	shared = (cr->cr_ref > 1);
165072200Sbmilekic	mtx_unlock(&cr->cr_mtx);
165184827Sjhb	return (shared);
16521541Srgrimes}
16531541Srgrimes
16541541Srgrimes/*
165584827Sjhb * Copy a ucred's contents from a template.  Does not block.
165684827Sjhb */
165784827Sjhbvoid
165884827Sjhbcrcopy(dest, src)
165984827Sjhb	struct ucred *dest, *src;
166084827Sjhb{
166184827Sjhb
166284827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
166384827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
166487218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
166584827Sjhb		(caddr_t)&src->cr_startcopy));
166684827Sjhb	uihold(dest->cr_uidinfo);
166784827Sjhb	uihold(dest->cr_ruidinfo);
166884827Sjhb	if (jailed(dest))
166984827Sjhb		prison_hold(dest->cr_prison);
167084827Sjhb}
167184827Sjhb
167284827Sjhb/*
16731541Srgrimes * Dup cred struct to a new held one.
16741541Srgrimes */
16751541Srgrimesstruct ucred *
16761541Srgrimescrdup(cr)
16771541Srgrimes	struct ucred *cr;
16781541Srgrimes{
16791541Srgrimes	struct ucred *newcr;
16801541Srgrimes
168184827Sjhb	newcr = crget();
168284827Sjhb	crcopy(newcr, cr);
16831541Srgrimes	return (newcr);
16841541Srgrimes}
16851541Srgrimes
16861541Srgrimes/*
16871541Srgrimes * Get login name, if available.
16881541Srgrimes */
168912221Sbde#ifndef _SYS_SYSPROTO_H_
16901541Srgrimesstruct getlogin_args {
16911541Srgrimes	char	*namebuf;
16921541Srgrimes	u_int	namelen;
16931541Srgrimes};
169412221Sbde#endif
169582749Sdillon/*
169682749Sdillon * MPSAFE
169782749Sdillon */
16981541Srgrimes/* ARGSUSED */
16991549Srgrimesint
170083366Sjuliangetlogin(td, uap)
170183366Sjulian	struct thread *td;
17021541Srgrimes	struct getlogin_args *uap;
17031541Srgrimes{
170482749Sdillon	int error;
170583366Sjulian	struct proc *p = td->td_proc;
17061541Srgrimes
170782749Sdillon	mtx_lock(&Giant);
170823358Sache	if (uap->namelen > MAXLOGNAME)
170923359Sache		uap->namelen = MAXLOGNAME;
171082749Sdillon	error = copyout((caddr_t) p->p_pgrp->pg_session->s_login,
171182749Sdillon	    (caddr_t) uap->namebuf, uap->namelen);
171282749Sdillon	mtx_unlock(&Giant);
171382749Sdillon	return(error);
17141541Srgrimes}
17151541Srgrimes
17161541Srgrimes/*
17171541Srgrimes * Set login name.
17181541Srgrimes */
171912221Sbde#ifndef _SYS_SYSPROTO_H_
17201541Srgrimesstruct setlogin_args {
17211541Srgrimes	char	*namebuf;
17221541Srgrimes};
172312221Sbde#endif
172482749Sdillon/*
172582749Sdillon * MPSAFE
172682749Sdillon */
17271541Srgrimes/* ARGSUSED */
17281549Srgrimesint
172983366Sjuliansetlogin(td, uap)
173083366Sjulian	struct thread *td;
17311541Srgrimes	struct setlogin_args *uap;
17321541Srgrimes{
173383366Sjulian	struct proc *p = td->td_proc;
17341541Srgrimes	int error;
173523330Sache	char logintmp[MAXLOGNAME];
17361541Srgrimes
173782749Sdillon	mtx_lock(&Giant);
173887218Srwatson	if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0)
173982749Sdillon		goto done2;
174022522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
174136845Sdfr	    sizeof(logintmp), (size_t *)0);
174287218Srwatson	if (error == ENAMETOOLONG)
17431541Srgrimes		error = EINVAL;
174487218Srwatson	else if (!error)
174587218Srwatson		(void)memcpy(p->p_pgrp->pg_session->s_login, logintmp,
174623330Sache		    sizeof(logintmp));
174782749Sdillondone2:
174882749Sdillon	mtx_unlock(&Giant);
17491541Srgrimes	return (error);
17501541Srgrimes}
175131891Ssef
175231891Ssefvoid
175331891Ssefsetsugid(p)
175455338Sphk	struct proc *p;
175531891Ssef{
175631891Ssef	p->p_flag |= P_SUGID;
175755707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
175831891Ssef		p->p_stops = 0;
175931891Ssef}
176065495Struckman
176182466Srwatson/*-
176282466Srwatson * Change a process's effective uid.
176377183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
176477183Srwatson * References: newcred must be an exclusive credential reference for the
176577183Srwatson *             duration of the call.
176665495Struckman */
176765495Struckmanvoid
176877183Srwatsonchange_euid(newcred, euid)
176977183Srwatson	struct ucred *newcred;
177077183Srwatson	uid_t euid;
177165495Struckman{
177265495Struckman
177377183Srwatson	newcred->cr_uid = euid;
177477183Srwatson	uifree(newcred->cr_uidinfo);
177577183Srwatson	newcred->cr_uidinfo = uifind(euid);
177665495Struckman}
177765495Struckman
177882466Srwatson/*-
177982466Srwatson * Change a process's effective gid.
178077183Srwatson * Side effects: newcred->cr_gid will be modified.
178177183Srwatson * References: newcred must be an exclusive credential reference for the
178277183Srwatson *             duration of the call.
178365495Struckman */
178467629Sgallatinvoid
178577183Srwatsonchange_egid(newcred, egid)
178677183Srwatson	struct ucred *newcred;
178777183Srwatson	gid_t egid;
178865495Struckman{
178965495Struckman
179077183Srwatson	newcred->cr_groups[0] = egid;
179165495Struckman}
179277183Srwatson
179382466Srwatson/*-
179482466Srwatson * Change a process's real uid.
179577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
179677183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
179777183Srwatson *               counts will be updated.
179877183Srwatson * References: newcred must be an exclusive credential reference for the
179977183Srwatson *             duration of the call.
180077183Srwatson */
180177183Srwatsonvoid
180277183Srwatsonchange_ruid(newcred, ruid)
180377183Srwatson	struct ucred *newcred;
180477183Srwatson	uid_t ruid;
180577183Srwatson{
180677183Srwatson
180777183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
180877183Srwatson	newcred->cr_ruid = ruid;
180977183Srwatson	uifree(newcred->cr_ruidinfo);
181077183Srwatson	newcred->cr_ruidinfo = uifind(ruid);
181177183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
181277183Srwatson}
181377183Srwatson
181482466Srwatson/*-
181582466Srwatson * Change a process's real gid.
181677183Srwatson * Side effects: newcred->cr_rgid will be updated.
181777183Srwatson * References: newcred must be an exclusive credential reference for the
181877183Srwatson *             duration of the call.
181977183Srwatson */
182077183Srwatsonvoid
182177183Srwatsonchange_rgid(newcred, rgid)
182277183Srwatson	struct ucred *newcred;
182377183Srwatson	gid_t rgid;
182477183Srwatson{
182577183Srwatson
182677183Srwatson	newcred->cr_rgid = rgid;
182777183Srwatson}
182877183Srwatson
182982466Srwatson/*-
183082466Srwatson * Change a process's saved uid.
183177183Srwatson * Side effects: newcred->cr_svuid will be updated.
183277183Srwatson * References: newcred must be an exclusive credential reference for the
183377183Srwatson *             duration of the call.
183477183Srwatson */
183577183Srwatsonvoid
183677183Srwatsonchange_svuid(newcred, svuid)
183777183Srwatson	struct ucred *newcred;
183877183Srwatson	uid_t svuid;
183977183Srwatson{
184077183Srwatson
184177183Srwatson	newcred->cr_svuid = svuid;
184277183Srwatson}
184377183Srwatson
184482466Srwatson/*-
184582466Srwatson * Change a process's saved gid.
184677183Srwatson * Side effects: newcred->cr_svgid will be updated.
184777183Srwatson * References: newcred must be an exclusive credential reference for the
184877183Srwatson *             duration of the call.
184977183Srwatson */
185077183Srwatsonvoid
185177183Srwatsonchange_svgid(newcred, svgid)
185277183Srwatson	struct ucred *newcred;
185377183Srwatson	gid_t svgid;
185477183Srwatson{
185577183Srwatson
185677183Srwatson	newcred->cr_svgid = svgid;
185777183Srwatson}
1858