kern_prot.c revision 74728
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 74728 2001-03-24 04:00:01Z jhb $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
4631778Seivind#include "opt_compat.h"
4731778Seivind
481541Srgrimes#include <sys/param.h>
491541Srgrimes#include <sys/acct.h>
501541Srgrimes#include <sys/systm.h>
5112221Sbde#include <sys/sysproto.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
541541Srgrimes#include <sys/proc.h>
551541Srgrimes#include <sys/malloc.h>
5631891Ssef#include <sys/pioctl.h>
5765495Struckman#include <sys/resourcevar.h>
5861287Srwatson#include <sys/sysctl.h>
5972786Srwatson#include <sys/jail.h>
601541Srgrimes
6130354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6230354Sphk
6312221Sbde#ifndef _SYS_SYSPROTO_H_
6411332Sswallacestruct getpid_args {
651541Srgrimes	int	dummy;
661541Srgrimes};
6712221Sbde#endif
681541Srgrimes
6958717Sdillon/*
7070317Sjake * getpid - MP SAFE
7158717Sdillon */
7270317Sjake
731541Srgrimes/* ARGSUSED */
741549Srgrimesint
7530994Sphkgetpid(p, uap)
761541Srgrimes	struct proc *p;
7711332Sswallace	struct getpid_args *uap;
781541Srgrimes{
791541Srgrimes
8030994Sphk	p->p_retval[0] = p->p_pid;
811541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8274728Sjhb	PROC_LOCK(p);
8330994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
8474728Sjhb	PROC_UNLOCK(p);
851541Srgrimes#endif
861541Srgrimes	return (0);
871541Srgrimes}
881541Srgrimes
8970317Sjake/*
9070317Sjake * getppid - MP SAFE
9170317Sjake */
9270317Sjake
9312221Sbde#ifndef _SYS_SYSPROTO_H_
9411332Sswallacestruct getppid_args {
9511332Sswallace        int     dummy;
9611332Sswallace};
9712221Sbde#endif
981541Srgrimes/* ARGSUSED */
991549Srgrimesint
10030994Sphkgetppid(p, uap)
1011541Srgrimes	struct proc *p;
10211332Sswallace	struct getppid_args *uap;
1031541Srgrimes{
1041541Srgrimes
10574728Sjhb	PROC_LOCK(p);
10630994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
10774728Sjhb	PROC_UNLOCK(p);
1081541Srgrimes	return (0);
1091541Srgrimes}
1101541Srgrimes
11158717Sdillon/*
11258717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter
11358717Sdillon *
11458717Sdillon * MP SAFE
11558717Sdillon */
11612221Sbde#ifndef _SYS_SYSPROTO_H_
11711332Sswallacestruct getpgrp_args {
11811332Sswallace        int     dummy;
11911332Sswallace};
12012221Sbde#endif
12111332Sswallace
1221549Srgrimesint
12330994Sphkgetpgrp(p, uap)
1241541Srgrimes	struct proc *p;
12511332Sswallace	struct getpgrp_args *uap;
1261541Srgrimes{
1271541Srgrimes
12830994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1291541Srgrimes	return (0);
1301541Srgrimes}
1311541Srgrimes
13228401Speter/* Get an arbitary pid's process group id */
13312221Sbde#ifndef _SYS_SYSPROTO_H_
13428401Speterstruct getpgid_args {
13528401Speter	pid_t	pid;
13628401Speter};
13728401Speter#endif
13828401Speter
13928401Speterint
14030994Sphkgetpgid(p, uap)
14128401Speter	struct proc *p;
14228401Speter	struct getpgid_args *uap;
14328401Speter{
14441726Struckman	struct proc *pt;
14541726Struckman
14641726Struckman	pt = p;
14728401Speter	if (uap->pid == 0)
14828401Speter		goto found;
14928401Speter
15041726Struckman	if ((pt = pfind(uap->pid)) == 0)
15128401Speter		return ESRCH;
15228401Speterfound:
15341726Struckman	p->p_retval[0] = pt->p_pgrp->pg_id;
15428401Speter	return 0;
15528401Speter}
15628401Speter
15728401Speter/*
15828401Speter * Get an arbitary pid's session id.
15928401Speter */
16028401Speter#ifndef _SYS_SYSPROTO_H_
16128401Speterstruct getsid_args {
16228401Speter	pid_t	pid;
16328401Speter};
16428401Speter#endif
16528401Speter
16628401Speterint
16730994Sphkgetsid(p, uap)
16828401Speter	struct proc *p;
16928401Speter	struct getsid_args *uap;
17028401Speter{
17141726Struckman	struct proc *pt;
17241726Struckman
17341726Struckman	pt = p;
17428401Speter	if (uap->pid == 0)
17528401Speter		goto found;
17628401Speter
17771002Sben	if ((pt = pfind(uap->pid)) == 0)
17828401Speter		return ESRCH;
17928401Speterfound:
18041726Struckman	p->p_retval[0] = pt->p_session->s_sid;
18128401Speter	return 0;
18228401Speter}
18328401Speter
18428401Speter
18558941Sdillon/*
18658941Sdillon * getuid() - MP SAFE
18758941Sdillon */
18828401Speter#ifndef _SYS_SYSPROTO_H_
18911332Sswallacestruct getuid_args {
19011332Sswallace        int     dummy;
19111332Sswallace};
19212221Sbde#endif
19311332Sswallace
1941541Srgrimes/* ARGSUSED */
1951549Srgrimesint
19630994Sphkgetuid(p, uap)
1971541Srgrimes	struct proc *p;
19811332Sswallace	struct getuid_args *uap;
1991541Srgrimes{
2001541Srgrimes
20130994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
2021541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
20330994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
2041541Srgrimes#endif
2051541Srgrimes	return (0);
2061541Srgrimes}
2071541Srgrimes
20858941Sdillon/*
20958941Sdillon * geteuid() - MP SAFE
21058941Sdillon */
21112221Sbde#ifndef _SYS_SYSPROTO_H_
21211332Sswallacestruct geteuid_args {
21311332Sswallace        int     dummy;
21411332Sswallace};
21512221Sbde#endif
21611332Sswallace
2171541Srgrimes/* ARGSUSED */
2181549Srgrimesint
21930994Sphkgeteuid(p, uap)
2201541Srgrimes	struct proc *p;
22111332Sswallace	struct geteuid_args *uap;
2221541Srgrimes{
2231541Srgrimes
22430994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2251541Srgrimes	return (0);
2261541Srgrimes}
2271541Srgrimes
22858941Sdillon/*
22958941Sdillon * getgid() - MP SAFE
23058941Sdillon */
23112221Sbde#ifndef _SYS_SYSPROTO_H_
23211332Sswallacestruct getgid_args {
23311332Sswallace        int     dummy;
23411332Sswallace};
23512221Sbde#endif
23611332Sswallace
2371541Srgrimes/* ARGSUSED */
2381549Srgrimesint
23930994Sphkgetgid(p, uap)
2401541Srgrimes	struct proc *p;
24111332Sswallace	struct getgid_args *uap;
2421541Srgrimes{
2431541Srgrimes
24430994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2451541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
24630994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2471541Srgrimes#endif
2481541Srgrimes	return (0);
2491541Srgrimes}
2501541Srgrimes
2511541Srgrimes/*
2521541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2531541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2541541Srgrimes * correctly in a library function.
2551541Srgrimes */
25612221Sbde#ifndef _SYS_SYSPROTO_H_
25711332Sswallacestruct getegid_args {
25811332Sswallace        int     dummy;
25911332Sswallace};
26012221Sbde#endif
26111332Sswallace
2621541Srgrimes/* ARGSUSED */
2631549Srgrimesint
26430994Sphkgetegid(p, uap)
2651541Srgrimes	struct proc *p;
26611332Sswallace	struct getegid_args *uap;
2671541Srgrimes{
2681541Srgrimes
26930994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2701541Srgrimes	return (0);
2711541Srgrimes}
2721541Srgrimes
27312221Sbde#ifndef _SYS_SYSPROTO_H_
2741541Srgrimesstruct getgroups_args {
2751541Srgrimes	u_int	gidsetsize;
2761541Srgrimes	gid_t	*gidset;
2771541Srgrimes};
27812221Sbde#endif
2791549Srgrimesint
28030994Sphkgetgroups(p, uap)
2811541Srgrimes	struct proc *p;
2821541Srgrimes	register struct	getgroups_args *uap;
2831541Srgrimes{
2841541Srgrimes	register struct pcred *pc = p->p_cred;
2851541Srgrimes	register u_int ngrp;
2861541Srgrimes	int error;
2871541Srgrimes
2881541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
28930994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2901541Srgrimes		return (0);
2911541Srgrimes	}
2921541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2931541Srgrimes		return (EINVAL);
2941541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2953098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2963098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2971541Srgrimes		return (error);
29830994Sphk	p->p_retval[0] = ngrp;
2991541Srgrimes	return (0);
3001541Srgrimes}
3011541Srgrimes
30212221Sbde#ifndef _SYS_SYSPROTO_H_
30312207Sbdestruct setsid_args {
30411332Sswallace        int     dummy;
30511332Sswallace};
30612221Sbde#endif
30711332Sswallace
3081541Srgrimes/* ARGSUSED */
3091549Srgrimesint
31030994Sphksetsid(p, uap)
3111541Srgrimes	register struct proc *p;
31212207Sbde	struct setsid_args *uap;
3131541Srgrimes{
3141541Srgrimes
3151541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3161541Srgrimes		return (EPERM);
3171541Srgrimes	} else {
3181541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
31930994Sphk		p->p_retval[0] = p->p_pid;
3201541Srgrimes		return (0);
3211541Srgrimes	}
3221541Srgrimes}
3231541Srgrimes
3241541Srgrimes/*
3251541Srgrimes * set process group (setpgid/old setpgrp)
3261541Srgrimes *
3271541Srgrimes * caller does setpgid(targpid, targpgid)
3281541Srgrimes *
3291541Srgrimes * pid must be caller or child of caller (ESRCH)
3301541Srgrimes * if a child
3311541Srgrimes *	pid must be in same session (EPERM)
3321541Srgrimes *	pid can't have done an exec (EACCES)
3331541Srgrimes * if pgid != pid
3341541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3351541Srgrimes * pid must not be session leader (EPERM)
3361541Srgrimes */
33712221Sbde#ifndef _SYS_SYSPROTO_H_
3381541Srgrimesstruct setpgid_args {
3391541Srgrimes	int	pid;	/* target process id */
3401541Srgrimes	int	pgid;	/* target pgrp id */
3411541Srgrimes};
34212221Sbde#endif
3431541Srgrimes/* ARGSUSED */
3441549Srgrimesint
34530994Sphksetpgid(curp, uap)
3461541Srgrimes	struct proc *curp;
3471541Srgrimes	register struct setpgid_args *uap;
3481541Srgrimes{
3491541Srgrimes	register struct proc *targp;		/* target process */
3501541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
3511541Srgrimes
35220677Sbde	if (uap->pgid < 0)
35320677Sbde		return (EINVAL);
3541541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3551541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3561541Srgrimes			return (ESRCH);
35715985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3581541Srgrimes			return (EPERM);
3591541Srgrimes		if (targp->p_flag & P_EXEC)
3601541Srgrimes			return (EACCES);
3611541Srgrimes	} else
3621541Srgrimes		targp = curp;
3631541Srgrimes	if (SESS_LEADER(targp))
3641541Srgrimes		return (EPERM);
3651541Srgrimes	if (uap->pgid == 0)
3661541Srgrimes		uap->pgid = targp->p_pid;
3671541Srgrimes	else if (uap->pgid != targp->p_pid)
3681541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3691541Srgrimes	            pgrp->pg_session != curp->p_session)
3701541Srgrimes			return (EPERM);
3711541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3721541Srgrimes}
3731541Srgrimes
37424448Speter/*
37524448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
37672093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
37724448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
37824448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
37924448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
38024448Speter * does not set the saved id - this is dangerous for traditional BSD
38124448Speter * programs.  For this reason, we *really* do not want to set
38224448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
38324448Speter */
38424448Speter#define POSIX_APPENDIX_B_4_2_2
38524448Speter
38612221Sbde#ifndef _SYS_SYSPROTO_H_
3871541Srgrimesstruct setuid_args {
3881541Srgrimes	uid_t	uid;
3891541Srgrimes};
39012221Sbde#endif
3911541Srgrimes/* ARGSUSED */
3921549Srgrimesint
39330994Sphksetuid(p, uap)
3941541Srgrimes	struct proc *p;
3951541Srgrimes	struct setuid_args *uap;
3961541Srgrimes{
3971541Srgrimes	register struct pcred *pc = p->p_cred;
3981541Srgrimes	register uid_t uid;
3991541Srgrimes	int error;
4001541Srgrimes
40124448Speter	/*
40224448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
40324448Speter	 *
40424448Speter	 * Note that setuid(geteuid()) is a special case of
40524448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
40672093Sasmodai	 * to use this clause to be compatible with traditional BSD
40724448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
40824448Speter	 * three id's (assuming you have privs).
40924448Speter	 *
41024448Speter	 * Notes on the logic.  We do things in three steps.
41124448Speter	 * 1: We determine if the euid is going to change, and do EPERM
41224448Speter	 *    right away.  We unconditionally change the euid later if this
41324448Speter	 *    test is satisfied, simplifying that part of the logic.
41424448Speter	 * 2: We determine if the real and/or saved uid's are going to
41524448Speter	 *    change.  Determined by compile options.
41624448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
41724448Speter	 */
4181541Srgrimes	uid = uap->uid;
41924448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
42017994Sache#ifdef _POSIX_SAVED_IDS
42124448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
42217994Sache#endif
42324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
42424448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
42524448Speter#endif
42646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4271541Srgrimes		return (error);
42824448Speter
42924448Speter#ifdef _POSIX_SAVED_IDS
4301541Srgrimes	/*
43124448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
43224448Speter	 * If so, we are changing the real uid and/or saved uid.
4331541Srgrimes	 */
43417994Sache	if (
43524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
43624448Speter	    uid == pc->pc_ucred->cr_uid ||
43717994Sache#endif
43846155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
43917994Sache#endif
44024448Speter	{
44124448Speter		/*
44265495Struckman		 * Set the real uid and transfer proc count to new user.
44324448Speter		 */
44424448Speter		if (uid != pc->p_ruid) {
44565495Struckman			change_ruid(p, uid);
44665495Struckman			setsugid(p);
44724448Speter		}
44824448Speter		/*
44924448Speter		 * Set saved uid
45024448Speter		 *
45124448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
45224448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
45324448Speter		 * is important that we should do this.
45424448Speter		 */
45524448Speter		if (pc->p_svuid != uid) {
45624448Speter			pc->p_svuid = uid;
45731891Ssef			setsugid(p);
45824448Speter		}
4598141Sache	}
46024448Speter
46124448Speter	/*
46224448Speter	 * In all permitted cases, we are changing the euid.
46324448Speter	 * Copy credentials so other references do not see our changes.
46424448Speter	 */
46524448Speter	if (pc->pc_ucred->cr_uid != uid) {
46665495Struckman		change_euid(p, uid);
46731891Ssef		setsugid(p);
46824448Speter	}
4691541Srgrimes	return (0);
4701541Srgrimes}
4711541Srgrimes
47212221Sbde#ifndef _SYS_SYSPROTO_H_
4731541Srgrimesstruct seteuid_args {
4741541Srgrimes	uid_t	euid;
4751541Srgrimes};
47612221Sbde#endif
4771541Srgrimes/* ARGSUSED */
4781549Srgrimesint
47930994Sphkseteuid(p, uap)
4801541Srgrimes	struct proc *p;
4811541Srgrimes	struct seteuid_args *uap;
4821541Srgrimes{
4831541Srgrimes	register struct pcred *pc = p->p_cred;
4841541Srgrimes	register uid_t euid;
4851541Srgrimes	int error;
4861541Srgrimes
4871541Srgrimes	euid = uap->euid;
48824449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
48924449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
49046155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4911541Srgrimes		return (error);
4921541Srgrimes	/*
4931541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4941541Srgrimes	 * not see our changes.
4951541Srgrimes	 */
49624449Speter	if (pc->pc_ucred->cr_uid != euid) {
49765495Struckman		change_euid(p, euid);
49831891Ssef		setsugid(p);
49924449Speter	}
5001541Srgrimes	return (0);
5011541Srgrimes}
5021541Srgrimes
50312221Sbde#ifndef _SYS_SYSPROTO_H_
5041541Srgrimesstruct setgid_args {
5051541Srgrimes	gid_t	gid;
5061541Srgrimes};
50712221Sbde#endif
5081541Srgrimes/* ARGSUSED */
5091549Srgrimesint
51030994Sphksetgid(p, uap)
5111541Srgrimes	struct proc *p;
5121541Srgrimes	struct setgid_args *uap;
5131541Srgrimes{
5141541Srgrimes	register struct pcred *pc = p->p_cred;
5151541Srgrimes	register gid_t gid;
5161541Srgrimes	int error;
5171541Srgrimes
51824448Speter	/*
51924448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
52024448Speter	 *
52124448Speter	 * Note that setgid(getegid()) is a special case of
52224448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52372093Sasmodai	 * to use this clause to be compatible with traditional BSD
52424448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
52524448Speter	 * three id's (assuming you have privs).
52624448Speter	 *
52724448Speter	 * For notes on the logic here, see setuid() above.
52824448Speter	 */
5291541Srgrimes	gid = uap->gid;
53024448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
53117994Sache#ifdef _POSIX_SAVED_IDS
53224448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
53317994Sache#endif
53424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53524448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
53624448Speter#endif
53746155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5381541Srgrimes		return (error);
53924448Speter
54017994Sache#ifdef _POSIX_SAVED_IDS
54124448Speter	/*
54224448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
54324448Speter	 * If so, we are changing the real uid and saved gid.
54424448Speter	 */
54524448Speter	if (
54624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
54724448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
54817994Sache#endif
54946155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
55024448Speter#endif
55124448Speter	{
55224448Speter		/*
55324448Speter		 * Set real gid
55424448Speter		 */
55524448Speter		if (pc->p_rgid != gid) {
55624448Speter			pc->p_rgid = gid;
55731891Ssef			setsugid(p);
55824448Speter		}
55924448Speter		/*
56024448Speter		 * Set saved gid
56124448Speter		 *
56224448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
56324448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
56424448Speter		 * is important that we should do this.
56524448Speter		 */
56624448Speter		if (pc->p_svgid != gid) {
56724448Speter			pc->p_svgid = gid;
56831891Ssef			setsugid(p);
56924448Speter		}
5708141Sache	}
57124448Speter	/*
57224448Speter	 * In all cases permitted cases, we are changing the egid.
57324448Speter	 * Copy credentials so other references do not see our changes.
57424448Speter	 */
57524448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
57624448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
57724448Speter		pc->pc_ucred->cr_groups[0] = gid;
57831891Ssef		setsugid(p);
57924448Speter	}
5801541Srgrimes	return (0);
5811541Srgrimes}
5821541Srgrimes
58312221Sbde#ifndef _SYS_SYSPROTO_H_
5841541Srgrimesstruct setegid_args {
5851541Srgrimes	gid_t	egid;
5861541Srgrimes};
58712221Sbde#endif
5881541Srgrimes/* ARGSUSED */
5891549Srgrimesint
59030994Sphksetegid(p, uap)
5911541Srgrimes	struct proc *p;
5921541Srgrimes	struct setegid_args *uap;
5931541Srgrimes{
5941541Srgrimes	register struct pcred *pc = p->p_cred;
5951541Srgrimes	register gid_t egid;
5961541Srgrimes	int error;
5971541Srgrimes
5981541Srgrimes	egid = uap->egid;
59924449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
60024449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
60146155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
6021541Srgrimes		return (error);
60324449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
60424449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
60524449Speter		pc->pc_ucred->cr_groups[0] = egid;
60631891Ssef		setsugid(p);
60724449Speter	}
6081541Srgrimes	return (0);
6091541Srgrimes}
6101541Srgrimes
61112221Sbde#ifndef _SYS_SYSPROTO_H_
6121541Srgrimesstruct setgroups_args {
6131541Srgrimes	u_int	gidsetsize;
6141541Srgrimes	gid_t	*gidset;
6151541Srgrimes};
61612221Sbde#endif
6171541Srgrimes/* ARGSUSED */
6181549Srgrimesint
61930994Sphksetgroups(p, uap)
6201541Srgrimes	struct proc *p;
6211541Srgrimes	struct setgroups_args *uap;
6221541Srgrimes{
6231541Srgrimes	register struct pcred *pc = p->p_cred;
6241541Srgrimes	register u_int ngrp;
6251541Srgrimes	int error;
6261541Srgrimes
62746155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
6281541Srgrimes		return (error);
62912063Sdg	ngrp = uap->gidsetsize;
63024447Speter	if (ngrp > NGROUPS)
6311541Srgrimes		return (EINVAL);
63224447Speter	/*
63324447Speter	 * XXX A little bit lazy here.  We could test if anything has
63424447Speter	 * changed before crcopy() and setting P_SUGID.
63524447Speter	 */
6361541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
63724447Speter	if (ngrp < 1) {
63824447Speter		/*
63924447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
64024447Speter		 * groups vector on non-BSD systems (which generally do not
64124447Speter		 * have the egid in the groups[0]).  We risk security holes
64224447Speter		 * when running non-BSD software if we do not do the same.
64324447Speter		 */
64424447Speter		pc->pc_ucred->cr_ngroups = 1;
64524447Speter	} else {
64624447Speter		if ((error = copyin((caddr_t)uap->gidset,
64724447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
64824447Speter			return (error);
64924447Speter		pc->pc_ucred->cr_ngroups = ngrp;
65024447Speter	}
65131891Ssef	setsugid(p);
6521541Srgrimes	return (0);
6531541Srgrimes}
6541541Srgrimes
65512221Sbde#ifndef _SYS_SYSPROTO_H_
6561541Srgrimesstruct setreuid_args {
6579238Sache	uid_t	ruid;
6589238Sache	uid_t	euid;
6591541Srgrimes};
66012221Sbde#endif
6611541Srgrimes/* ARGSUSED */
6621549Srgrimesint
66330994Sphksetreuid(p, uap)
6641541Srgrimes	register struct proc *p;
6651541Srgrimes	struct setreuid_args *uap;
6661541Srgrimes{
6671541Srgrimes	register struct pcred *pc = p->p_cred;
6689238Sache	register uid_t ruid, euid;
6698135Sache	int error;
6701541Srgrimes
6719238Sache	ruid = uap->ruid;
6729238Sache	euid = uap->euid;
67343311Sdillon	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
67443311Sdillon	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
67543311Sdillon	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
67646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
6778135Sache		return (error);
6789238Sache
67924450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
68065495Struckman		change_euid(p, euid);
68131891Ssef		setsugid(p);
68224450Speter	}
68324450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
68465495Struckman		change_ruid(p, ruid);
68531891Ssef		setsugid(p);
6868135Sache	}
68724559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
68824559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6898111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
69031891Ssef		setsugid(p);
69124450Speter	}
6928135Sache	return (0);
6931541Srgrimes}
6941541Srgrimes
69512221Sbde#ifndef _SYS_SYSPROTO_H_
6961541Srgrimesstruct setregid_args {
6979238Sache	gid_t	rgid;
6989238Sache	gid_t	egid;
6991541Srgrimes};
70012221Sbde#endif
7011541Srgrimes/* ARGSUSED */
7021549Srgrimesint
70330994Sphksetregid(p, uap)
7041541Srgrimes	register struct proc *p;
7051541Srgrimes	struct setregid_args *uap;
7061541Srgrimes{
7071541Srgrimes	register struct pcred *pc = p->p_cred;
7089238Sache	register gid_t rgid, egid;
7098135Sache	int error;
7101541Srgrimes
7119238Sache	rgid = uap->rgid;
7129238Sache	egid = uap->egid;
71343311Sdillon	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
71443311Sdillon	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
71543311Sdillon	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
71646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
7178135Sache		return (error);
7189238Sache
71924450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
72024450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
7219238Sache		pc->pc_ucred->cr_groups[0] = egid;
72231891Ssef		setsugid(p);
72324450Speter	}
72424450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7259238Sache		pc->p_rgid = rgid;
72631891Ssef		setsugid(p);
72724450Speter	}
72824559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
72924559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7308111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
73131891Ssef		setsugid(p);
73224450Speter	}
7338135Sache	return (0);
7341541Srgrimes}
7351541Srgrimes
73656115Speter/*
73756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
73856115Speter * saved uid is explicit.
73956115Speter */
74056115Speter
74124453Speter#ifndef _SYS_SYSPROTO_H_
74256115Speterstruct setresuid_args {
74356115Speter	uid_t	ruid;
74456115Speter	uid_t	euid;
74556115Speter	uid_t	suid;
74656115Speter};
74756115Speter#endif
74856115Speter/* ARGSUSED */
74956115Speterint
75056115Spetersetresuid(p, uap)
75156115Speter	register struct proc *p;
75256115Speter	struct setresuid_args *uap;
75356115Speter{
75456115Speter	register struct pcred *pc = p->p_cred;
75556115Speter	register uid_t ruid, euid, suid;
75656115Speter	int error;
75756115Speter
75856115Speter	ruid = uap->ruid;
75956115Speter	euid = uap->euid;
76056115Speter	suid = uap->suid;
76156115Speter	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
76256115Speter	      ruid != pc->pc_ucred->cr_uid) ||
76356115Speter	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
76456115Speter	      euid != pc->pc_ucred->cr_uid) ||
76556115Speter	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
76656115Speter	      suid != pc->pc_ucred->cr_uid)) &&
76756115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
76856115Speter		return (error);
76956115Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
77065495Struckman		change_euid(p, euid);
77156115Speter		setsugid(p);
77256115Speter	}
77356115Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
77465495Struckman		change_ruid(p, ruid);
77556115Speter		setsugid(p);
77656115Speter	}
77756115Speter	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
77856115Speter		pc->p_svuid = suid;
77956115Speter		setsugid(p);
78056115Speter	}
78156115Speter	return (0);
78256115Speter}
78356115Speter
78456115Speter/*
78556115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
78656115Speter * saved gid is explicit.
78756115Speter */
78856115Speter
78956115Speter#ifndef _SYS_SYSPROTO_H_
79056115Speterstruct setresgid_args {
79156115Speter	gid_t	rgid;
79256115Speter	gid_t	egid;
79356115Speter	gid_t	sgid;
79456115Speter};
79556115Speter#endif
79656115Speter/* ARGSUSED */
79756115Speterint
79856115Spetersetresgid(p, uap)
79956115Speter	register struct proc *p;
80056115Speter	struct setresgid_args *uap;
80156115Speter{
80256115Speter	register struct pcred *pc = p->p_cred;
80356115Speter	register gid_t rgid, egid, sgid;
80456115Speter	int error;
80556115Speter
80656115Speter	rgid = uap->rgid;
80756115Speter	egid = uap->egid;
80856115Speter	sgid = uap->sgid;
80956115Speter	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
81056115Speter	      rgid != pc->pc_ucred->cr_groups[0]) ||
81156115Speter	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
81256115Speter	      egid != pc->pc_ucred->cr_groups[0]) ||
81356115Speter	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
81456115Speter	      sgid != pc->pc_ucred->cr_groups[0])) &&
81556115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
81656115Speter		return (error);
81756115Speter
81856115Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
81956115Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
82056115Speter		pc->pc_ucred->cr_groups[0] = egid;
82156115Speter		setsugid(p);
82256115Speter	}
82356115Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
82456115Speter		pc->p_rgid = rgid;
82556115Speter		setsugid(p);
82656115Speter	}
82756115Speter	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
82856115Speter		pc->p_svgid = sgid;
82956115Speter		setsugid(p);
83056115Speter	}
83156115Speter	return (0);
83256115Speter}
83356115Speter
83456115Speter#ifndef _SYS_SYSPROTO_H_
83556115Speterstruct getresuid_args {
83656115Speter	uid_t	*ruid;
83756115Speter	uid_t	*euid;
83856115Speter	uid_t	*suid;
83956115Speter};
84056115Speter#endif
84156115Speter/* ARGSUSED */
84256115Speterint
84356115Spetergetresuid(p, uap)
84456115Speter	register struct proc *p;
84556115Speter	struct getresuid_args *uap;
84656115Speter{
84756115Speter	struct pcred *pc = p->p_cred;
84856115Speter	int error1 = 0, error2 = 0, error3 = 0;
84956115Speter
85056115Speter	if (uap->ruid)
85156115Speter		error1 = copyout((caddr_t)&pc->p_ruid,
85256115Speter		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
85356115Speter	if (uap->euid)
85456115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
85556115Speter		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
85656115Speter	if (uap->suid)
85756115Speter		error3 = copyout((caddr_t)&pc->p_svuid,
85856115Speter		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
85956115Speter	return error1 ? error1 : (error2 ? error2 : error3);
86056115Speter}
86156115Speter
86256115Speter#ifndef _SYS_SYSPROTO_H_
86356115Speterstruct getresgid_args {
86456115Speter	gid_t	*rgid;
86556115Speter	gid_t	*egid;
86656115Speter	gid_t	*sgid;
86756115Speter};
86856115Speter#endif
86956115Speter/* ARGSUSED */
87056115Speterint
87156115Spetergetresgid(p, uap)
87256115Speter	register struct proc *p;
87356115Speter	struct getresgid_args *uap;
87456115Speter{
87556115Speter	struct pcred *pc = p->p_cred;
87656115Speter	int error1 = 0, error2 = 0, error3 = 0;
87756115Speter
87856115Speter	if (uap->rgid)
87956115Speter		error1 = copyout((caddr_t)&pc->p_rgid,
88056115Speter		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
88156115Speter	if (uap->egid)
88256115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
88356115Speter		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
88456115Speter	if (uap->sgid)
88556115Speter		error3 = copyout((caddr_t)&pc->p_svgid,
88656115Speter		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
88756115Speter	return error1 ? error1 : (error2 ? error2 : error3);
88856115Speter}
88956115Speter
89056115Speter
89156115Speter#ifndef _SYS_SYSPROTO_H_
89224453Speterstruct issetugid_args {
89324453Speter	int dummy;
89424453Speter};
89524453Speter#endif
89624453Speter/* ARGSUSED */
89724453Speterint
89830994Sphkissetugid(p, uap)
89924453Speter	register struct proc *p;
90024453Speter	struct issetugid_args *uap;
90124453Speter{
90224453Speter	/*
90324453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
90424453Speter	 * we use P_SUGID because we consider changing the owners as
90524453Speter	 * "tainting" as well.
90624453Speter	 * This is significant for procs that start as root and "become"
90724453Speter	 * a user without an exec - programs cannot know *everything*
90824453Speter	 * that libc *might* have put in their data segment.
90924453Speter	 */
91060216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
91124453Speter	return (0);
91224453Speter}
91324453Speter
9141541Srgrimes/*
9151541Srgrimes * Check if gid is a member of the group set.
9161541Srgrimes */
9171549Srgrimesint
9181541Srgrimesgroupmember(gid, cred)
9191541Srgrimes	gid_t gid;
9201541Srgrimes	register struct ucred *cred;
9211541Srgrimes{
9221541Srgrimes	register gid_t *gp;
9231541Srgrimes	gid_t *egp;
9241541Srgrimes
9251541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
9261541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
9271541Srgrimes		if (*gp == gid)
9281541Srgrimes			return (1);
9291541Srgrimes	return (0);
9301541Srgrimes}
9311541Srgrimes
93261287Srwatsonstatic int suser_permitted = 1;
93361287Srwatson
93461287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
93561287Srwatson    "processes with uid 0 have privilege");
93661287Srwatson
9371541Srgrimes/*
9381541Srgrimes * Test whether the specified credentials imply "super-user"
9391541Srgrimes * privilege; if so, and we have accounting info, set the flag
9401541Srgrimes * indicating use of super-powers.
9411541Srgrimes * Returns 0 or error.
9421541Srgrimes */
9431549Srgrimesint
94446112Sphksuser(p)
94572786Srwatson	struct proc *p;
94646112Sphk{
94746155Sphk	return suser_xxx(0, p, 0);
94846112Sphk}
94946112Sphk
95046112Sphkint
95146155Sphksuser_xxx(cred, proc, flag)
95272786Srwatson	struct ucred *cred;
95372786Srwatson	struct proc *proc;
95446155Sphk	int flag;
9551541Srgrimes{
95661282Srwatson	if (!suser_permitted)
95761282Srwatson		return (EPERM);
95846155Sphk	if (!cred && !proc) {
95946155Sphk		printf("suser_xxx(): THINK!\n");
96046155Sphk		return (EPERM);
9611541Srgrimes	}
96246155Sphk	if (!cred)
96346155Sphk		cred = proc->p_ucred;
96446155Sphk	if (cred->cr_uid != 0)
96546155Sphk		return (EPERM);
96672786Srwatson	if (jailed(cred) && !(flag & PRISON_ROOT))
96746155Sphk		return (EPERM);
96846155Sphk	return (0);
9691541Srgrimes}
9701541Srgrimes
97165237Srwatsonstatic int
97272786Srwatsonp_cansee(struct proc *p1, struct proc *p2, int *privused)
97365237Srwatson{
97472786Srwatson	int error;
97553518Sphk
97665237Srwatson	if (privused != NULL)
97765237Srwatson		*privused = 0;
97865237Srwatson
97972786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
98072786Srwatson		return (error);
98165237Srwatson
98265293Srwatson	if (!ps_showallprocs && p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) {
98365293Srwatson		if (suser_xxx(NULL, p1, PRISON_ROOT) == 0) {
98465293Srwatson			if (privused != NULL)
98565293Srwatson				*privused = 1;
98665293Srwatson			return (0);
98765293Srwatson		}
98865237Srwatson		return (ESRCH);
98965293Srwatson	}
99065237Srwatson
99165237Srwatson	return (0);
99265237Srwatson}
99365237Srwatson
99465237Srwatsonstatic int
99572786Srwatsonp_cankill(struct proc *p1, struct proc *p2, int *privused)
99653518Sphk{
99772786Srwatson	int error;
99853518Sphk
99965237Srwatson	if (privused != NULL)
100065237Srwatson		*privused = 0;
100165237Srwatson
100253518Sphk	if (p1 == p2)
100353518Sphk		return (0);
100465237Srwatson
100572786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
100672786Srwatson		return (error);
100765237Srwatson
100853518Sphk	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
100953518Sphk		return (0);
101053518Sphk	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
101153518Sphk		return (0);
101265237Srwatson	/*
101365237Srwatson	 * XXX should a process be able to affect another process
101465237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
101565237Srwatson	 */
101653518Sphk	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
101753518Sphk		return (0);
101853518Sphk	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
101953518Sphk		return (0);
102065237Srwatson
102165237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
102265237Srwatson		if (privused != NULL)
102365237Srwatson			*privused = 1;
102453518Sphk		return (0);
102565237Srwatson	}
102665237Srwatson
102765237Srwatson#ifdef CAPABILITIES
102865237Srwatson	if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) {
102965237Srwatson		if (privused != NULL)
103065237Srwatson			*privused = 1;
103165237Srwatson		return (0);
103265237Srwatson	}
103365237Srwatson#endif
103465237Srwatson
103553518Sphk	return (EPERM);
103653518Sphk}
103753518Sphk
103865237Srwatsonstatic int
103972786Srwatsonp_cansched(struct proc *p1, struct proc *p2, int *privused)
104065237Srwatson{
104172786Srwatson	int error;
104265237Srwatson
104365237Srwatson	if (privused != NULL)
104465237Srwatson		*privused = 0;
104565237Srwatson
104665237Srwatson	if (p1 == p2)
104765237Srwatson		return (0);
104865237Srwatson
104972786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
105072786Srwatson		return (error);
105165237Srwatson
105265237Srwatson	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
105365237Srwatson		return (0);
105465237Srwatson	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
105565237Srwatson		return (0);
105665237Srwatson	/*
105765237Srwatson	 * XXX should a process be able to affect another process
105865237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
105965237Srwatson	 */
106065237Srwatson	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
106165237Srwatson		return (0);
106265237Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
106365237Srwatson		return (0);
106465237Srwatson
106565237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
106665237Srwatson		if (privused != NULL)
106765237Srwatson			*privused = 1;
106865237Srwatson		return (0);
106965237Srwatson	}
107065237Srwatson
107165237Srwatson#ifdef CAPABILITIES
107265237Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) {
107365237Srwatson		if (privused != NULL)
107465237Srwatson			*privused = 1;
107565237Srwatson		return (0);
107665237Srwatson	}
107765237Srwatson#endif
107865237Srwatson
107965237Srwatson	return (EPERM);
108065237Srwatson}
108165237Srwatson
108265237Srwatsonstatic int
108372786Srwatsonp_candebug(struct proc *p1, struct proc *p2, int *privused)
108465237Srwatson{
108572786Srwatson	int error;
108665237Srwatson
108765237Srwatson	if (privused != NULL)
108865237Srwatson		*privused = 0;
108965237Srwatson
109065237Srwatson	/* XXX it is authorized, but semantics don't permit it */
109165237Srwatson	if (p1 == p2)
109265237Srwatson		return (0);
109365237Srwatson
109472786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
109572786Srwatson		return (error);
109665237Srwatson
109765237Srwatson	/* not owned by you, has done setuid (unless you're root) */
109865237Srwatson	/* add a CAP_SYS_PTRACE here? */
109967999Srwatson	if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid ||
110067999Srwatson	    p1->p_cred->p_ruid != p2->p_cred->p_ruid ||
110168591Srwatson	    p1->p_cred->p_svuid != p2->p_cred->p_ruid ||
110267999Srwatson	    p2->p_flag & P_SUGID) {
110365237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
110465237Srwatson			return (error);
110565237Srwatson		if (privused != NULL)
110665237Srwatson			*privused = 1;
110765237Srwatson	}
110865237Srwatson
110965237Srwatson	/* can't trace init when securelevel > 0 */
111065237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
111165237Srwatson		return (EPERM);
111265237Srwatson
111365237Srwatson	return (0);
111465237Srwatson}
111565237Srwatson
111665237Srwatsonint
111772786Srwatsonp_can(struct proc *p1, struct proc *p2, int operation,
111865237Srwatson    int *privused)
111965237Srwatson{
112065237Srwatson
112165237Srwatson	switch(operation) {
112265237Srwatson	case P_CAN_SEE:
112365237Srwatson		return (p_cansee(p1, p2, privused));
112465237Srwatson
112565237Srwatson	case P_CAN_KILL:
112665237Srwatson		return (p_cankill(p1, p2, privused));
112765237Srwatson
112865237Srwatson	case P_CAN_SCHED:
112965237Srwatson		return (p_cansched(p1, p2, privused));
113065237Srwatson
113165237Srwatson	case P_CAN_DEBUG:
113265237Srwatson		return (p_candebug(p1, p2, privused));
113365237Srwatson
113465237Srwatson	default:
113565237Srwatson		panic("p_can: invalid operation");
113665237Srwatson	}
113765237Srwatson}
113865237Srwatson
113965237Srwatson
114053518Sphk/*
11411541Srgrimes * Allocate a zeroed cred structure.
11421541Srgrimes */
11431541Srgrimesstruct ucred *
11441541Srgrimescrget()
11451541Srgrimes{
11461541Srgrimes	register struct ucred *cr;
11471541Srgrimes
114869239Salfred	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
11491541Srgrimes	cr->cr_ref = 1;
115069239Salfred	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
11511541Srgrimes	return (cr);
11521541Srgrimes}
11531541Srgrimes
11541541Srgrimes/*
115572474Srwatson * Claim another reference to a ucred structure
115669401Salfred */
115769401Salfredvoid
115869401Salfredcrhold(cr)
115969401Salfred	struct ucred *cr;
116069401Salfred{
116169401Salfred
116272200Sbmilekic	mtx_lock(&cr->cr_mtx);
116369401Salfred	cr->cr_ref++;
116472200Sbmilekic	mtx_unlock(&(cr)->cr_mtx);
116569401Salfred}
116669401Salfred
116769401Salfred
116869401Salfred/*
11691541Srgrimes * Free a cred structure.
11701541Srgrimes * Throws away space when ref count gets to 0.
11711541Srgrimes */
11721549Srgrimesvoid
11731541Srgrimescrfree(cr)
11741541Srgrimes	struct ucred *cr;
11751541Srgrimes{
117669239Salfred
117772200Sbmilekic	mtx_lock(&cr->cr_mtx);
117865495Struckman	if (--cr->cr_ref == 0) {
117969239Salfred		mtx_destroy(&cr->cr_mtx);
118065495Struckman		/*
118165495Struckman		 * Some callers of crget(), such as nfs_statfs(),
118265495Struckman		 * allocate a temporary credential, but don't
118365495Struckman		 * allocate a uidinfo structure.
118465495Struckman		 */
118565495Struckman		if (cr->cr_uidinfo != NULL)
118665495Struckman			uifree(cr->cr_uidinfo);
118772786Srwatson		/*
118872786Srwatson		 * Free a prison, if any.
118972786Srwatson		 */
119072786Srwatson		if (jailed(cr))
119172786Srwatson			prison_free(cr->cr_prison);
11921541Srgrimes		FREE((caddr_t)cr, M_CRED);
119369239Salfred	} else {
119472200Sbmilekic		mtx_unlock(&cr->cr_mtx);
119565495Struckman	}
11961541Srgrimes}
11971541Srgrimes
11981541Srgrimes/*
11991541Srgrimes * Copy cred structure to a new one and free the old one.
12001541Srgrimes */
12011541Srgrimesstruct ucred *
12021541Srgrimescrcopy(cr)
12031541Srgrimes	struct ucred *cr;
12041541Srgrimes{
12051541Srgrimes	struct ucred *newcr;
12061541Srgrimes
120772200Sbmilekic	mtx_lock(&cr->cr_mtx);
120869239Salfred	if (cr->cr_ref == 1) {
120972200Sbmilekic		mtx_unlock(&cr->cr_mtx);
12101541Srgrimes		return (cr);
121169239Salfred	}
121272200Sbmilekic	mtx_unlock(&cr->cr_mtx);
121369239Salfred	newcr = crdup(cr);
12141541Srgrimes	crfree(cr);
12151541Srgrimes	return (newcr);
12161541Srgrimes}
12171541Srgrimes
12181541Srgrimes/*
12191541Srgrimes * Dup cred struct to a new held one.
12201541Srgrimes */
12211541Srgrimesstruct ucred *
12221541Srgrimescrdup(cr)
12231541Srgrimes	struct ucred *cr;
12241541Srgrimes{
12251541Srgrimes	struct ucred *newcr;
12261541Srgrimes
122769239Salfred	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
12281541Srgrimes	*newcr = *cr;
122969239Salfred	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
123065495Struckman	uihold(newcr->cr_uidinfo);
123172786Srwatson	if (jailed(newcr))
123272786Srwatson		prison_hold(newcr->cr_prison);
12331541Srgrimes	newcr->cr_ref = 1;
12341541Srgrimes	return (newcr);
12351541Srgrimes}
12361541Srgrimes
12371541Srgrimes/*
12381541Srgrimes * Get login name, if available.
12391541Srgrimes */
124012221Sbde#ifndef _SYS_SYSPROTO_H_
12411541Srgrimesstruct getlogin_args {
12421541Srgrimes	char	*namebuf;
12431541Srgrimes	u_int	namelen;
12441541Srgrimes};
124512221Sbde#endif
12461541Srgrimes/* ARGSUSED */
12471549Srgrimesint
124830994Sphkgetlogin(p, uap)
12491541Srgrimes	struct proc *p;
12501541Srgrimes	struct getlogin_args *uap;
12511541Srgrimes{
12521541Srgrimes
125323358Sache	if (uap->namelen > MAXLOGNAME)
125423359Sache		uap->namelen = MAXLOGNAME;
12551541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
12561541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
12571541Srgrimes}
12581541Srgrimes
12591541Srgrimes/*
12601541Srgrimes * Set login name.
12611541Srgrimes */
126212221Sbde#ifndef _SYS_SYSPROTO_H_
12631541Srgrimesstruct setlogin_args {
12641541Srgrimes	char	*namebuf;
12651541Srgrimes};
126612221Sbde#endif
12671541Srgrimes/* ARGSUSED */
12681549Srgrimesint
126930994Sphksetlogin(p, uap)
12701541Srgrimes	struct proc *p;
12711541Srgrimes	struct setlogin_args *uap;
12721541Srgrimes{
12731541Srgrimes	int error;
127423330Sache	char logintmp[MAXLOGNAME];
12751541Srgrimes
127646155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
12771541Srgrimes		return (error);
127822522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
127936845Sdfr	    sizeof(logintmp), (size_t *)0);
12801541Srgrimes	if (error == ENAMETOOLONG)
12811541Srgrimes		error = EINVAL;
128222522Sdavidn	else if (!error)
128322522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
128423330Sache		    sizeof(logintmp));
12851541Srgrimes	return (error);
12861541Srgrimes}
128731891Ssef
128831891Ssefvoid
128931891Ssefsetsugid(p)
129055338Sphk	struct proc *p;
129131891Ssef{
129231891Ssef	p->p_flag |= P_SUGID;
129355707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
129431891Ssef		p->p_stops = 0;
129531891Ssef}
129665495Struckman
129765495Struckman/*
129865495Struckman * Helper function to change the effective uid of a process
129965495Struckman */
130065495Struckmanvoid
130165495Struckmanchange_euid(p, euid)
130265495Struckman	struct	proc *p;
130365495Struckman	uid_t	euid;
130465495Struckman{
130565495Struckman	struct	pcred *pc;
130665495Struckman	struct	uidinfo *uip;
130765495Struckman
130865495Struckman	pc = p->p_cred;
130965495Struckman	/*
131065495Struckman	 * crcopy is essentially a NOP if ucred has a reference count
131165495Struckman	 * of 1, which is true if it has already been copied.
131265495Struckman	 */
131365495Struckman	pc->pc_ucred = crcopy(pc->pc_ucred);
131465495Struckman	uip = pc->pc_ucred->cr_uidinfo;
131565495Struckman	pc->pc_ucred->cr_uid = euid;
131665495Struckman	pc->pc_ucred->cr_uidinfo = uifind(euid);
131765495Struckman	uifree(uip);
131865495Struckman}
131965495Struckman
132065495Struckman/*
132165495Struckman * Helper function to change the real uid of a process
132265495Struckman *
132365495Struckman * The per-uid process count for this process is transfered from
132465495Struckman * the old uid to the new uid.
132565495Struckman */
132667629Sgallatinvoid
132765495Struckmanchange_ruid(p, ruid)
132865495Struckman	struct	proc *p;
132965495Struckman	uid_t	ruid;
133065495Struckman{
133165495Struckman	struct	pcred *pc;
133265495Struckman	struct	uidinfo *uip;
133365495Struckman
133465495Struckman	pc = p->p_cred;
133565495Struckman	(void)chgproccnt(pc->p_uidinfo, -1, 0);
133665495Struckman	uip = pc->p_uidinfo;
133765495Struckman	/* It is assumed that pcred is not shared between processes */
133865495Struckman	pc->p_ruid = ruid;
133965495Struckman	pc->p_uidinfo = uifind(ruid);
134065495Struckman	(void)chgproccnt(pc->p_uidinfo, 1, 0);
134165495Struckman	uifree(uip);
134265495Struckman}
1343