kern_prot.c revision 75448
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 75448 2001-04-12 19:39:00Z 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;
14675448Srwatson	int error;
14741726Struckman
14841726Struckman	pt = p;
14928401Speter	if (uap->pid == 0)
15028401Speter		goto found;
15128401Speter
15241726Struckman	if ((pt = pfind(uap->pid)) == 0)
15328401Speter		return ESRCH;
15475448Srwatson	if ((error = p_can(p, pt, P_CAN_SEE, NULL)))
15575448Srwatson		return (error);
15628401Speterfound:
15741726Struckman	p->p_retval[0] = pt->p_pgrp->pg_id;
15828401Speter	return 0;
15928401Speter}
16028401Speter
16128401Speter/*
16228401Speter * Get an arbitary pid's session id.
16328401Speter */
16428401Speter#ifndef _SYS_SYSPROTO_H_
16528401Speterstruct getsid_args {
16628401Speter	pid_t	pid;
16728401Speter};
16828401Speter#endif
16928401Speter
17028401Speterint
17130994Sphkgetsid(p, uap)
17228401Speter	struct proc *p;
17328401Speter	struct getsid_args *uap;
17428401Speter{
17541726Struckman	struct proc *pt;
17675448Srwatson	int error;
17741726Struckman
17841726Struckman	pt = p;
17928401Speter	if (uap->pid == 0)
18028401Speter		goto found;
18128401Speter
18271002Sben	if ((pt = pfind(uap->pid)) == 0)
18328401Speter		return ESRCH;
18475448Srwatson	if ((error = p_can(p, pt, P_CAN_SEE, NULL)))
18575448Srwatson		return (error);
18628401Speterfound:
18741726Struckman	p->p_retval[0] = pt->p_session->s_sid;
18828401Speter	return 0;
18928401Speter}
19028401Speter
19128401Speter
19258941Sdillon/*
19358941Sdillon * getuid() - MP SAFE
19458941Sdillon */
19528401Speter#ifndef _SYS_SYSPROTO_H_
19611332Sswallacestruct getuid_args {
19711332Sswallace        int     dummy;
19811332Sswallace};
19912221Sbde#endif
20011332Sswallace
2011541Srgrimes/* ARGSUSED */
2021549Srgrimesint
20330994Sphkgetuid(p, uap)
2041541Srgrimes	struct proc *p;
20511332Sswallace	struct getuid_args *uap;
2061541Srgrimes{
2071541Srgrimes
20830994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
2091541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
21030994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
2111541Srgrimes#endif
2121541Srgrimes	return (0);
2131541Srgrimes}
2141541Srgrimes
21558941Sdillon/*
21658941Sdillon * geteuid() - MP SAFE
21758941Sdillon */
21812221Sbde#ifndef _SYS_SYSPROTO_H_
21911332Sswallacestruct geteuid_args {
22011332Sswallace        int     dummy;
22111332Sswallace};
22212221Sbde#endif
22311332Sswallace
2241541Srgrimes/* ARGSUSED */
2251549Srgrimesint
22630994Sphkgeteuid(p, uap)
2271541Srgrimes	struct proc *p;
22811332Sswallace	struct geteuid_args *uap;
2291541Srgrimes{
2301541Srgrimes
23130994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2321541Srgrimes	return (0);
2331541Srgrimes}
2341541Srgrimes
23558941Sdillon/*
23658941Sdillon * getgid() - MP SAFE
23758941Sdillon */
23812221Sbde#ifndef _SYS_SYSPROTO_H_
23911332Sswallacestruct getgid_args {
24011332Sswallace        int     dummy;
24111332Sswallace};
24212221Sbde#endif
24311332Sswallace
2441541Srgrimes/* ARGSUSED */
2451549Srgrimesint
24630994Sphkgetgid(p, uap)
2471541Srgrimes	struct proc *p;
24811332Sswallace	struct getgid_args *uap;
2491541Srgrimes{
2501541Srgrimes
25130994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2521541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
25330994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2541541Srgrimes#endif
2551541Srgrimes	return (0);
2561541Srgrimes}
2571541Srgrimes
2581541Srgrimes/*
2591541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2601541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2611541Srgrimes * correctly in a library function.
2621541Srgrimes */
26312221Sbde#ifndef _SYS_SYSPROTO_H_
26411332Sswallacestruct getegid_args {
26511332Sswallace        int     dummy;
26611332Sswallace};
26712221Sbde#endif
26811332Sswallace
2691541Srgrimes/* ARGSUSED */
2701549Srgrimesint
27130994Sphkgetegid(p, uap)
2721541Srgrimes	struct proc *p;
27311332Sswallace	struct getegid_args *uap;
2741541Srgrimes{
2751541Srgrimes
27630994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2771541Srgrimes	return (0);
2781541Srgrimes}
2791541Srgrimes
28012221Sbde#ifndef _SYS_SYSPROTO_H_
2811541Srgrimesstruct getgroups_args {
2821541Srgrimes	u_int	gidsetsize;
2831541Srgrimes	gid_t	*gidset;
2841541Srgrimes};
28512221Sbde#endif
2861549Srgrimesint
28730994Sphkgetgroups(p, uap)
2881541Srgrimes	struct proc *p;
2891541Srgrimes	register struct	getgroups_args *uap;
2901541Srgrimes{
2911541Srgrimes	register struct pcred *pc = p->p_cred;
2921541Srgrimes	register u_int ngrp;
2931541Srgrimes	int error;
2941541Srgrimes
2951541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
29630994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2971541Srgrimes		return (0);
2981541Srgrimes	}
2991541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
3001541Srgrimes		return (EINVAL);
3011541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
3023098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
3033098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
3041541Srgrimes		return (error);
30530994Sphk	p->p_retval[0] = ngrp;
3061541Srgrimes	return (0);
3071541Srgrimes}
3081541Srgrimes
30912221Sbde#ifndef _SYS_SYSPROTO_H_
31012207Sbdestruct setsid_args {
31111332Sswallace        int     dummy;
31211332Sswallace};
31312221Sbde#endif
31411332Sswallace
3151541Srgrimes/* ARGSUSED */
3161549Srgrimesint
31730994Sphksetsid(p, uap)
3181541Srgrimes	register struct proc *p;
31912207Sbde	struct setsid_args *uap;
3201541Srgrimes{
3211541Srgrimes
3221541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3231541Srgrimes		return (EPERM);
3241541Srgrimes	} else {
3251541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
32630994Sphk		p->p_retval[0] = p->p_pid;
3271541Srgrimes		return (0);
3281541Srgrimes	}
3291541Srgrimes}
3301541Srgrimes
3311541Srgrimes/*
3321541Srgrimes * set process group (setpgid/old setpgrp)
3331541Srgrimes *
3341541Srgrimes * caller does setpgid(targpid, targpgid)
3351541Srgrimes *
3361541Srgrimes * pid must be caller or child of caller (ESRCH)
3371541Srgrimes * if a child
3381541Srgrimes *	pid must be in same session (EPERM)
3391541Srgrimes *	pid can't have done an exec (EACCES)
3401541Srgrimes * if pgid != pid
3411541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3421541Srgrimes * pid must not be session leader (EPERM)
3431541Srgrimes */
34412221Sbde#ifndef _SYS_SYSPROTO_H_
3451541Srgrimesstruct setpgid_args {
3461541Srgrimes	int	pid;	/* target process id */
3471541Srgrimes	int	pgid;	/* target pgrp id */
3481541Srgrimes};
34912221Sbde#endif
3501541Srgrimes/* ARGSUSED */
3511549Srgrimesint
35230994Sphksetpgid(curp, uap)
3531541Srgrimes	struct proc *curp;
3541541Srgrimes	register struct setpgid_args *uap;
3551541Srgrimes{
3561541Srgrimes	register struct proc *targp;		/* target process */
3571541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
35875448Srwatson	int error;
3591541Srgrimes
36020677Sbde	if (uap->pgid < 0)
36120677Sbde		return (EINVAL);
3621541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3631541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3641541Srgrimes			return (ESRCH);
36575448Srwatson		if ((error = p_can(curproc, targp, P_CAN_SEE, NULL)))
36675448Srwatson			return (error);
36715985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3681541Srgrimes			return (EPERM);
3691541Srgrimes		if (targp->p_flag & P_EXEC)
3701541Srgrimes			return (EACCES);
3711541Srgrimes	} else
3721541Srgrimes		targp = curp;
3731541Srgrimes	if (SESS_LEADER(targp))
3741541Srgrimes		return (EPERM);
3751541Srgrimes	if (uap->pgid == 0)
3761541Srgrimes		uap->pgid = targp->p_pid;
3771541Srgrimes	else if (uap->pgid != targp->p_pid)
3781541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3791541Srgrimes	            pgrp->pg_session != curp->p_session)
3801541Srgrimes			return (EPERM);
3811541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3821541Srgrimes}
3831541Srgrimes
38424448Speter/*
38524448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
38672093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
38724448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
38824448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
38924448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
39024448Speter * does not set the saved id - this is dangerous for traditional BSD
39124448Speter * programs.  For this reason, we *really* do not want to set
39224448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
39324448Speter */
39424448Speter#define POSIX_APPENDIX_B_4_2_2
39524448Speter
39612221Sbde#ifndef _SYS_SYSPROTO_H_
3971541Srgrimesstruct setuid_args {
3981541Srgrimes	uid_t	uid;
3991541Srgrimes};
40012221Sbde#endif
4011541Srgrimes/* ARGSUSED */
4021549Srgrimesint
40330994Sphksetuid(p, uap)
4041541Srgrimes	struct proc *p;
4051541Srgrimes	struct setuid_args *uap;
4061541Srgrimes{
4071541Srgrimes	register struct pcred *pc = p->p_cred;
4081541Srgrimes	register uid_t uid;
4091541Srgrimes	int error;
4101541Srgrimes
41124448Speter	/*
41224448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
41324448Speter	 *
41424448Speter	 * Note that setuid(geteuid()) is a special case of
41524448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
41672093Sasmodai	 * to use this clause to be compatible with traditional BSD
41724448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
41824448Speter	 * three id's (assuming you have privs).
41924448Speter	 *
42024448Speter	 * Notes on the logic.  We do things in three steps.
42124448Speter	 * 1: We determine if the euid is going to change, and do EPERM
42224448Speter	 *    right away.  We unconditionally change the euid later if this
42324448Speter	 *    test is satisfied, simplifying that part of the logic.
42424448Speter	 * 2: We determine if the real and/or saved uid's are going to
42524448Speter	 *    change.  Determined by compile options.
42624448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
42724448Speter	 */
4281541Srgrimes	uid = uap->uid;
42924448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
43017994Sache#ifdef _POSIX_SAVED_IDS
43124448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
43217994Sache#endif
43324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
43424448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
43524448Speter#endif
43646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4371541Srgrimes		return (error);
43824448Speter
43924448Speter#ifdef _POSIX_SAVED_IDS
4401541Srgrimes	/*
44124448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
44224448Speter	 * If so, we are changing the real uid and/or saved uid.
4431541Srgrimes	 */
44417994Sache	if (
44524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
44624448Speter	    uid == pc->pc_ucred->cr_uid ||
44717994Sache#endif
44846155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
44917994Sache#endif
45024448Speter	{
45124448Speter		/*
45265495Struckman		 * Set the real uid and transfer proc count to new user.
45324448Speter		 */
45424448Speter		if (uid != pc->p_ruid) {
45565495Struckman			change_ruid(p, uid);
45665495Struckman			setsugid(p);
45724448Speter		}
45824448Speter		/*
45924448Speter		 * Set saved uid
46024448Speter		 *
46124448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
46224448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
46324448Speter		 * is important that we should do this.
46424448Speter		 */
46524448Speter		if (pc->p_svuid != uid) {
46624448Speter			pc->p_svuid = uid;
46731891Ssef			setsugid(p);
46824448Speter		}
4698141Sache	}
47024448Speter
47124448Speter	/*
47224448Speter	 * In all permitted cases, we are changing the euid.
47324448Speter	 * Copy credentials so other references do not see our changes.
47424448Speter	 */
47524448Speter	if (pc->pc_ucred->cr_uid != uid) {
47665495Struckman		change_euid(p, uid);
47731891Ssef		setsugid(p);
47824448Speter	}
4791541Srgrimes	return (0);
4801541Srgrimes}
4811541Srgrimes
48212221Sbde#ifndef _SYS_SYSPROTO_H_
4831541Srgrimesstruct seteuid_args {
4841541Srgrimes	uid_t	euid;
4851541Srgrimes};
48612221Sbde#endif
4871541Srgrimes/* ARGSUSED */
4881549Srgrimesint
48930994Sphkseteuid(p, uap)
4901541Srgrimes	struct proc *p;
4911541Srgrimes	struct seteuid_args *uap;
4921541Srgrimes{
4931541Srgrimes	register struct pcred *pc = p->p_cred;
4941541Srgrimes	register uid_t euid;
4951541Srgrimes	int error;
4961541Srgrimes
4971541Srgrimes	euid = uap->euid;
49824449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
49924449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
50046155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5011541Srgrimes		return (error);
5021541Srgrimes	/*
5031541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
5041541Srgrimes	 * not see our changes.
5051541Srgrimes	 */
50624449Speter	if (pc->pc_ucred->cr_uid != euid) {
50765495Struckman		change_euid(p, euid);
50831891Ssef		setsugid(p);
50924449Speter	}
5101541Srgrimes	return (0);
5111541Srgrimes}
5121541Srgrimes
51312221Sbde#ifndef _SYS_SYSPROTO_H_
5141541Srgrimesstruct setgid_args {
5151541Srgrimes	gid_t	gid;
5161541Srgrimes};
51712221Sbde#endif
5181541Srgrimes/* ARGSUSED */
5191549Srgrimesint
52030994Sphksetgid(p, uap)
5211541Srgrimes	struct proc *p;
5221541Srgrimes	struct setgid_args *uap;
5231541Srgrimes{
5241541Srgrimes	register struct pcred *pc = p->p_cred;
5251541Srgrimes	register gid_t gid;
5261541Srgrimes	int error;
5271541Srgrimes
52824448Speter	/*
52924448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
53024448Speter	 *
53124448Speter	 * Note that setgid(getegid()) is a special case of
53224448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
53372093Sasmodai	 * to use this clause to be compatible with traditional BSD
53424448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
53524448Speter	 * three id's (assuming you have privs).
53624448Speter	 *
53724448Speter	 * For notes on the logic here, see setuid() above.
53824448Speter	 */
5391541Srgrimes	gid = uap->gid;
54024448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
54117994Sache#ifdef _POSIX_SAVED_IDS
54224448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
54317994Sache#endif
54424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
54524448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
54624448Speter#endif
54746155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5481541Srgrimes		return (error);
54924448Speter
55017994Sache#ifdef _POSIX_SAVED_IDS
55124448Speter	/*
55224448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
55324448Speter	 * If so, we are changing the real uid and saved gid.
55424448Speter	 */
55524448Speter	if (
55624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
55724448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
55817994Sache#endif
55946155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
56024448Speter#endif
56124448Speter	{
56224448Speter		/*
56324448Speter		 * Set real gid
56424448Speter		 */
56524448Speter		if (pc->p_rgid != gid) {
56624448Speter			pc->p_rgid = gid;
56731891Ssef			setsugid(p);
56824448Speter		}
56924448Speter		/*
57024448Speter		 * Set saved gid
57124448Speter		 *
57224448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
57324448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
57424448Speter		 * is important that we should do this.
57524448Speter		 */
57624448Speter		if (pc->p_svgid != gid) {
57724448Speter			pc->p_svgid = gid;
57831891Ssef			setsugid(p);
57924448Speter		}
5808141Sache	}
58124448Speter	/*
58224448Speter	 * In all cases permitted cases, we are changing the egid.
58324448Speter	 * Copy credentials so other references do not see our changes.
58424448Speter	 */
58524448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
58624448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
58724448Speter		pc->pc_ucred->cr_groups[0] = gid;
58831891Ssef		setsugid(p);
58924448Speter	}
5901541Srgrimes	return (0);
5911541Srgrimes}
5921541Srgrimes
59312221Sbde#ifndef _SYS_SYSPROTO_H_
5941541Srgrimesstruct setegid_args {
5951541Srgrimes	gid_t	egid;
5961541Srgrimes};
59712221Sbde#endif
5981541Srgrimes/* ARGSUSED */
5991549Srgrimesint
60030994Sphksetegid(p, uap)
6011541Srgrimes	struct proc *p;
6021541Srgrimes	struct setegid_args *uap;
6031541Srgrimes{
6041541Srgrimes	register struct pcred *pc = p->p_cred;
6051541Srgrimes	register gid_t egid;
6061541Srgrimes	int error;
6071541Srgrimes
6081541Srgrimes	egid = uap->egid;
60924449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
61024449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
61146155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
6121541Srgrimes		return (error);
61324449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
61424449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
61524449Speter		pc->pc_ucred->cr_groups[0] = egid;
61631891Ssef		setsugid(p);
61724449Speter	}
6181541Srgrimes	return (0);
6191541Srgrimes}
6201541Srgrimes
62112221Sbde#ifndef _SYS_SYSPROTO_H_
6221541Srgrimesstruct setgroups_args {
6231541Srgrimes	u_int	gidsetsize;
6241541Srgrimes	gid_t	*gidset;
6251541Srgrimes};
62612221Sbde#endif
6271541Srgrimes/* ARGSUSED */
6281549Srgrimesint
62930994Sphksetgroups(p, uap)
6301541Srgrimes	struct proc *p;
6311541Srgrimes	struct setgroups_args *uap;
6321541Srgrimes{
6331541Srgrimes	register struct pcred *pc = p->p_cred;
6341541Srgrimes	register u_int ngrp;
6351541Srgrimes	int error;
6361541Srgrimes
63746155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
6381541Srgrimes		return (error);
63912063Sdg	ngrp = uap->gidsetsize;
64024447Speter	if (ngrp > NGROUPS)
6411541Srgrimes		return (EINVAL);
64224447Speter	/*
64324447Speter	 * XXX A little bit lazy here.  We could test if anything has
64424447Speter	 * changed before crcopy() and setting P_SUGID.
64524447Speter	 */
6461541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
64724447Speter	if (ngrp < 1) {
64824447Speter		/*
64924447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
65024447Speter		 * groups vector on non-BSD systems (which generally do not
65124447Speter		 * have the egid in the groups[0]).  We risk security holes
65224447Speter		 * when running non-BSD software if we do not do the same.
65324447Speter		 */
65424447Speter		pc->pc_ucred->cr_ngroups = 1;
65524447Speter	} else {
65624447Speter		if ((error = copyin((caddr_t)uap->gidset,
65724447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
65824447Speter			return (error);
65924447Speter		pc->pc_ucred->cr_ngroups = ngrp;
66024447Speter	}
66131891Ssef	setsugid(p);
6621541Srgrimes	return (0);
6631541Srgrimes}
6641541Srgrimes
66512221Sbde#ifndef _SYS_SYSPROTO_H_
6661541Srgrimesstruct setreuid_args {
6679238Sache	uid_t	ruid;
6689238Sache	uid_t	euid;
6691541Srgrimes};
67012221Sbde#endif
6711541Srgrimes/* ARGSUSED */
6721549Srgrimesint
67330994Sphksetreuid(p, uap)
6741541Srgrimes	register struct proc *p;
6751541Srgrimes	struct setreuid_args *uap;
6761541Srgrimes{
6771541Srgrimes	register struct pcred *pc = p->p_cred;
6789238Sache	register uid_t ruid, euid;
6798135Sache	int error;
6801541Srgrimes
6819238Sache	ruid = uap->ruid;
6829238Sache	euid = uap->euid;
68343311Sdillon	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
68443311Sdillon	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
68543311Sdillon	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
68646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
6878135Sache		return (error);
6889238Sache
68924450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
69065495Struckman		change_euid(p, euid);
69131891Ssef		setsugid(p);
69224450Speter	}
69324450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
69465495Struckman		change_ruid(p, ruid);
69531891Ssef		setsugid(p);
6968135Sache	}
69724559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
69824559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6998111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
70031891Ssef		setsugid(p);
70124450Speter	}
7028135Sache	return (0);
7031541Srgrimes}
7041541Srgrimes
70512221Sbde#ifndef _SYS_SYSPROTO_H_
7061541Srgrimesstruct setregid_args {
7079238Sache	gid_t	rgid;
7089238Sache	gid_t	egid;
7091541Srgrimes};
71012221Sbde#endif
7111541Srgrimes/* ARGSUSED */
7121549Srgrimesint
71330994Sphksetregid(p, uap)
7141541Srgrimes	register struct proc *p;
7151541Srgrimes	struct setregid_args *uap;
7161541Srgrimes{
7171541Srgrimes	register struct pcred *pc = p->p_cred;
7189238Sache	register gid_t rgid, egid;
7198135Sache	int error;
7201541Srgrimes
7219238Sache	rgid = uap->rgid;
7229238Sache	egid = uap->egid;
72343311Sdillon	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
72443311Sdillon	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
72543311Sdillon	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
72646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
7278135Sache		return (error);
7289238Sache
72924450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
73024450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
7319238Sache		pc->pc_ucred->cr_groups[0] = egid;
73231891Ssef		setsugid(p);
73324450Speter	}
73424450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7359238Sache		pc->p_rgid = rgid;
73631891Ssef		setsugid(p);
73724450Speter	}
73824559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
73924559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7408111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
74131891Ssef		setsugid(p);
74224450Speter	}
7438135Sache	return (0);
7441541Srgrimes}
7451541Srgrimes
74656115Speter/*
74756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
74856115Speter * saved uid is explicit.
74956115Speter */
75056115Speter
75124453Speter#ifndef _SYS_SYSPROTO_H_
75256115Speterstruct setresuid_args {
75356115Speter	uid_t	ruid;
75456115Speter	uid_t	euid;
75556115Speter	uid_t	suid;
75656115Speter};
75756115Speter#endif
75856115Speter/* ARGSUSED */
75956115Speterint
76056115Spetersetresuid(p, uap)
76156115Speter	register struct proc *p;
76256115Speter	struct setresuid_args *uap;
76356115Speter{
76456115Speter	register struct pcred *pc = p->p_cred;
76556115Speter	register uid_t ruid, euid, suid;
76656115Speter	int error;
76756115Speter
76856115Speter	ruid = uap->ruid;
76956115Speter	euid = uap->euid;
77056115Speter	suid = uap->suid;
77156115Speter	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
77256115Speter	      ruid != pc->pc_ucred->cr_uid) ||
77356115Speter	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
77456115Speter	      euid != pc->pc_ucred->cr_uid) ||
77556115Speter	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
77656115Speter	      suid != pc->pc_ucred->cr_uid)) &&
77756115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
77856115Speter		return (error);
77956115Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
78065495Struckman		change_euid(p, euid);
78156115Speter		setsugid(p);
78256115Speter	}
78356115Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
78465495Struckman		change_ruid(p, ruid);
78556115Speter		setsugid(p);
78656115Speter	}
78756115Speter	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
78856115Speter		pc->p_svuid = suid;
78956115Speter		setsugid(p);
79056115Speter	}
79156115Speter	return (0);
79256115Speter}
79356115Speter
79456115Speter/*
79556115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
79656115Speter * saved gid is explicit.
79756115Speter */
79856115Speter
79956115Speter#ifndef _SYS_SYSPROTO_H_
80056115Speterstruct setresgid_args {
80156115Speter	gid_t	rgid;
80256115Speter	gid_t	egid;
80356115Speter	gid_t	sgid;
80456115Speter};
80556115Speter#endif
80656115Speter/* ARGSUSED */
80756115Speterint
80856115Spetersetresgid(p, uap)
80956115Speter	register struct proc *p;
81056115Speter	struct setresgid_args *uap;
81156115Speter{
81256115Speter	register struct pcred *pc = p->p_cred;
81356115Speter	register gid_t rgid, egid, sgid;
81456115Speter	int error;
81556115Speter
81656115Speter	rgid = uap->rgid;
81756115Speter	egid = uap->egid;
81856115Speter	sgid = uap->sgid;
81956115Speter	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
82056115Speter	      rgid != pc->pc_ucred->cr_groups[0]) ||
82156115Speter	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
82256115Speter	      egid != pc->pc_ucred->cr_groups[0]) ||
82356115Speter	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
82456115Speter	      sgid != pc->pc_ucred->cr_groups[0])) &&
82556115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
82656115Speter		return (error);
82756115Speter
82856115Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
82956115Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
83056115Speter		pc->pc_ucred->cr_groups[0] = egid;
83156115Speter		setsugid(p);
83256115Speter	}
83356115Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
83456115Speter		pc->p_rgid = rgid;
83556115Speter		setsugid(p);
83656115Speter	}
83756115Speter	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
83856115Speter		pc->p_svgid = sgid;
83956115Speter		setsugid(p);
84056115Speter	}
84156115Speter	return (0);
84256115Speter}
84356115Speter
84456115Speter#ifndef _SYS_SYSPROTO_H_
84556115Speterstruct getresuid_args {
84656115Speter	uid_t	*ruid;
84756115Speter	uid_t	*euid;
84856115Speter	uid_t	*suid;
84956115Speter};
85056115Speter#endif
85156115Speter/* ARGSUSED */
85256115Speterint
85356115Spetergetresuid(p, uap)
85456115Speter	register struct proc *p;
85556115Speter	struct getresuid_args *uap;
85656115Speter{
85756115Speter	struct pcred *pc = p->p_cred;
85856115Speter	int error1 = 0, error2 = 0, error3 = 0;
85956115Speter
86056115Speter	if (uap->ruid)
86156115Speter		error1 = copyout((caddr_t)&pc->p_ruid,
86256115Speter		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
86356115Speter	if (uap->euid)
86456115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
86556115Speter		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
86656115Speter	if (uap->suid)
86756115Speter		error3 = copyout((caddr_t)&pc->p_svuid,
86856115Speter		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
86956115Speter	return error1 ? error1 : (error2 ? error2 : error3);
87056115Speter}
87156115Speter
87256115Speter#ifndef _SYS_SYSPROTO_H_
87356115Speterstruct getresgid_args {
87456115Speter	gid_t	*rgid;
87556115Speter	gid_t	*egid;
87656115Speter	gid_t	*sgid;
87756115Speter};
87856115Speter#endif
87956115Speter/* ARGSUSED */
88056115Speterint
88156115Spetergetresgid(p, uap)
88256115Speter	register struct proc *p;
88356115Speter	struct getresgid_args *uap;
88456115Speter{
88556115Speter	struct pcred *pc = p->p_cred;
88656115Speter	int error1 = 0, error2 = 0, error3 = 0;
88756115Speter
88856115Speter	if (uap->rgid)
88956115Speter		error1 = copyout((caddr_t)&pc->p_rgid,
89056115Speter		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
89156115Speter	if (uap->egid)
89256115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
89356115Speter		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
89456115Speter	if (uap->sgid)
89556115Speter		error3 = copyout((caddr_t)&pc->p_svgid,
89656115Speter		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
89756115Speter	return error1 ? error1 : (error2 ? error2 : error3);
89856115Speter}
89956115Speter
90056115Speter
90156115Speter#ifndef _SYS_SYSPROTO_H_
90224453Speterstruct issetugid_args {
90324453Speter	int dummy;
90424453Speter};
90524453Speter#endif
90624453Speter/* ARGSUSED */
90724453Speterint
90830994Sphkissetugid(p, uap)
90924453Speter	register struct proc *p;
91024453Speter	struct issetugid_args *uap;
91124453Speter{
91224453Speter	/*
91324453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
91424453Speter	 * we use P_SUGID because we consider changing the owners as
91524453Speter	 * "tainting" as well.
91624453Speter	 * This is significant for procs that start as root and "become"
91724453Speter	 * a user without an exec - programs cannot know *everything*
91824453Speter	 * that libc *might* have put in their data segment.
91924453Speter	 */
92060216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
92124453Speter	return (0);
92224453Speter}
92324453Speter
92475426Srwatsonint
92575426Srwatson__setugid(p, uap)
92675426Srwatson	struct proc *p;
92775426Srwatson	struct __setugid_args *uap;
92875426Srwatson{
92975426Srwatson
93075426Srwatson#ifdef REGRESSION
93175426Srwatson	switch (uap->flag) {
93275426Srwatson	case 0:
93375426Srwatson		p->p_flag &= ~P_SUGID;
93475426Srwatson		return (0);
93575426Srwatson	case 1:
93675426Srwatson		p->p_flag |= P_SUGID;
93775426Srwatson		return (0);
93875426Srwatson	default:
93975426Srwatson		return (EINVAL);
94075426Srwatson	}
94175426Srwatson#else /* !REGRESSION */
94275426Srwatson	return (ENOSYS);
94375426Srwatson#endif /* !REGRESSION */
94475426Srwatson}
94575426Srwatson
9461541Srgrimes/*
9471541Srgrimes * Check if gid is a member of the group set.
9481541Srgrimes */
9491549Srgrimesint
9501541Srgrimesgroupmember(gid, cred)
9511541Srgrimes	gid_t gid;
9521541Srgrimes	register struct ucred *cred;
9531541Srgrimes{
9541541Srgrimes	register gid_t *gp;
9551541Srgrimes	gid_t *egp;
9561541Srgrimes
9571541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
9581541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
9591541Srgrimes		if (*gp == gid)
9601541Srgrimes			return (1);
9611541Srgrimes	return (0);
9621541Srgrimes}
9631541Srgrimes
96461287Srwatsonstatic int suser_permitted = 1;
96561287Srwatson
96661287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
96761287Srwatson    "processes with uid 0 have privilege");
96861287Srwatson
9691541Srgrimes/*
9701541Srgrimes * Test whether the specified credentials imply "super-user"
9711541Srgrimes * privilege; if so, and we have accounting info, set the flag
9721541Srgrimes * indicating use of super-powers.
9731541Srgrimes * Returns 0 or error.
9741541Srgrimes */
9751549Srgrimesint
97646112Sphksuser(p)
97772786Srwatson	struct proc *p;
97846112Sphk{
97946155Sphk	return suser_xxx(0, p, 0);
98046112Sphk}
98146112Sphk
98246112Sphkint
98346155Sphksuser_xxx(cred, proc, flag)
98472786Srwatson	struct ucred *cred;
98572786Srwatson	struct proc *proc;
98646155Sphk	int flag;
9871541Srgrimes{
98861282Srwatson	if (!suser_permitted)
98961282Srwatson		return (EPERM);
99046155Sphk	if (!cred && !proc) {
99146155Sphk		printf("suser_xxx(): THINK!\n");
99246155Sphk		return (EPERM);
9931541Srgrimes	}
99446155Sphk	if (!cred)
99546155Sphk		cred = proc->p_ucred;
99646155Sphk	if (cred->cr_uid != 0)
99746155Sphk		return (EPERM);
99872786Srwatson	if (jailed(cred) && !(flag & PRISON_ROOT))
99946155Sphk		return (EPERM);
100046155Sphk	return (0);
10011541Srgrimes}
10021541Srgrimes
100374956Srwatson/*
100474956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2
100574956Srwatson * Arguments: imutable credentials u1, u2
100674956Srwatson * Returns: 0 for permitted, an errno value otherwise
100774956Srwatson * Locks: none
100874956Srwatson * References: u1 and u2 must be valid for the lifetime of the call
100974956Srwatson *             u1 may equal u2, in which case only one reference is required
101074956Srwatson */
101174956Srwatsonint
101274956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2)
101365237Srwatson{
101472786Srwatson	int error;
101553518Sphk
101674956Srwatson	if ((error = prison_check(u1, u2)))
101772786Srwatson		return (error);
101874956Srwatson	if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) {
101975005Srwatson		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
102074956Srwatson			return (ESRCH);
102165293Srwatson	}
102265237Srwatson	return (0);
102365237Srwatson}
102465237Srwatson
102565237Srwatsonstatic int
102674956Srwatsonp_cansee(struct proc *p1, struct proc *p2, int *privused)
102774956Srwatson{
102874956Srwatson
102974956Srwatson	/* XXX: privused is going away, so don't do that here. */
103074956Srwatson	if (privused != NULL)
103174956Srwatson		*privused = 0;
103274956Srwatson	/* Wrap u_cansee() for all functionality. */
103374956Srwatson	return (u_cansee(p1->p_ucred, p2->p_ucred));
103474956Srwatson}
103574956Srwatson
103675437Srwatson/*
103775437Srwatson * Can process p1 send the signal signum to process p2?
103875437Srwatson */
103975437Srwatsonint
104075437Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum)
104153518Sphk{
104275437Srwatson	int	error;
104375437Srwatson
104453518Sphk	if (p1 == p2)
104553518Sphk		return (0);
104665237Srwatson
104775437Srwatson	/*
104875437Srwatson	 * Jail semantics limit the scope of signalling to p2 in the same
104975437Srwatson	 * jail as p1, if p1 is in jail.
105075437Srwatson	 */
105172786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
105272786Srwatson		return (error);
105365237Srwatson
105465237Srwatson	/*
105575437Srwatson	 * UNIX signalling semantics require that processes in the same
105675437Srwatson	 * session always be able to deliver SIGCONT to one another,
105775437Srwatson	 * overriding the remaining protections.
105865237Srwatson	 */
105975437Srwatson	if (signum == SIGCONT && p1->p_session == p2->p_session)
106053518Sphk		return (0);
106165237Srwatson
106275437Srwatson	/*
106375437Srwatson	 * UNIX uid semantics depend on the status of the P_SUGID
106475437Srwatson	 * bit on the target process.  If the bit is set, then more
106575437Srwatson	 * restricted signal sets are permitted.
106675437Srwatson	 */
106775437Srwatson	if (p2->p_flag & P_SUGID) {
106875437Srwatson		switch (signum) {
106975437Srwatson		case 0:
107075437Srwatson		case SIGKILL:
107175437Srwatson		case SIGINT:
107275437Srwatson		case SIGTERM:
107375437Srwatson		case SIGSTOP:
107475437Srwatson		case SIGTTIN:
107575437Srwatson		case SIGTTOU:
107675437Srwatson		case SIGTSTP:
107775437Srwatson		case SIGHUP:
107875437Srwatson		case SIGUSR1:
107975437Srwatson		case SIGUSR2:
108075437Srwatson			/*
108175437Srwatson			 * Restricted rules allow a broadish scope of uid
108275437Srwatson			 * uid overlap.
108375437Srwatson			 * XXX: Maybe too broad.
108475437Srwatson			 */
108575437Srwatson			if (p1->p_cred->p_ruid != p2->p_cred->p_ruid &&
108675437Srwatson			    p1->p_ucred->cr_uid != p2->p_cred->p_ruid &&
108775437Srwatson			    p1->p_cred->p_ruid != p2->p_ucred->cr_uid &&
108875437Srwatson			    p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) {
108975437Srwatson				/* Not permitted, try privilege. */
109075437Srwatson				error = suser_xxx(NULL, p1, PRISON_ROOT);
109175437Srwatson				if (error)
109275437Srwatson					return (error);
109375437Srwatson			}
109475437Srwatson			break;
109575437Srwatson		default:
109675437Srwatson			/* Not permitted, try privilege. */
109775437Srwatson			error = suser_xxx(NULL, p1, PRISON_ROOT);
109875437Srwatson			if (error)
109975437Srwatson				return (error);
110075437Srwatson		}
110175437Srwatson	} else {
110275437Srwatson		/*
110375437Srwatson		 * Normal rules allow a broad scope of uid overlap.
110475437Srwatson		 * XXX: Maybe too broad.
110575437Srwatson		 */
110675437Srwatson		if (p1->p_cred->p_ruid != p2->p_cred->p_ruid &&
110775437Srwatson		    p1->p_cred->p_ruid != p2->p_cred->p_svuid &&
110875437Srwatson		    p1->p_ucred->cr_uid != p2->p_cred->p_ruid &&
110975437Srwatson		    p1->p_ucred->cr_uid != p2->p_cred->p_svuid &&
111075437Srwatson		    p1->p_cred->p_ruid != p2->p_ucred->cr_uid &&
111175437Srwatson		    p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) {
111275437Srwatson			/* Not permitted, try privilege. */
111375437Srwatson			error = suser_xxx(NULL, p1, PRISON_ROOT);
111475437Srwatson			if (error)
111575437Srwatson				return (error);
111675437Srwatson		}
111765237Srwatson	}
111865237Srwatson
111975437Srwatson        return (0);
112053518Sphk}
112153518Sphk
112265237Srwatsonstatic int
112372786Srwatsonp_cansched(struct proc *p1, struct proc *p2, int *privused)
112465237Srwatson{
112572786Srwatson	int error;
112665237Srwatson
112765237Srwatson	if (privused != NULL)
112865237Srwatson		*privused = 0;
112965237Srwatson
113065237Srwatson	if (p1 == p2)
113165237Srwatson		return (0);
113265237Srwatson
113372786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
113472786Srwatson		return (error);
113565237Srwatson
113665237Srwatson	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
113765237Srwatson		return (0);
113865237Srwatson	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
113965237Srwatson		return (0);
114065237Srwatson	/*
114165237Srwatson	 * XXX should a process be able to affect another process
114265237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
114365237Srwatson	 */
114465237Srwatson	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
114565237Srwatson		return (0);
114665237Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
114765237Srwatson		return (0);
114865237Srwatson
114965237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
115065237Srwatson		if (privused != NULL)
115165237Srwatson			*privused = 1;
115265237Srwatson		return (0);
115365237Srwatson	}
115465237Srwatson
115565237Srwatson#ifdef CAPABILITIES
115665237Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) {
115765237Srwatson		if (privused != NULL)
115865237Srwatson			*privused = 1;
115965237Srwatson		return (0);
116065237Srwatson	}
116165237Srwatson#endif
116265237Srwatson
116365237Srwatson	return (EPERM);
116465237Srwatson}
116565237Srwatson
116665237Srwatsonstatic int
116772786Srwatsonp_candebug(struct proc *p1, struct proc *p2, int *privused)
116865237Srwatson{
116972786Srwatson	int error;
117065237Srwatson
117165237Srwatson	if (privused != NULL)
117265237Srwatson		*privused = 0;
117365237Srwatson
117465237Srwatson	/* XXX it is authorized, but semantics don't permit it */
117565237Srwatson	if (p1 == p2)
117665237Srwatson		return (0);
117765237Srwatson
117872786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
117972786Srwatson		return (error);
118065237Srwatson
118165237Srwatson	/* not owned by you, has done setuid (unless you're root) */
118265237Srwatson	/* add a CAP_SYS_PTRACE here? */
118367999Srwatson	if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid ||
118467999Srwatson	    p1->p_cred->p_ruid != p2->p_cred->p_ruid ||
118568591Srwatson	    p1->p_cred->p_svuid != p2->p_cred->p_ruid ||
118667999Srwatson	    p2->p_flag & P_SUGID) {
118765237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
118865237Srwatson			return (error);
118965237Srwatson		if (privused != NULL)
119065237Srwatson			*privused = 1;
119165237Srwatson	}
119265237Srwatson
119365237Srwatson	/* can't trace init when securelevel > 0 */
119465237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
119565237Srwatson		return (EPERM);
119665237Srwatson
119765237Srwatson	return (0);
119865237Srwatson}
119965237Srwatson
120065237Srwatsonint
120172786Srwatsonp_can(struct proc *p1, struct proc *p2, int operation,
120265237Srwatson    int *privused)
120365237Srwatson{
120465237Srwatson
120565237Srwatson	switch(operation) {
120665237Srwatson	case P_CAN_SEE:
120765237Srwatson		return (p_cansee(p1, p2, privused));
120865237Srwatson
120965237Srwatson	case P_CAN_SCHED:
121065237Srwatson		return (p_cansched(p1, p2, privused));
121165237Srwatson
121265237Srwatson	case P_CAN_DEBUG:
121365237Srwatson		return (p_candebug(p1, p2, privused));
121465237Srwatson
121565237Srwatson	default:
121665237Srwatson		panic("p_can: invalid operation");
121765237Srwatson	}
121865237Srwatson}
121965237Srwatson
122065237Srwatson
122153518Sphk/*
12221541Srgrimes * Allocate a zeroed cred structure.
12231541Srgrimes */
12241541Srgrimesstruct ucred *
12251541Srgrimescrget()
12261541Srgrimes{
12271541Srgrimes	register struct ucred *cr;
12281541Srgrimes
122969239Salfred	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO);
12301541Srgrimes	cr->cr_ref = 1;
123169239Salfred	mtx_init(&cr->cr_mtx, "ucred", MTX_DEF);
12321541Srgrimes	return (cr);
12331541Srgrimes}
12341541Srgrimes
12351541Srgrimes/*
123672474Srwatson * Claim another reference to a ucred structure
123769401Salfred */
123869401Salfredvoid
123969401Salfredcrhold(cr)
124069401Salfred	struct ucred *cr;
124169401Salfred{
124269401Salfred
124372200Sbmilekic	mtx_lock(&cr->cr_mtx);
124469401Salfred	cr->cr_ref++;
124572200Sbmilekic	mtx_unlock(&(cr)->cr_mtx);
124669401Salfred}
124769401Salfred
124869401Salfred
124969401Salfred/*
12501541Srgrimes * Free a cred structure.
12511541Srgrimes * Throws away space when ref count gets to 0.
12521541Srgrimes */
12531549Srgrimesvoid
12541541Srgrimescrfree(cr)
12551541Srgrimes	struct ucred *cr;
12561541Srgrimes{
125769239Salfred
125872200Sbmilekic	mtx_lock(&cr->cr_mtx);
125965495Struckman	if (--cr->cr_ref == 0) {
126069239Salfred		mtx_destroy(&cr->cr_mtx);
126165495Struckman		/*
126265495Struckman		 * Some callers of crget(), such as nfs_statfs(),
126365495Struckman		 * allocate a temporary credential, but don't
126465495Struckman		 * allocate a uidinfo structure.
126565495Struckman		 */
126665495Struckman		if (cr->cr_uidinfo != NULL)
126765495Struckman			uifree(cr->cr_uidinfo);
126872786Srwatson		/*
126972786Srwatson		 * Free a prison, if any.
127072786Srwatson		 */
127172786Srwatson		if (jailed(cr))
127272786Srwatson			prison_free(cr->cr_prison);
12731541Srgrimes		FREE((caddr_t)cr, M_CRED);
127469239Salfred	} else {
127572200Sbmilekic		mtx_unlock(&cr->cr_mtx);
127665495Struckman	}
12771541Srgrimes}
12781541Srgrimes
12791541Srgrimes/*
12801541Srgrimes * Copy cred structure to a new one and free the old one.
12811541Srgrimes */
12821541Srgrimesstruct ucred *
12831541Srgrimescrcopy(cr)
12841541Srgrimes	struct ucred *cr;
12851541Srgrimes{
12861541Srgrimes	struct ucred *newcr;
12871541Srgrimes
128872200Sbmilekic	mtx_lock(&cr->cr_mtx);
128969239Salfred	if (cr->cr_ref == 1) {
129072200Sbmilekic		mtx_unlock(&cr->cr_mtx);
12911541Srgrimes		return (cr);
129269239Salfred	}
129372200Sbmilekic	mtx_unlock(&cr->cr_mtx);
129469239Salfred	newcr = crdup(cr);
12951541Srgrimes	crfree(cr);
12961541Srgrimes	return (newcr);
12971541Srgrimes}
12981541Srgrimes
12991541Srgrimes/*
13001541Srgrimes * Dup cred struct to a new held one.
13011541Srgrimes */
13021541Srgrimesstruct ucred *
13031541Srgrimescrdup(cr)
13041541Srgrimes	struct ucred *cr;
13051541Srgrimes{
13061541Srgrimes	struct ucred *newcr;
13071541Srgrimes
130869239Salfred	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
13091541Srgrimes	*newcr = *cr;
131069239Salfred	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
131165495Struckman	uihold(newcr->cr_uidinfo);
131272786Srwatson	if (jailed(newcr))
131372786Srwatson		prison_hold(newcr->cr_prison);
13141541Srgrimes	newcr->cr_ref = 1;
13151541Srgrimes	return (newcr);
13161541Srgrimes}
13171541Srgrimes
13181541Srgrimes/*
13191541Srgrimes * Get login name, if available.
13201541Srgrimes */
132112221Sbde#ifndef _SYS_SYSPROTO_H_
13221541Srgrimesstruct getlogin_args {
13231541Srgrimes	char	*namebuf;
13241541Srgrimes	u_int	namelen;
13251541Srgrimes};
132612221Sbde#endif
13271541Srgrimes/* ARGSUSED */
13281549Srgrimesint
132930994Sphkgetlogin(p, uap)
13301541Srgrimes	struct proc *p;
13311541Srgrimes	struct getlogin_args *uap;
13321541Srgrimes{
13331541Srgrimes
133423358Sache	if (uap->namelen > MAXLOGNAME)
133523359Sache		uap->namelen = MAXLOGNAME;
13361541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
13371541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
13381541Srgrimes}
13391541Srgrimes
13401541Srgrimes/*
13411541Srgrimes * Set login name.
13421541Srgrimes */
134312221Sbde#ifndef _SYS_SYSPROTO_H_
13441541Srgrimesstruct setlogin_args {
13451541Srgrimes	char	*namebuf;
13461541Srgrimes};
134712221Sbde#endif
13481541Srgrimes/* ARGSUSED */
13491549Srgrimesint
135030994Sphksetlogin(p, uap)
13511541Srgrimes	struct proc *p;
13521541Srgrimes	struct setlogin_args *uap;
13531541Srgrimes{
13541541Srgrimes	int error;
135523330Sache	char logintmp[MAXLOGNAME];
13561541Srgrimes
135746155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
13581541Srgrimes		return (error);
135922522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
136036845Sdfr	    sizeof(logintmp), (size_t *)0);
13611541Srgrimes	if (error == ENAMETOOLONG)
13621541Srgrimes		error = EINVAL;
136322522Sdavidn	else if (!error)
136422522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
136523330Sache		    sizeof(logintmp));
13661541Srgrimes	return (error);
13671541Srgrimes}
136831891Ssef
136931891Ssefvoid
137031891Ssefsetsugid(p)
137155338Sphk	struct proc *p;
137231891Ssef{
137331891Ssef	p->p_flag |= P_SUGID;
137455707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
137531891Ssef		p->p_stops = 0;
137631891Ssef}
137765495Struckman
137865495Struckman/*
137965495Struckman * Helper function to change the effective uid of a process
138065495Struckman */
138165495Struckmanvoid
138265495Struckmanchange_euid(p, euid)
138365495Struckman	struct	proc *p;
138465495Struckman	uid_t	euid;
138565495Struckman{
138665495Struckman	struct	pcred *pc;
138765495Struckman	struct	uidinfo *uip;
138865495Struckman
138965495Struckman	pc = p->p_cred;
139065495Struckman	/*
139165495Struckman	 * crcopy is essentially a NOP if ucred has a reference count
139265495Struckman	 * of 1, which is true if it has already been copied.
139365495Struckman	 */
139465495Struckman	pc->pc_ucred = crcopy(pc->pc_ucred);
139565495Struckman	uip = pc->pc_ucred->cr_uidinfo;
139665495Struckman	pc->pc_ucred->cr_uid = euid;
139765495Struckman	pc->pc_ucred->cr_uidinfo = uifind(euid);
139865495Struckman	uifree(uip);
139965495Struckman}
140065495Struckman
140165495Struckman/*
140265495Struckman * Helper function to change the real uid of a process
140365495Struckman *
140465495Struckman * The per-uid process count for this process is transfered from
140565495Struckman * the old uid to the new uid.
140665495Struckman */
140767629Sgallatinvoid
140865495Struckmanchange_ruid(p, ruid)
140965495Struckman	struct	proc *p;
141065495Struckman	uid_t	ruid;
141165495Struckman{
141265495Struckman	struct	pcred *pc;
141365495Struckman	struct	uidinfo *uip;
141465495Struckman
141565495Struckman	pc = p->p_cred;
141665495Struckman	(void)chgproccnt(pc->p_uidinfo, -1, 0);
141765495Struckman	uip = pc->p_uidinfo;
141865495Struckman	/* It is assumed that pcred is not shared between processes */
141965495Struckman	pc->p_ruid = ruid;
142065495Struckman	pc->p_uidinfo = uifind(ruid);
142165495Struckman	(void)chgproccnt(pc->p_uidinfo, 1, 0);
142265495Struckman	uifree(uip);
142365495Struckman}
1424