kern_prot.c revision 75426
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.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
3950477Speter * $FreeBSD: head/sys/kern/kern_prot.c 75426 2001-04-11 20:20:40Z rwatson $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
4631778Seivind#include "opt_compat.h"
4775426Srwatson#include "opt_global.h"
4831778Seivind
491541Srgrimes#include <sys/param.h>
501541Srgrimes#include <sys/acct.h>
511541Srgrimes#include <sys/systm.h>
5212221Sbde#include <sys/sysproto.h>
5341059Speter#include <sys/kernel.h>
5470317Sjake#include <sys/lock.h>
551541Srgrimes#include <sys/proc.h>
561541Srgrimes#include <sys/malloc.h>
5731891Ssef#include <sys/pioctl.h>
5865495Struckman#include <sys/resourcevar.h>
5961287Srwatson#include <sys/sysctl.h>
6072786Srwatson#include <sys/jail.h>
611541Srgrimes
6230354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6330354Sphk
6412221Sbde#ifndef _SYS_SYSPROTO_H_
6511332Sswallacestruct getpid_args {
661541Srgrimes	int	dummy;
671541Srgrimes};
6812221Sbde#endif
691541Srgrimes
7058717Sdillon/*
7170317Sjake * getpid - MP SAFE
7258717Sdillon */
7370317Sjake
741541Srgrimes/* ARGSUSED */
751549Srgrimesint
7630994Sphkgetpid(p, uap)
771541Srgrimes	struct proc *p;
7811332Sswallace	struct getpid_args *uap;
791541Srgrimes{
801541Srgrimes
8130994Sphk	p->p_retval[0] = p->p_pid;
821541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8374728Sjhb	PROC_LOCK(p);
8430994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
8574728Sjhb	PROC_UNLOCK(p);
861541Srgrimes#endif
871541Srgrimes	return (0);
881541Srgrimes}
891541Srgrimes
9070317Sjake/*
9170317Sjake * getppid - MP SAFE
9270317Sjake */
9370317Sjake
9412221Sbde#ifndef _SYS_SYSPROTO_H_
9511332Sswallacestruct getppid_args {
9611332Sswallace        int     dummy;
9711332Sswallace};
9812221Sbde#endif
991541Srgrimes/* ARGSUSED */
1001549Srgrimesint
10130994Sphkgetppid(p, uap)
1021541Srgrimes	struct proc *p;
10311332Sswallace	struct getppid_args *uap;
1041541Srgrimes{
1051541Srgrimes
10674728Sjhb	PROC_LOCK(p);
10730994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
10874728Sjhb	PROC_UNLOCK(p);
1091541Srgrimes	return (0);
1101541Srgrimes}
1111541Srgrimes
11258717Sdillon/*
11358717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter
11458717Sdillon *
11558717Sdillon * MP SAFE
11658717Sdillon */
11712221Sbde#ifndef _SYS_SYSPROTO_H_
11811332Sswallacestruct getpgrp_args {
11911332Sswallace        int     dummy;
12011332Sswallace};
12112221Sbde#endif
12211332Sswallace
1231549Srgrimesint
12430994Sphkgetpgrp(p, uap)
1251541Srgrimes	struct proc *p;
12611332Sswallace	struct getpgrp_args *uap;
1271541Srgrimes{
1281541Srgrimes
12930994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1301541Srgrimes	return (0);
1311541Srgrimes}
1321541Srgrimes
13328401Speter/* Get an arbitary pid's process group id */
13412221Sbde#ifndef _SYS_SYSPROTO_H_
13528401Speterstruct getpgid_args {
13628401Speter	pid_t	pid;
13728401Speter};
13828401Speter#endif
13928401Speter
14028401Speterint
14130994Sphkgetpgid(p, uap)
14228401Speter	struct proc *p;
14328401Speter	struct getpgid_args *uap;
14428401Speter{
14541726Struckman	struct proc *pt;
14641726Struckman
14741726Struckman	pt = p;
14828401Speter	if (uap->pid == 0)
14928401Speter		goto found;
15028401Speter
15141726Struckman	if ((pt = pfind(uap->pid)) == 0)
15228401Speter		return ESRCH;
15328401Speterfound:
15441726Struckman	p->p_retval[0] = pt->p_pgrp->pg_id;
15528401Speter	return 0;
15628401Speter}
15728401Speter
15828401Speter/*
15928401Speter * Get an arbitary pid's session id.
16028401Speter */
16128401Speter#ifndef _SYS_SYSPROTO_H_
16228401Speterstruct getsid_args {
16328401Speter	pid_t	pid;
16428401Speter};
16528401Speter#endif
16628401Speter
16728401Speterint
16830994Sphkgetsid(p, uap)
16928401Speter	struct proc *p;
17028401Speter	struct getsid_args *uap;
17128401Speter{
17241726Struckman	struct proc *pt;
17341726Struckman
17441726Struckman	pt = p;
17528401Speter	if (uap->pid == 0)
17628401Speter		goto found;
17728401Speter
17871002Sben	if ((pt = pfind(uap->pid)) == 0)
17928401Speter		return ESRCH;
18028401Speterfound:
18141726Struckman	p->p_retval[0] = pt->p_session->s_sid;
18228401Speter	return 0;
18328401Speter}
18428401Speter
18528401Speter
18658941Sdillon/*
18758941Sdillon * getuid() - MP SAFE
18858941Sdillon */
18928401Speter#ifndef _SYS_SYSPROTO_H_
19011332Sswallacestruct getuid_args {
19111332Sswallace        int     dummy;
19211332Sswallace};
19312221Sbde#endif
19411332Sswallace
1951541Srgrimes/* ARGSUSED */
1961549Srgrimesint
19730994Sphkgetuid(p, uap)
1981541Srgrimes	struct proc *p;
19911332Sswallace	struct getuid_args *uap;
2001541Srgrimes{
2011541Srgrimes
20230994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
2031541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
20430994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
2051541Srgrimes#endif
2061541Srgrimes	return (0);
2071541Srgrimes}
2081541Srgrimes
20958941Sdillon/*
21058941Sdillon * geteuid() - MP SAFE
21158941Sdillon */
21212221Sbde#ifndef _SYS_SYSPROTO_H_
21311332Sswallacestruct geteuid_args {
21411332Sswallace        int     dummy;
21511332Sswallace};
21612221Sbde#endif
21711332Sswallace
2181541Srgrimes/* ARGSUSED */
2191549Srgrimesint
22030994Sphkgeteuid(p, uap)
2211541Srgrimes	struct proc *p;
22211332Sswallace	struct geteuid_args *uap;
2231541Srgrimes{
2241541Srgrimes
22530994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2261541Srgrimes	return (0);
2271541Srgrimes}
2281541Srgrimes
22958941Sdillon/*
23058941Sdillon * getgid() - MP SAFE
23158941Sdillon */
23212221Sbde#ifndef _SYS_SYSPROTO_H_
23311332Sswallacestruct getgid_args {
23411332Sswallace        int     dummy;
23511332Sswallace};
23612221Sbde#endif
23711332Sswallace
2381541Srgrimes/* ARGSUSED */
2391549Srgrimesint
24030994Sphkgetgid(p, uap)
2411541Srgrimes	struct proc *p;
24211332Sswallace	struct getgid_args *uap;
2431541Srgrimes{
2441541Srgrimes
24530994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2461541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
24730994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2481541Srgrimes#endif
2491541Srgrimes	return (0);
2501541Srgrimes}
2511541Srgrimes
2521541Srgrimes/*
2531541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2541541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2551541Srgrimes * correctly in a library function.
2561541Srgrimes */
25712221Sbde#ifndef _SYS_SYSPROTO_H_
25811332Sswallacestruct getegid_args {
25911332Sswallace        int     dummy;
26011332Sswallace};
26112221Sbde#endif
26211332Sswallace
2631541Srgrimes/* ARGSUSED */
2641549Srgrimesint
26530994Sphkgetegid(p, uap)
2661541Srgrimes	struct proc *p;
26711332Sswallace	struct getegid_args *uap;
2681541Srgrimes{
2691541Srgrimes
27030994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2711541Srgrimes	return (0);
2721541Srgrimes}
2731541Srgrimes
27412221Sbde#ifndef _SYS_SYSPROTO_H_
2751541Srgrimesstruct getgroups_args {
2761541Srgrimes	u_int	gidsetsize;
2771541Srgrimes	gid_t	*gidset;
2781541Srgrimes};
27912221Sbde#endif
2801549Srgrimesint
28130994Sphkgetgroups(p, uap)
2821541Srgrimes	struct proc *p;
2831541Srgrimes	register struct	getgroups_args *uap;
2841541Srgrimes{
2851541Srgrimes	register struct pcred *pc = p->p_cred;
2861541Srgrimes	register u_int ngrp;
2871541Srgrimes	int error;
2881541Srgrimes
2891541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
29030994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2911541Srgrimes		return (0);
2921541Srgrimes	}
2931541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2941541Srgrimes		return (EINVAL);
2951541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2963098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2973098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2981541Srgrimes		return (error);
29930994Sphk	p->p_retval[0] = ngrp;
3001541Srgrimes	return (0);
3011541Srgrimes}
3021541Srgrimes
30312221Sbde#ifndef _SYS_SYSPROTO_H_
30412207Sbdestruct setsid_args {
30511332Sswallace        int     dummy;
30611332Sswallace};
30712221Sbde#endif
30811332Sswallace
3091541Srgrimes/* ARGSUSED */
3101549Srgrimesint
31130994Sphksetsid(p, uap)
3121541Srgrimes	register struct proc *p;
31312207Sbde	struct setsid_args *uap;
3141541Srgrimes{
3151541Srgrimes
3161541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3171541Srgrimes		return (EPERM);
3181541Srgrimes	} else {
3191541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
32030994Sphk		p->p_retval[0] = p->p_pid;
3211541Srgrimes		return (0);
3221541Srgrimes	}
3231541Srgrimes}
3241541Srgrimes
3251541Srgrimes/*
3261541Srgrimes * set process group (setpgid/old setpgrp)
3271541Srgrimes *
3281541Srgrimes * caller does setpgid(targpid, targpgid)
3291541Srgrimes *
3301541Srgrimes * pid must be caller or child of caller (ESRCH)
3311541Srgrimes * if a child
3321541Srgrimes *	pid must be in same session (EPERM)
3331541Srgrimes *	pid can't have done an exec (EACCES)
3341541Srgrimes * if pgid != pid
3351541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3361541Srgrimes * pid must not be session leader (EPERM)
3371541Srgrimes */
33812221Sbde#ifndef _SYS_SYSPROTO_H_
3391541Srgrimesstruct setpgid_args {
3401541Srgrimes	int	pid;	/* target process id */
3411541Srgrimes	int	pgid;	/* target pgrp id */
3421541Srgrimes};
34312221Sbde#endif
3441541Srgrimes/* ARGSUSED */
3451549Srgrimesint
34630994Sphksetpgid(curp, uap)
3471541Srgrimes	struct proc *curp;
3481541Srgrimes	register struct setpgid_args *uap;
3491541Srgrimes{
3501541Srgrimes	register struct proc *targp;		/* target process */
3511541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
3521541Srgrimes
35320677Sbde	if (uap->pgid < 0)
35420677Sbde		return (EINVAL);
3551541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3561541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3571541Srgrimes			return (ESRCH);
35815985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3591541Srgrimes			return (EPERM);
3601541Srgrimes		if (targp->p_flag & P_EXEC)
3611541Srgrimes			return (EACCES);
3621541Srgrimes	} else
3631541Srgrimes		targp = curp;
3641541Srgrimes	if (SESS_LEADER(targp))
3651541Srgrimes		return (EPERM);
3661541Srgrimes	if (uap->pgid == 0)
3671541Srgrimes		uap->pgid = targp->p_pid;
3681541Srgrimes	else if (uap->pgid != targp->p_pid)
3691541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3701541Srgrimes	            pgrp->pg_session != curp->p_session)
3711541Srgrimes			return (EPERM);
3721541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3731541Srgrimes}
3741541Srgrimes
37524448Speter/*
37624448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
37772093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
37824448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
37924448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
38024448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
38124448Speter * does not set the saved id - this is dangerous for traditional BSD
38224448Speter * programs.  For this reason, we *really* do not want to set
38324448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
38424448Speter */
38524448Speter#define POSIX_APPENDIX_B_4_2_2
38624448Speter
38712221Sbde#ifndef _SYS_SYSPROTO_H_
3881541Srgrimesstruct setuid_args {
3891541Srgrimes	uid_t	uid;
3901541Srgrimes};
39112221Sbde#endif
3921541Srgrimes/* ARGSUSED */
3931549Srgrimesint
39430994Sphksetuid(p, uap)
3951541Srgrimes	struct proc *p;
3961541Srgrimes	struct setuid_args *uap;
3971541Srgrimes{
3981541Srgrimes	register struct pcred *pc = p->p_cred;
3991541Srgrimes	register uid_t uid;
4001541Srgrimes	int error;
4011541Srgrimes
40224448Speter	/*
40324448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
40424448Speter	 *
40524448Speter	 * Note that setuid(geteuid()) is a special case of
40624448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
40772093Sasmodai	 * to use this clause to be compatible with traditional BSD
40824448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
40924448Speter	 * three id's (assuming you have privs).
41024448Speter	 *
41124448Speter	 * Notes on the logic.  We do things in three steps.
41224448Speter	 * 1: We determine if the euid is going to change, and do EPERM
41324448Speter	 *    right away.  We unconditionally change the euid later if this
41424448Speter	 *    test is satisfied, simplifying that part of the logic.
41524448Speter	 * 2: We determine if the real and/or saved uid's are going to
41624448Speter	 *    change.  Determined by compile options.
41724448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
41824448Speter	 */
4191541Srgrimes	uid = uap->uid;
42024448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
42117994Sache#ifdef _POSIX_SAVED_IDS
42224448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
42317994Sache#endif
42424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
42524448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
42624448Speter#endif
42746155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4281541Srgrimes		return (error);
42924448Speter
43024448Speter#ifdef _POSIX_SAVED_IDS
4311541Srgrimes	/*
43224448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
43324448Speter	 * If so, we are changing the real uid and/or saved uid.
4341541Srgrimes	 */
43517994Sache	if (
43624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
43724448Speter	    uid == pc->pc_ucred->cr_uid ||
43817994Sache#endif
43946155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
44017994Sache#endif
44124448Speter	{
44224448Speter		/*
44365495Struckman		 * Set the real uid and transfer proc count to new user.
44424448Speter		 */
44524448Speter		if (uid != pc->p_ruid) {
44665495Struckman			change_ruid(p, uid);
44765495Struckman			setsugid(p);
44824448Speter		}
44924448Speter		/*
45024448Speter		 * Set saved uid
45124448Speter		 *
45224448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
45324448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
45424448Speter		 * is important that we should do this.
45524448Speter		 */
45624448Speter		if (pc->p_svuid != uid) {
45724448Speter			pc->p_svuid = uid;
45831891Ssef			setsugid(p);
45924448Speter		}
4608141Sache	}
46124448Speter
46224448Speter	/*
46324448Speter	 * In all permitted cases, we are changing the euid.
46424448Speter	 * Copy credentials so other references do not see our changes.
46524448Speter	 */
46624448Speter	if (pc->pc_ucred->cr_uid != uid) {
46765495Struckman		change_euid(p, uid);
46831891Ssef		setsugid(p);
46924448Speter	}
4701541Srgrimes	return (0);
4711541Srgrimes}
4721541Srgrimes
47312221Sbde#ifndef _SYS_SYSPROTO_H_
4741541Srgrimesstruct seteuid_args {
4751541Srgrimes	uid_t	euid;
4761541Srgrimes};
47712221Sbde#endif
4781541Srgrimes/* ARGSUSED */
4791549Srgrimesint
48030994Sphkseteuid(p, uap)
4811541Srgrimes	struct proc *p;
4821541Srgrimes	struct seteuid_args *uap;
4831541Srgrimes{
4841541Srgrimes	register struct pcred *pc = p->p_cred;
4851541Srgrimes	register uid_t euid;
4861541Srgrimes	int error;
4871541Srgrimes
4881541Srgrimes	euid = uap->euid;
48924449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
49024449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
49146155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4921541Srgrimes		return (error);
4931541Srgrimes	/*
4941541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4951541Srgrimes	 * not see our changes.
4961541Srgrimes	 */
49724449Speter	if (pc->pc_ucred->cr_uid != euid) {
49865495Struckman		change_euid(p, euid);
49931891Ssef		setsugid(p);
50024449Speter	}
5011541Srgrimes	return (0);
5021541Srgrimes}
5031541Srgrimes
50412221Sbde#ifndef _SYS_SYSPROTO_H_
5051541Srgrimesstruct setgid_args {
5061541Srgrimes	gid_t	gid;
5071541Srgrimes};
50812221Sbde#endif
5091541Srgrimes/* ARGSUSED */
5101549Srgrimesint
51130994Sphksetgid(p, uap)
5121541Srgrimes	struct proc *p;
5131541Srgrimes	struct setgid_args *uap;
5141541Srgrimes{
5151541Srgrimes	register struct pcred *pc = p->p_cred;
5161541Srgrimes	register gid_t gid;
5171541Srgrimes	int error;
5181541Srgrimes
51924448Speter	/*
52024448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
52124448Speter	 *
52224448Speter	 * Note that setgid(getegid()) is a special case of
52324448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52472093Sasmodai	 * to use this clause to be compatible with traditional BSD
52524448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
52624448Speter	 * three id's (assuming you have privs).
52724448Speter	 *
52824448Speter	 * For notes on the logic here, see setuid() above.
52924448Speter	 */
5301541Srgrimes	gid = uap->gid;
53124448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
53217994Sache#ifdef _POSIX_SAVED_IDS
53324448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
53417994Sache#endif
53524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53624448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
53724448Speter#endif
53846155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5391541Srgrimes		return (error);
54024448Speter
54117994Sache#ifdef _POSIX_SAVED_IDS
54224448Speter	/*
54324448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
54424448Speter	 * If so, we are changing the real uid and saved gid.
54524448Speter	 */
54624448Speter	if (
54724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
54824448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
54917994Sache#endif
55046155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
55124448Speter#endif
55224448Speter	{
55324448Speter		/*
55424448Speter		 * Set real gid
55524448Speter		 */
55624448Speter		if (pc->p_rgid != gid) {
55724448Speter			pc->p_rgid = gid;
55831891Ssef			setsugid(p);
55924448Speter		}
56024448Speter		/*
56124448Speter		 * Set saved gid
56224448Speter		 *
56324448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
56424448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
56524448Speter		 * is important that we should do this.
56624448Speter		 */
56724448Speter		if (pc->p_svgid != gid) {
56824448Speter			pc->p_svgid = gid;
56931891Ssef			setsugid(p);
57024448Speter		}
5718141Sache	}
57224448Speter	/*
57324448Speter	 * In all cases permitted cases, we are changing the egid.
57424448Speter	 * Copy credentials so other references do not see our changes.
57524448Speter	 */
57624448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
57724448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
57824448Speter		pc->pc_ucred->cr_groups[0] = gid;
57931891Ssef		setsugid(p);
58024448Speter	}
5811541Srgrimes	return (0);
5821541Srgrimes}
5831541Srgrimes
58412221Sbde#ifndef _SYS_SYSPROTO_H_
5851541Srgrimesstruct setegid_args {
5861541Srgrimes	gid_t	egid;
5871541Srgrimes};
58812221Sbde#endif
5891541Srgrimes/* ARGSUSED */
5901549Srgrimesint
59130994Sphksetegid(p, uap)
5921541Srgrimes	struct proc *p;
5931541Srgrimes	struct setegid_args *uap;
5941541Srgrimes{
5951541Srgrimes	register struct pcred *pc = p->p_cred;
5961541Srgrimes	register gid_t egid;
5971541Srgrimes	int error;
5981541Srgrimes
5991541Srgrimes	egid = uap->egid;
60024449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
60124449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
60246155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
6031541Srgrimes		return (error);
60424449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
60524449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
60624449Speter		pc->pc_ucred->cr_groups[0] = egid;
60731891Ssef		setsugid(p);
60824449Speter	}
6091541Srgrimes	return (0);
6101541Srgrimes}
6111541Srgrimes
61212221Sbde#ifndef _SYS_SYSPROTO_H_
6131541Srgrimesstruct setgroups_args {
6141541Srgrimes	u_int	gidsetsize;
6151541Srgrimes	gid_t	*gidset;
6161541Srgrimes};
61712221Sbde#endif
6181541Srgrimes/* ARGSUSED */
6191549Srgrimesint
62030994Sphksetgroups(p, uap)
6211541Srgrimes	struct proc *p;
6221541Srgrimes	struct setgroups_args *uap;
6231541Srgrimes{
6241541Srgrimes	register struct pcred *pc = p->p_cred;
6251541Srgrimes	register u_int ngrp;
6261541Srgrimes	int error;
6271541Srgrimes
62846155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
6291541Srgrimes		return (error);
63012063Sdg	ngrp = uap->gidsetsize;
63124447Speter	if (ngrp > NGROUPS)
6321541Srgrimes		return (EINVAL);
63324447Speter	/*
63424447Speter	 * XXX A little bit lazy here.  We could test if anything has
63524447Speter	 * changed before crcopy() and setting P_SUGID.
63624447Speter	 */
6371541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
63824447Speter	if (ngrp < 1) {
63924447Speter		/*
64024447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
64124447Speter		 * groups vector on non-BSD systems (which generally do not
64224447Speter		 * have the egid in the groups[0]).  We risk security holes
64324447Speter		 * when running non-BSD software if we do not do the same.
64424447Speter		 */
64524447Speter		pc->pc_ucred->cr_ngroups = 1;
64624447Speter	} else {
64724447Speter		if ((error = copyin((caddr_t)uap->gidset,
64824447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
64924447Speter			return (error);
65024447Speter		pc->pc_ucred->cr_ngroups = ngrp;
65124447Speter	}
65231891Ssef	setsugid(p);
6531541Srgrimes	return (0);
6541541Srgrimes}
6551541Srgrimes
65612221Sbde#ifndef _SYS_SYSPROTO_H_
6571541Srgrimesstruct setreuid_args {
6589238Sache	uid_t	ruid;
6599238Sache	uid_t	euid;
6601541Srgrimes};
66112221Sbde#endif
6621541Srgrimes/* ARGSUSED */
6631549Srgrimesint
66430994Sphksetreuid(p, uap)
6651541Srgrimes	register struct proc *p;
6661541Srgrimes	struct setreuid_args *uap;
6671541Srgrimes{
6681541Srgrimes	register struct pcred *pc = p->p_cred;
6699238Sache	register uid_t ruid, euid;
6708135Sache	int error;
6711541Srgrimes
6729238Sache	ruid = uap->ruid;
6739238Sache	euid = uap->euid;
67443311Sdillon	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
67543311Sdillon	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
67643311Sdillon	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
67746155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
6788135Sache		return (error);
6799238Sache
68024450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
68165495Struckman		change_euid(p, euid);
68231891Ssef		setsugid(p);
68324450Speter	}
68424450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
68565495Struckman		change_ruid(p, ruid);
68631891Ssef		setsugid(p);
6878135Sache	}
68824559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
68924559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6908111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
69131891Ssef		setsugid(p);
69224450Speter	}
6938135Sache	return (0);
6941541Srgrimes}
6951541Srgrimes
69612221Sbde#ifndef _SYS_SYSPROTO_H_
6971541Srgrimesstruct setregid_args {
6989238Sache	gid_t	rgid;
6999238Sache	gid_t	egid;
7001541Srgrimes};
70112221Sbde#endif
7021541Srgrimes/* ARGSUSED */
7031549Srgrimesint
70430994Sphksetregid(p, uap)
7051541Srgrimes	register struct proc *p;
7061541Srgrimes	struct setregid_args *uap;
7071541Srgrimes{
7081541Srgrimes	register struct pcred *pc = p->p_cred;
7099238Sache	register gid_t rgid, egid;
7108135Sache	int error;
7111541Srgrimes
7129238Sache	rgid = uap->rgid;
7139238Sache	egid = uap->egid;
71443311Sdillon	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
71543311Sdillon	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
71643311Sdillon	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
71746155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
7188135Sache		return (error);
7199238Sache
72024450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
72124450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
7229238Sache		pc->pc_ucred->cr_groups[0] = egid;
72331891Ssef		setsugid(p);
72424450Speter	}
72524450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7269238Sache		pc->p_rgid = rgid;
72731891Ssef		setsugid(p);
72824450Speter	}
72924559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
73024559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7318111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
73231891Ssef		setsugid(p);
73324450Speter	}
7348135Sache	return (0);
7351541Srgrimes}
7361541Srgrimes
73756115Speter/*
73856115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
73956115Speter * saved uid is explicit.
74056115Speter */
74156115Speter
74224453Speter#ifndef _SYS_SYSPROTO_H_
74356115Speterstruct setresuid_args {
74456115Speter	uid_t	ruid;
74556115Speter	uid_t	euid;
74656115Speter	uid_t	suid;
74756115Speter};
74856115Speter#endif
74956115Speter/* ARGSUSED */
75056115Speterint
75156115Spetersetresuid(p, uap)
75256115Speter	register struct proc *p;
75356115Speter	struct setresuid_args *uap;
75456115Speter{
75556115Speter	register struct pcred *pc = p->p_cred;
75656115Speter	register uid_t ruid, euid, suid;
75756115Speter	int error;
75856115Speter
75956115Speter	ruid = uap->ruid;
76056115Speter	euid = uap->euid;
76156115Speter	suid = uap->suid;
76256115Speter	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
76356115Speter	      ruid != pc->pc_ucred->cr_uid) ||
76456115Speter	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
76556115Speter	      euid != pc->pc_ucred->cr_uid) ||
76656115Speter	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
76756115Speter	      suid != pc->pc_ucred->cr_uid)) &&
76856115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
76956115Speter		return (error);
77056115Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
77165495Struckman		change_euid(p, euid);
77256115Speter		setsugid(p);
77356115Speter	}
77456115Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
77565495Struckman		change_ruid(p, ruid);
77656115Speter		setsugid(p);
77756115Speter	}
77856115Speter	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
77956115Speter		pc->p_svuid = suid;
78056115Speter		setsugid(p);
78156115Speter	}
78256115Speter	return (0);
78356115Speter}
78456115Speter
78556115Speter/*
78656115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
78756115Speter * saved gid is explicit.
78856115Speter */
78956115Speter
79056115Speter#ifndef _SYS_SYSPROTO_H_
79156115Speterstruct setresgid_args {
79256115Speter	gid_t	rgid;
79356115Speter	gid_t	egid;
79456115Speter	gid_t	sgid;
79556115Speter};
79656115Speter#endif
79756115Speter/* ARGSUSED */
79856115Speterint
79956115Spetersetresgid(p, uap)
80056115Speter	register struct proc *p;
80156115Speter	struct setresgid_args *uap;
80256115Speter{
80356115Speter	register struct pcred *pc = p->p_cred;
80456115Speter	register gid_t rgid, egid, sgid;
80556115Speter	int error;
80656115Speter
80756115Speter	rgid = uap->rgid;
80856115Speter	egid = uap->egid;
80956115Speter	sgid = uap->sgid;
81056115Speter	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
81156115Speter	      rgid != pc->pc_ucred->cr_groups[0]) ||
81256115Speter	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
81356115Speter	      egid != pc->pc_ucred->cr_groups[0]) ||
81456115Speter	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
81556115Speter	      sgid != pc->pc_ucred->cr_groups[0])) &&
81656115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
81756115Speter		return (error);
81856115Speter
81956115Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
82056115Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
82156115Speter		pc->pc_ucred->cr_groups[0] = egid;
82256115Speter		setsugid(p);
82356115Speter	}
82456115Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
82556115Speter		pc->p_rgid = rgid;
82656115Speter		setsugid(p);
82756115Speter	}
82856115Speter	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
82956115Speter		pc->p_svgid = sgid;
83056115Speter		setsugid(p);
83156115Speter	}
83256115Speter	return (0);
83356115Speter}
83456115Speter
83556115Speter#ifndef _SYS_SYSPROTO_H_
83656115Speterstruct getresuid_args {
83756115Speter	uid_t	*ruid;
83856115Speter	uid_t	*euid;
83956115Speter	uid_t	*suid;
84056115Speter};
84156115Speter#endif
84256115Speter/* ARGSUSED */
84356115Speterint
84456115Spetergetresuid(p, uap)
84556115Speter	register struct proc *p;
84656115Speter	struct getresuid_args *uap;
84756115Speter{
84856115Speter	struct pcred *pc = p->p_cred;
84956115Speter	int error1 = 0, error2 = 0, error3 = 0;
85056115Speter
85156115Speter	if (uap->ruid)
85256115Speter		error1 = copyout((caddr_t)&pc->p_ruid,
85356115Speter		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
85456115Speter	if (uap->euid)
85556115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
85656115Speter		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
85756115Speter	if (uap->suid)
85856115Speter		error3 = copyout((caddr_t)&pc->p_svuid,
85956115Speter		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
86056115Speter	return error1 ? error1 : (error2 ? error2 : error3);
86156115Speter}
86256115Speter
86356115Speter#ifndef _SYS_SYSPROTO_H_
86456115Speterstruct getresgid_args {
86556115Speter	gid_t	*rgid;
86656115Speter	gid_t	*egid;
86756115Speter	gid_t	*sgid;
86856115Speter};
86956115Speter#endif
87056115Speter/* ARGSUSED */
87156115Speterint
87256115Spetergetresgid(p, uap)
87356115Speter	register struct proc *p;
87456115Speter	struct getresgid_args *uap;
87556115Speter{
87656115Speter	struct pcred *pc = p->p_cred;
87756115Speter	int error1 = 0, error2 = 0, error3 = 0;
87856115Speter
87956115Speter	if (uap->rgid)
88056115Speter		error1 = copyout((caddr_t)&pc->p_rgid,
88156115Speter		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
88256115Speter	if (uap->egid)
88356115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
88456115Speter		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
88556115Speter	if (uap->sgid)
88656115Speter		error3 = copyout((caddr_t)&pc->p_svgid,
88756115Speter		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
88856115Speter	return error1 ? error1 : (error2 ? error2 : error3);
88956115Speter}
89056115Speter
89156115Speter
89256115Speter#ifndef _SYS_SYSPROTO_H_
89324453Speterstruct issetugid_args {
89424453Speter	int dummy;
89524453Speter};
89624453Speter#endif
89724453Speter/* ARGSUSED */
89824453Speterint
89930994Sphkissetugid(p, uap)
90024453Speter	register struct proc *p;
90124453Speter	struct issetugid_args *uap;
90224453Speter{
90324453Speter	/*
90424453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
90524453Speter	 * we use P_SUGID because we consider changing the owners as
90624453Speter	 * "tainting" as well.
90724453Speter	 * This is significant for procs that start as root and "become"
90824453Speter	 * a user without an exec - programs cannot know *everything*
90924453Speter	 * that libc *might* have put in their data segment.
91024453Speter	 */
91160216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
91224453Speter	return (0);
91324453Speter}
91424453Speter
91575426Srwatsonint
91675426Srwatson__setugid(p, uap)
91775426Srwatson	struct proc *p;
91875426Srwatson	struct __setugid_args *uap;
91975426Srwatson{
92075426Srwatson
92175426Srwatson#ifdef REGRESSION
92275426Srwatson	switch (uap->flag) {
92375426Srwatson	case 0:
92475426Srwatson		p->p_flag &= ~P_SUGID;
92575426Srwatson		return (0);
92675426Srwatson	case 1:
92775426Srwatson		p->p_flag |= P_SUGID;
92875426Srwatson		return (0);
92975426Srwatson	default:
93075426Srwatson		return (EINVAL);
93175426Srwatson	}
93275426Srwatson#else /* !REGRESSION */
93375426Srwatson	return (ENOSYS);
93475426Srwatson#endif /* !REGRESSION */
93575426Srwatson}
93675426Srwatson
9371541Srgrimes/*
9381541Srgrimes * Check if gid is a member of the group set.
9391541Srgrimes */
9401549Srgrimesint
9411541Srgrimesgroupmember(gid, cred)
9421541Srgrimes	gid_t gid;
9431541Srgrimes	register struct ucred *cred;
9441541Srgrimes{
9451541Srgrimes	register gid_t *gp;
9461541Srgrimes	gid_t *egp;
9471541Srgrimes
9481541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
9491541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
9501541Srgrimes		if (*gp == gid)
9511541Srgrimes			return (1);
9521541Srgrimes	return (0);
9531541Srgrimes}
9541541Srgrimes
95561287Srwatsonstatic int suser_permitted = 1;
95661287Srwatson
95761287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
95861287Srwatson    "processes with uid 0 have privilege");
95961287Srwatson
9601541Srgrimes/*
9611541Srgrimes * Test whether the specified credentials imply "super-user"
9621541Srgrimes * privilege; if so, and we have accounting info, set the flag
9631541Srgrimes * indicating use of super-powers.
9641541Srgrimes * Returns 0 or error.
9651541Srgrimes */
9661549Srgrimesint
96746112Sphksuser(p)
96872786Srwatson	struct proc *p;
96946112Sphk{
97046155Sphk	return suser_xxx(0, p, 0);
97146112Sphk}
97246112Sphk
97346112Sphkint
97446155Sphksuser_xxx(cred, proc, flag)
97572786Srwatson	struct ucred *cred;
97672786Srwatson	struct proc *proc;
97746155Sphk	int flag;
9781541Srgrimes{
97961282Srwatson	if (!suser_permitted)
98061282Srwatson		return (EPERM);
98146155Sphk	if (!cred && !proc) {
98246155Sphk		printf("suser_xxx(): THINK!\n");
98346155Sphk		return (EPERM);
9841541Srgrimes	}
98546155Sphk	if (!cred)
98646155Sphk		cred = proc->p_ucred;
98746155Sphk	if (cred->cr_uid != 0)
98846155Sphk		return (EPERM);
98972786Srwatson	if (jailed(cred) && !(flag & PRISON_ROOT))
99046155Sphk		return (EPERM);
99146155Sphk	return (0);
9921541Srgrimes}
9931541Srgrimes
99474956Srwatson/*
99574956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2
99674956Srwatson * Arguments: imutable credentials u1, u2
99774956Srwatson * Returns: 0 for permitted, an errno value otherwise
99874956Srwatson * Locks: none
99974956Srwatson * References: u1 and u2 must be valid for the lifetime of the call
100074956Srwatson *             u1 may equal u2, in which case only one reference is required
100174956Srwatson */
100274956Srwatsonint
100374956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2)
100465237Srwatson{
100572786Srwatson	int error;
100653518Sphk
100774956Srwatson	if ((error = prison_check(u1, u2)))
100872786Srwatson		return (error);
100974956Srwatson	if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) {
101075005Srwatson		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
101174956Srwatson			return (ESRCH);
101265293Srwatson	}
101365237Srwatson	return (0);
101465237Srwatson}
101565237Srwatson
101665237Srwatsonstatic int
101774956Srwatsonp_cansee(struct proc *p1, struct proc *p2, int *privused)
101874956Srwatson{
101974956Srwatson
102074956Srwatson	/* XXX: privused is going away, so don't do that here. */
102174956Srwatson	if (privused != NULL)
102274956Srwatson		*privused = 0;
102374956Srwatson	/* Wrap u_cansee() for all functionality. */
102474956Srwatson	return (u_cansee(p1->p_ucred, p2->p_ucred));
102574956Srwatson}
102674956Srwatson
102774956Srwatsonstatic int
102872786Srwatsonp_cankill(struct proc *p1, struct proc *p2, int *privused)
102953518Sphk{
103072786Srwatson	int error;
103153518Sphk
103265237Srwatson	if (privused != NULL)
103365237Srwatson		*privused = 0;
103465237Srwatson
103553518Sphk	if (p1 == p2)
103653518Sphk		return (0);
103765237Srwatson
103872786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
103972786Srwatson		return (error);
104065237Srwatson
104153518Sphk	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
104253518Sphk		return (0);
104353518Sphk	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
104453518Sphk		return (0);
104565237Srwatson	/*
104665237Srwatson	 * XXX should a process be able to affect another process
104765237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
104865237Srwatson	 */
104953518Sphk	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
105053518Sphk		return (0);
105153518Sphk	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
105253518Sphk		return (0);
105365237Srwatson
105465237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
105565237Srwatson		if (privused != NULL)
105665237Srwatson			*privused = 1;
105753518Sphk		return (0);
105865237Srwatson	}
105965237Srwatson
106065237Srwatson#ifdef CAPABILITIES
106165237Srwatson	if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) {
106265237Srwatson		if (privused != NULL)
106365237Srwatson			*privused = 1;
106465237Srwatson		return (0);
106565237Srwatson	}
106665237Srwatson#endif
106765237Srwatson
106853518Sphk	return (EPERM);
106953518Sphk}
107053518Sphk
107165237Srwatsonstatic int
107272786Srwatsonp_cansched(struct proc *p1, struct proc *p2, int *privused)
107365237Srwatson{
107472786Srwatson	int error;
107565237Srwatson
107665237Srwatson	if (privused != NULL)
107765237Srwatson		*privused = 0;
107865237Srwatson
107965237Srwatson	if (p1 == p2)
108065237Srwatson		return (0);
108165237Srwatson
108272786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
108372786Srwatson		return (error);
108465237Srwatson
108565237Srwatson	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
108665237Srwatson		return (0);
108765237Srwatson	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
108865237Srwatson		return (0);
108965237Srwatson	/*
109065237Srwatson	 * XXX should a process be able to affect another process
109165237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
109265237Srwatson	 */
109365237Srwatson	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
109465237Srwatson		return (0);
109565237Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
109665237Srwatson		return (0);
109765237Srwatson
109865237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
109965237Srwatson		if (privused != NULL)
110065237Srwatson			*privused = 1;
110165237Srwatson		return (0);
110265237Srwatson	}
110365237Srwatson
110465237Srwatson#ifdef CAPABILITIES
110565237Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) {
110665237Srwatson		if (privused != NULL)
110765237Srwatson			*privused = 1;
110865237Srwatson		return (0);
110965237Srwatson	}
111065237Srwatson#endif
111165237Srwatson
111265237Srwatson	return (EPERM);
111365237Srwatson}
111465237Srwatson
111565237Srwatsonstatic int
111672786Srwatsonp_candebug(struct proc *p1, struct proc *p2, int *privused)
111765237Srwatson{
111872786Srwatson	int error;
111965237Srwatson
112065237Srwatson	if (privused != NULL)
112165237Srwatson		*privused = 0;
112265237Srwatson
112365237Srwatson	/* XXX it is authorized, but semantics don't permit it */
112465237Srwatson	if (p1 == p2)
112565237Srwatson		return (0);
112665237Srwatson
112772786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
112872786Srwatson		return (error);
112965237Srwatson
113065237Srwatson	/* not owned by you, has done setuid (unless you're root) */
113165237Srwatson	/* add a CAP_SYS_PTRACE here? */
113267999Srwatson	if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid ||
113367999Srwatson	    p1->p_cred->p_ruid != p2->p_cred->p_ruid ||
113468591Srwatson	    p1->p_cred->p_svuid != p2->p_cred->p_ruid ||
113567999Srwatson	    p2->p_flag & P_SUGID) {
113665237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
113765237Srwatson			return (error);
113865237Srwatson		if (privused != NULL)
113965237Srwatson			*privused = 1;
114065237Srwatson	}
114165237Srwatson
114265237Srwatson	/* can't trace init when securelevel > 0 */
114365237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
114465237Srwatson		return (EPERM);
114565237Srwatson
114665237Srwatson	return (0);
114765237Srwatson}
114865237Srwatson
114965237Srwatsonint
115072786Srwatsonp_can(struct proc *p1, struct proc *p2, int operation,
115165237Srwatson    int *privused)
115265237Srwatson{
115365237Srwatson
115465237Srwatson	switch(operation) {
115565237Srwatson	case P_CAN_SEE:
115665237Srwatson		return (p_cansee(p1, p2, privused));
115765237Srwatson
115865237Srwatson	case P_CAN_KILL:
115965237Srwatson		return (p_cankill(p1, p2, privused));
116065237Srwatson
116165237Srwatson	case P_CAN_SCHED:
116265237Srwatson		return (p_cansched(p1, p2, privused));
116365237Srwatson
116465237Srwatson	case P_CAN_DEBUG:
116565237Srwatson		return (p_candebug(p1, p2, privused));
116665237Srwatson
116765237Srwatson	default:
116865237Srwatson		panic("p_can: invalid operation");
116965237Srwatson	}
117065237Srwatson}
117165237Srwatson
117265237Srwatson
117353518Sphk/*
11741541Srgrimes * Allocate a zeroed cred structure.
11751541Srgrimes */
11761541Srgrimesstruct ucred *
11771541Srgrimescrget()
11781541Srgrimes{
11791541Srgrimes	register struct ucred *cr;
11801541Srgrimes
118169239Salfred	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
11821541Srgrimes	cr->cr_ref = 1;
118369239Salfred	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
11841541Srgrimes	return (cr);
11851541Srgrimes}
11861541Srgrimes
11871541Srgrimes/*
118872474Srwatson * Claim another reference to a ucred structure
118969401Salfred */
119069401Salfredvoid
119169401Salfredcrhold(cr)
119269401Salfred	struct ucred *cr;
119369401Salfred{
119469401Salfred
119572200Sbmilekic	mtx_lock(&cr->cr_mtx);
119669401Salfred	cr->cr_ref++;
119772200Sbmilekic	mtx_unlock(&(cr)->cr_mtx);
119869401Salfred}
119969401Salfred
120069401Salfred
120169401Salfred/*
12021541Srgrimes * Free a cred structure.
12031541Srgrimes * Throws away space when ref count gets to 0.
12041541Srgrimes */
12051549Srgrimesvoid
12061541Srgrimescrfree(cr)
12071541Srgrimes	struct ucred *cr;
12081541Srgrimes{
120969239Salfred
121072200Sbmilekic	mtx_lock(&cr->cr_mtx);
121165495Struckman	if (--cr->cr_ref == 0) {
121269239Salfred		mtx_destroy(&cr->cr_mtx);
121365495Struckman		/*
121465495Struckman		 * Some callers of crget(), such as nfs_statfs(),
121565495Struckman		 * allocate a temporary credential, but don't
121665495Struckman		 * allocate a uidinfo structure.
121765495Struckman		 */
121865495Struckman		if (cr->cr_uidinfo != NULL)
121965495Struckman			uifree(cr->cr_uidinfo);
122072786Srwatson		/*
122172786Srwatson		 * Free a prison, if any.
122272786Srwatson		 */
122372786Srwatson		if (jailed(cr))
122472786Srwatson			prison_free(cr->cr_prison);
12251541Srgrimes		FREE((caddr_t)cr, M_CRED);
122669239Salfred	} else {
122772200Sbmilekic		mtx_unlock(&cr->cr_mtx);
122865495Struckman	}
12291541Srgrimes}
12301541Srgrimes
12311541Srgrimes/*
12321541Srgrimes * Copy cred structure to a new one and free the old one.
12331541Srgrimes */
12341541Srgrimesstruct ucred *
12351541Srgrimescrcopy(cr)
12361541Srgrimes	struct ucred *cr;
12371541Srgrimes{
12381541Srgrimes	struct ucred *newcr;
12391541Srgrimes
124072200Sbmilekic	mtx_lock(&cr->cr_mtx);
124169239Salfred	if (cr->cr_ref == 1) {
124272200Sbmilekic		mtx_unlock(&cr->cr_mtx);
12431541Srgrimes		return (cr);
124469239Salfred	}
124572200Sbmilekic	mtx_unlock(&cr->cr_mtx);
124669239Salfred	newcr = crdup(cr);
12471541Srgrimes	crfree(cr);
12481541Srgrimes	return (newcr);
12491541Srgrimes}
12501541Srgrimes
12511541Srgrimes/*
12521541Srgrimes * Dup cred struct to a new held one.
12531541Srgrimes */
12541541Srgrimesstruct ucred *
12551541Srgrimescrdup(cr)
12561541Srgrimes	struct ucred *cr;
12571541Srgrimes{
12581541Srgrimes	struct ucred *newcr;
12591541Srgrimes
126069239Salfred	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
12611541Srgrimes	*newcr = *cr;
126269239Salfred	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
126365495Struckman	uihold(newcr->cr_uidinfo);
126472786Srwatson	if (jailed(newcr))
126572786Srwatson		prison_hold(newcr->cr_prison);
12661541Srgrimes	newcr->cr_ref = 1;
12671541Srgrimes	return (newcr);
12681541Srgrimes}
12691541Srgrimes
12701541Srgrimes/*
12711541Srgrimes * Get login name, if available.
12721541Srgrimes */
127312221Sbde#ifndef _SYS_SYSPROTO_H_
12741541Srgrimesstruct getlogin_args {
12751541Srgrimes	char	*namebuf;
12761541Srgrimes	u_int	namelen;
12771541Srgrimes};
127812221Sbde#endif
12791541Srgrimes/* ARGSUSED */
12801549Srgrimesint
128130994Sphkgetlogin(p, uap)
12821541Srgrimes	struct proc *p;
12831541Srgrimes	struct getlogin_args *uap;
12841541Srgrimes{
12851541Srgrimes
128623358Sache	if (uap->namelen > MAXLOGNAME)
128723359Sache		uap->namelen = MAXLOGNAME;
12881541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
12891541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
12901541Srgrimes}
12911541Srgrimes
12921541Srgrimes/*
12931541Srgrimes * Set login name.
12941541Srgrimes */
129512221Sbde#ifndef _SYS_SYSPROTO_H_
12961541Srgrimesstruct setlogin_args {
12971541Srgrimes	char	*namebuf;
12981541Srgrimes};
129912221Sbde#endif
13001541Srgrimes/* ARGSUSED */
13011549Srgrimesint
130230994Sphksetlogin(p, uap)
13031541Srgrimes	struct proc *p;
13041541Srgrimes	struct setlogin_args *uap;
13051541Srgrimes{
13061541Srgrimes	int error;
130723330Sache	char logintmp[MAXLOGNAME];
13081541Srgrimes
130946155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
13101541Srgrimes		return (error);
131122522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
131236845Sdfr	    sizeof(logintmp), (size_t *)0);
13131541Srgrimes	if (error == ENAMETOOLONG)
13141541Srgrimes		error = EINVAL;
131522522Sdavidn	else if (!error)
131622522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
131723330Sache		    sizeof(logintmp));
13181541Srgrimes	return (error);
13191541Srgrimes}
132031891Ssef
132131891Ssefvoid
132231891Ssefsetsugid(p)
132355338Sphk	struct proc *p;
132431891Ssef{
132531891Ssef	p->p_flag |= P_SUGID;
132655707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
132731891Ssef		p->p_stops = 0;
132831891Ssef}
132965495Struckman
133065495Struckman/*
133165495Struckman * Helper function to change the effective uid of a process
133265495Struckman */
133365495Struckmanvoid
133465495Struckmanchange_euid(p, euid)
133565495Struckman	struct	proc *p;
133665495Struckman	uid_t	euid;
133765495Struckman{
133865495Struckman	struct	pcred *pc;
133965495Struckman	struct	uidinfo *uip;
134065495Struckman
134165495Struckman	pc = p->p_cred;
134265495Struckman	/*
134365495Struckman	 * crcopy is essentially a NOP if ucred has a reference count
134465495Struckman	 * of 1, which is true if it has already been copied.
134565495Struckman	 */
134665495Struckman	pc->pc_ucred = crcopy(pc->pc_ucred);
134765495Struckman	uip = pc->pc_ucred->cr_uidinfo;
134865495Struckman	pc->pc_ucred->cr_uid = euid;
134965495Struckman	pc->pc_ucred->cr_uidinfo = uifind(euid);
135065495Struckman	uifree(uip);
135165495Struckman}
135265495Struckman
135365495Struckman/*
135465495Struckman * Helper function to change the real uid of a process
135565495Struckman *
135665495Struckman * The per-uid process count for this process is transfered from
135765495Struckman * the old uid to the new uid.
135865495Struckman */
135967629Sgallatinvoid
136065495Struckmanchange_ruid(p, ruid)
136165495Struckman	struct	proc *p;
136265495Struckman	uid_t	ruid;
136365495Struckman{
136465495Struckman	struct	pcred *pc;
136565495Struckman	struct	uidinfo *uip;
136665495Struckman
136765495Struckman	pc = p->p_cred;
136865495Struckman	(void)chgproccnt(pc->p_uidinfo, -1, 0);
136965495Struckman	uip = pc->p_uidinfo;
137065495Struckman	/* It is assumed that pcred is not shared between processes */
137165495Struckman	pc->p_ruid = ruid;
137265495Struckman	pc->p_uidinfo = uifind(ruid);
137365495Struckman	(void)chgproccnt(pc->p_uidinfo, 1, 0);
137465495Struckman	uifree(uip);
137565495Struckman}
1376