kern_prot.c revision 79335
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 79335 2001-07-05 17:10:46Z 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>
5076166Smarkm#include <sys/systm.h>
511541Srgrimes#include <sys/acct.h>
5241059Speter#include <sys/kernel.h>
5370317Sjake#include <sys/lock.h>
5476166Smarkm#include <sys/mutex.h>
551541Srgrimes#include <sys/proc.h>
5676166Smarkm#include <sys/sysproto.h>
571541Srgrimes#include <sys/malloc.h>
5831891Ssef#include <sys/pioctl.h>
5965495Struckman#include <sys/resourcevar.h>
6061287Srwatson#include <sys/sysctl.h>
6172786Srwatson#include <sys/jail.h>
621541Srgrimes
6330354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
6430354Sphk
6512221Sbde#ifndef _SYS_SYSPROTO_H_
6611332Sswallacestruct getpid_args {
671541Srgrimes	int	dummy;
681541Srgrimes};
6912221Sbde#endif
701541Srgrimes
7158717Sdillon/*
7270317Sjake * getpid - MP SAFE
7358717Sdillon */
7470317Sjake
751541Srgrimes/* ARGSUSED */
761549Srgrimesint
7730994Sphkgetpid(p, uap)
781541Srgrimes	struct proc *p;
7911332Sswallace	struct getpid_args *uap;
801541Srgrimes{
811541Srgrimes
8230994Sphk	p->p_retval[0] = p->p_pid;
831541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8474728Sjhb	PROC_LOCK(p);
8530994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
8674728Sjhb	PROC_UNLOCK(p);
871541Srgrimes#endif
881541Srgrimes	return (0);
891541Srgrimes}
901541Srgrimes
9170317Sjake/*
9270317Sjake * getppid - MP SAFE
9370317Sjake */
9470317Sjake
9512221Sbde#ifndef _SYS_SYSPROTO_H_
9611332Sswallacestruct getppid_args {
9711332Sswallace        int     dummy;
9811332Sswallace};
9912221Sbde#endif
1001541Srgrimes/* ARGSUSED */
1011549Srgrimesint
10230994Sphkgetppid(p, uap)
1031541Srgrimes	struct proc *p;
10411332Sswallace	struct getppid_args *uap;
1051541Srgrimes{
1061541Srgrimes
10774728Sjhb	PROC_LOCK(p);
10830994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
10974728Sjhb	PROC_UNLOCK(p);
1101541Srgrimes	return (0);
1111541Srgrimes}
1121541Srgrimes
11358717Sdillon/*
11458717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter
11558717Sdillon *
11658717Sdillon * MP SAFE
11758717Sdillon */
11812221Sbde#ifndef _SYS_SYSPROTO_H_
11911332Sswallacestruct getpgrp_args {
12011332Sswallace        int     dummy;
12111332Sswallace};
12212221Sbde#endif
12311332Sswallace
1241549Srgrimesint
12530994Sphkgetpgrp(p, uap)
1261541Srgrimes	struct proc *p;
12711332Sswallace	struct getpgrp_args *uap;
1281541Srgrimes{
1291541Srgrimes
13030994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1311541Srgrimes	return (0);
1321541Srgrimes}
1331541Srgrimes
13428401Speter/* Get an arbitary pid's process group id */
13512221Sbde#ifndef _SYS_SYSPROTO_H_
13628401Speterstruct getpgid_args {
13728401Speter	pid_t	pid;
13828401Speter};
13928401Speter#endif
14028401Speter
14128401Speterint
14230994Sphkgetpgid(p, uap)
14328401Speter	struct proc *p;
14428401Speter	struct getpgid_args *uap;
14528401Speter{
14641726Struckman	struct proc *pt;
14775448Srwatson	int error;
14841726Struckman
14928401Speter	if (uap->pid == 0)
15075893Sjhb		p->p_retval[0] = p->p_pgrp->pg_id;
15175893Sjhb	else {
15275893Sjhb		if ((pt = pfind(uap->pid)) == NULL)
15375893Sjhb			return ESRCH;
15479335Srwatson		if ((error = p_cansee(p, pt))) {
15575893Sjhb			PROC_UNLOCK(pt);
15675893Sjhb			return (error);
15775893Sjhb		}
15875893Sjhb		p->p_retval[0] = pt->p_pgrp->pg_id;
15975893Sjhb		PROC_UNLOCK(pt);
16075893Sjhb	}
16128401Speter	return 0;
16228401Speter}
16328401Speter
16428401Speter/*
16528401Speter * Get an arbitary pid's session id.
16628401Speter */
16728401Speter#ifndef _SYS_SYSPROTO_H_
16828401Speterstruct getsid_args {
16928401Speter	pid_t	pid;
17028401Speter};
17128401Speter#endif
17228401Speter
17328401Speterint
17430994Sphkgetsid(p, uap)
17528401Speter	struct proc *p;
17628401Speter	struct getsid_args *uap;
17728401Speter{
17841726Struckman	struct proc *pt;
17975448Srwatson	int error;
18041726Struckman
18128401Speter	if (uap->pid == 0)
18275893Sjhb		p->p_retval[0] = p->p_session->s_sid;
18375893Sjhb	else {
18475893Sjhb		if ((pt = pfind(uap->pid)) == NULL)
18575893Sjhb			return ESRCH;
18679335Srwatson		if ((error = p_cansee(p, pt))) {
18775893Sjhb			PROC_UNLOCK(pt);
18875893Sjhb			return (error);
18975893Sjhb		}
19075893Sjhb		p->p_retval[0] = pt->p_session->s_sid;
19175893Sjhb		PROC_UNLOCK(pt);
19275893Sjhb	}
19328401Speter	return 0;
19428401Speter}
19528401Speter
19628401Speter
19758941Sdillon/*
19858941Sdillon * getuid() - MP SAFE
19958941Sdillon */
20028401Speter#ifndef _SYS_SYSPROTO_H_
20111332Sswallacestruct getuid_args {
20211332Sswallace        int     dummy;
20311332Sswallace};
20412221Sbde#endif
20511332Sswallace
2061541Srgrimes/* ARGSUSED */
2071549Srgrimesint
20830994Sphkgetuid(p, uap)
2091541Srgrimes	struct proc *p;
21011332Sswallace	struct getuid_args *uap;
2111541Srgrimes{
2121541Srgrimes
21377183Srwatson	p->p_retval[0] = p->p_ucred->cr_ruid;
2141541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
21530994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
2161541Srgrimes#endif
2171541Srgrimes	return (0);
2181541Srgrimes}
2191541Srgrimes
22058941Sdillon/*
22158941Sdillon * geteuid() - MP SAFE
22258941Sdillon */
22312221Sbde#ifndef _SYS_SYSPROTO_H_
22411332Sswallacestruct geteuid_args {
22511332Sswallace        int     dummy;
22611332Sswallace};
22712221Sbde#endif
22811332Sswallace
2291541Srgrimes/* ARGSUSED */
2301549Srgrimesint
23130994Sphkgeteuid(p, uap)
2321541Srgrimes	struct proc *p;
23311332Sswallace	struct geteuid_args *uap;
2341541Srgrimes{
2351541Srgrimes
23630994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2371541Srgrimes	return (0);
2381541Srgrimes}
2391541Srgrimes
24058941Sdillon/*
24158941Sdillon * getgid() - MP SAFE
24258941Sdillon */
24312221Sbde#ifndef _SYS_SYSPROTO_H_
24411332Sswallacestruct getgid_args {
24511332Sswallace        int     dummy;
24611332Sswallace};
24712221Sbde#endif
24811332Sswallace
2491541Srgrimes/* ARGSUSED */
2501549Srgrimesint
25130994Sphkgetgid(p, uap)
2521541Srgrimes	struct proc *p;
25311332Sswallace	struct getgid_args *uap;
2541541Srgrimes{
2551541Srgrimes
25677183Srwatson	p->p_retval[0] = p->p_ucred->cr_rgid;
2571541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
25830994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2591541Srgrimes#endif
2601541Srgrimes	return (0);
2611541Srgrimes}
2621541Srgrimes
2631541Srgrimes/*
2641541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2651541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2661541Srgrimes * correctly in a library function.
2671541Srgrimes */
26812221Sbde#ifndef _SYS_SYSPROTO_H_
26911332Sswallacestruct getegid_args {
27011332Sswallace        int     dummy;
27111332Sswallace};
27212221Sbde#endif
27311332Sswallace
2741541Srgrimes/* ARGSUSED */
2751549Srgrimesint
27630994Sphkgetegid(p, uap)
2771541Srgrimes	struct proc *p;
27811332Sswallace	struct getegid_args *uap;
2791541Srgrimes{
2801541Srgrimes
28130994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2821541Srgrimes	return (0);
2831541Srgrimes}
2841541Srgrimes
28512221Sbde#ifndef _SYS_SYSPROTO_H_
2861541Srgrimesstruct getgroups_args {
2871541Srgrimes	u_int	gidsetsize;
2881541Srgrimes	gid_t	*gidset;
2891541Srgrimes};
29012221Sbde#endif
2911549Srgrimesint
29230994Sphkgetgroups(p, uap)
2931541Srgrimes	struct proc *p;
2941541Srgrimes	register struct	getgroups_args *uap;
2951541Srgrimes{
29677183Srwatson	struct ucred *cred = p->p_ucred;
29777183Srwatson	u_int ngrp;
2981541Srgrimes	int error;
2991541Srgrimes
3001541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
30177183Srwatson		p->p_retval[0] = cred->cr_ngroups;
3021541Srgrimes		return (0);
3031541Srgrimes	}
30477183Srwatson	if (ngrp < cred->cr_ngroups)
3051541Srgrimes		return (EINVAL);
30677183Srwatson	ngrp = cred->cr_ngroups;
30777183Srwatson	if ((error = copyout((caddr_t)cred->cr_groups,
3083098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
3091541Srgrimes		return (error);
31030994Sphk	p->p_retval[0] = ngrp;
3111541Srgrimes	return (0);
3121541Srgrimes}
3131541Srgrimes
31412221Sbde#ifndef _SYS_SYSPROTO_H_
31512207Sbdestruct setsid_args {
31611332Sswallace        int     dummy;
31711332Sswallace};
31812221Sbde#endif
31911332Sswallace
3201541Srgrimes/* ARGSUSED */
3211549Srgrimesint
32230994Sphksetsid(p, uap)
3231541Srgrimes	register struct proc *p;
32412207Sbde	struct setsid_args *uap;
3251541Srgrimes{
3261541Srgrimes
3271541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3281541Srgrimes		return (EPERM);
3291541Srgrimes	} else {
3301541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
33130994Sphk		p->p_retval[0] = p->p_pid;
3321541Srgrimes		return (0);
3331541Srgrimes	}
3341541Srgrimes}
3351541Srgrimes
3361541Srgrimes/*
3371541Srgrimes * set process group (setpgid/old setpgrp)
3381541Srgrimes *
3391541Srgrimes * caller does setpgid(targpid, targpgid)
3401541Srgrimes *
3411541Srgrimes * pid must be caller or child of caller (ESRCH)
3421541Srgrimes * if a child
3431541Srgrimes *	pid must be in same session (EPERM)
3441541Srgrimes *	pid can't have done an exec (EACCES)
3451541Srgrimes * if pgid != pid
3461541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3471541Srgrimes * pid must not be session leader (EPERM)
3481541Srgrimes */
34912221Sbde#ifndef _SYS_SYSPROTO_H_
3501541Srgrimesstruct setpgid_args {
3511541Srgrimes	int	pid;	/* target process id */
3521541Srgrimes	int	pgid;	/* target pgrp id */
3531541Srgrimes};
35412221Sbde#endif
3551541Srgrimes/* ARGSUSED */
3561549Srgrimesint
35730994Sphksetpgid(curp, uap)
3581541Srgrimes	struct proc *curp;
3591541Srgrimes	register struct setpgid_args *uap;
3601541Srgrimes{
3611541Srgrimes	register struct proc *targp;		/* target process */
3621541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
36375448Srwatson	int error;
3641541Srgrimes
36520677Sbde	if (uap->pgid < 0)
36620677Sbde		return (EINVAL);
3671541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
36875893Sjhb		if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) {
36975893Sjhb			if (targp)
37075893Sjhb				PROC_UNLOCK(targp);
3711541Srgrimes			return (ESRCH);
37275893Sjhb		}
37379335Srwatson		if ((error = p_cansee(curproc, targp))) {
37475893Sjhb			PROC_UNLOCK(targp);
37575448Srwatson			return (error);
37675893Sjhb		}
37775893Sjhb		if (targp->p_pgrp == NULL ||
37875893Sjhb		    targp->p_session != curp->p_session) {
37975893Sjhb			PROC_UNLOCK(targp);
3801541Srgrimes			return (EPERM);
38175893Sjhb		}
38275893Sjhb		if (targp->p_flag & P_EXEC) {
38375893Sjhb			PROC_UNLOCK(targp);
3841541Srgrimes			return (EACCES);
38575893Sjhb		}
38675893Sjhb	} else {
3871541Srgrimes		targp = curp;
38875893Sjhb		PROC_LOCK(curp);	/* XXX: not needed */
38975893Sjhb	}
39075893Sjhb	if (SESS_LEADER(targp)) {
39175893Sjhb		PROC_UNLOCK(targp);
3921541Srgrimes		return (EPERM);
39375893Sjhb	}
3941541Srgrimes	if (uap->pgid == 0)
3951541Srgrimes		uap->pgid = targp->p_pid;
3961541Srgrimes	else if (uap->pgid != targp->p_pid)
3971541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
39875893Sjhb	            pgrp->pg_session != curp->p_session) {
39975893Sjhb			PROC_UNLOCK(targp);
4001541Srgrimes			return (EPERM);
40175893Sjhb		}
40275893Sjhb	/* XXX: We should probably hold the lock across enterpgrp. */
40375893Sjhb	PROC_UNLOCK(targp);
4041541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
4051541Srgrimes}
4061541Srgrimes
40724448Speter/*
40824448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
40972093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
41024448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
41124448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
41224448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
41324448Speter * does not set the saved id - this is dangerous for traditional BSD
41424448Speter * programs.  For this reason, we *really* do not want to set
41524448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
41624448Speter */
41724448Speter#define POSIX_APPENDIX_B_4_2_2
41824448Speter
41912221Sbde#ifndef _SYS_SYSPROTO_H_
4201541Srgrimesstruct setuid_args {
4211541Srgrimes	uid_t	uid;
4221541Srgrimes};
42312221Sbde#endif
4241541Srgrimes/* ARGSUSED */
4251549Srgrimesint
42630994Sphksetuid(p, uap)
4271541Srgrimes	struct proc *p;
4281541Srgrimes	struct setuid_args *uap;
4291541Srgrimes{
43077183Srwatson	struct ucred *newcred, *oldcred;
43177183Srwatson	uid_t uid;
4321541Srgrimes	int error;
4331541Srgrimes
43477183Srwatson	uid = uap->uid;
43577183Srwatson	oldcred = p->p_ucred;
43624448Speter	/*
43724448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
43824448Speter	 *
43924448Speter	 * Note that setuid(geteuid()) is a special case of
44024448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
44172093Sasmodai	 * to use this clause to be compatible with traditional BSD
44224448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
44324448Speter	 * three id's (assuming you have privs).
44424448Speter	 *
44524448Speter	 * Notes on the logic.  We do things in three steps.
44624448Speter	 * 1: We determine if the euid is going to change, and do EPERM
44724448Speter	 *    right away.  We unconditionally change the euid later if this
44824448Speter	 *    test is satisfied, simplifying that part of the logic.
44924448Speter	 * 2: We determine if the real and/or saved uid's are going to
45024448Speter	 *    change.  Determined by compile options.
45124448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
45224448Speter	 */
45377183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
45417994Sache#ifdef _POSIX_SAVED_IDS
45577183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
45617994Sache#endif
45724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
45877183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
45924448Speter#endif
46077183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
4611541Srgrimes		return (error);
46224448Speter
46377183Srwatson	newcred = crdup(oldcred);
46424448Speter#ifdef _POSIX_SAVED_IDS
4651541Srgrimes	/*
46624448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
46724448Speter	 * If so, we are changing the real uid and/or saved uid.
4681541Srgrimes	 */
46917994Sache	if (
47024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
47177183Srwatson	    uid == oldcred->cr_uid ||
47217994Sache#endif
47377183Srwatson	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
47417994Sache#endif
47524448Speter	{
47624448Speter		/*
47765495Struckman		 * Set the real uid and transfer proc count to new user.
47824448Speter		 */
47977183Srwatson		if (uid != oldcred->cr_ruid) {
48077183Srwatson			change_ruid(newcred, uid);
48165495Struckman			setsugid(p);
48224448Speter		}
48324448Speter		/*
48424448Speter		 * Set saved uid
48524448Speter		 *
48624448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
48724448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
48824448Speter		 * is important that we should do this.
48924448Speter		 */
49077183Srwatson		if (uid != oldcred->cr_svuid) {
49177183Srwatson			change_svuid(newcred, uid);
49231891Ssef			setsugid(p);
49324448Speter		}
4948141Sache	}
49524448Speter
49624448Speter	/*
49724448Speter	 * In all permitted cases, we are changing the euid.
49824448Speter	 * Copy credentials so other references do not see our changes.
49924448Speter	 */
50077183Srwatson	if (uid != oldcred->cr_uid) {
50177183Srwatson		change_euid(newcred, uid);
50231891Ssef		setsugid(p);
50324448Speter	}
50477183Srwatson	p->p_ucred = newcred;
50577183Srwatson	crfree(oldcred);
5061541Srgrimes	return (0);
5071541Srgrimes}
5081541Srgrimes
50912221Sbde#ifndef _SYS_SYSPROTO_H_
5101541Srgrimesstruct seteuid_args {
5111541Srgrimes	uid_t	euid;
5121541Srgrimes};
51312221Sbde#endif
5141541Srgrimes/* ARGSUSED */
5151549Srgrimesint
51630994Sphkseteuid(p, uap)
5171541Srgrimes	struct proc *p;
5181541Srgrimes	struct seteuid_args *uap;
5191541Srgrimes{
52077183Srwatson	struct ucred *newcred, *oldcred;
52177183Srwatson	uid_t euid;
5221541Srgrimes	int error;
5231541Srgrimes
5241541Srgrimes	euid = uap->euid;
52577183Srwatson	oldcred = p->p_ucred;
52677183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
52777183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
52877183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
5291541Srgrimes		return (error);
5301541Srgrimes	/*
5311541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
5321541Srgrimes	 * not see our changes.
5331541Srgrimes	 */
53477183Srwatson	newcred = crdup(oldcred);
53577183Srwatson	if (oldcred->cr_uid != euid) {
53677183Srwatson		change_euid(newcred, euid);
53731891Ssef		setsugid(p);
53824449Speter	}
53977183Srwatson	p->p_ucred = newcred;
54077183Srwatson	crfree(oldcred);
5411541Srgrimes	return (0);
5421541Srgrimes}
5431541Srgrimes
54412221Sbde#ifndef _SYS_SYSPROTO_H_
5451541Srgrimesstruct setgid_args {
5461541Srgrimes	gid_t	gid;
5471541Srgrimes};
54812221Sbde#endif
5491541Srgrimes/* ARGSUSED */
5501549Srgrimesint
55130994Sphksetgid(p, uap)
5521541Srgrimes	struct proc *p;
5531541Srgrimes	struct setgid_args *uap;
5541541Srgrimes{
55577183Srwatson	struct ucred *newcred, *oldcred;
55677183Srwatson	gid_t gid;
5571541Srgrimes	int error;
5581541Srgrimes
55977183Srwatson	gid = uap->gid;
56077183Srwatson	oldcred = p->p_ucred;
56124448Speter	/*
56224448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
56324448Speter	 *
56424448Speter	 * Note that setgid(getegid()) is a special case of
56524448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
56672093Sasmodai	 * to use this clause to be compatible with traditional BSD
56724448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
56824448Speter	 * three id's (assuming you have privs).
56924448Speter	 *
57024448Speter	 * For notes on the logic here, see setuid() above.
57124448Speter	 */
57277183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
57317994Sache#ifdef _POSIX_SAVED_IDS
57477183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
57517994Sache#endif
57624448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
57777183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
57824448Speter#endif
57977183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
5801541Srgrimes		return (error);
58124448Speter
58277183Srwatson	newcred = crdup(oldcred);
58317994Sache#ifdef _POSIX_SAVED_IDS
58424448Speter	/*
58524448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
58624448Speter	 * If so, we are changing the real uid and saved gid.
58724448Speter	 */
58824448Speter	if (
58924448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
59077183Srwatson	    gid == oldcred->cr_groups[0] ||
59117994Sache#endif
59277183Srwatson	    suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */
59324448Speter#endif
59424448Speter	{
59524448Speter		/*
59624448Speter		 * Set real gid
59724448Speter		 */
59877183Srwatson		if (oldcred->cr_rgid != gid) {
59977183Srwatson			change_rgid(newcred, gid);
60031891Ssef			setsugid(p);
60124448Speter		}
60224448Speter		/*
60324448Speter		 * Set saved gid
60424448Speter		 *
60524448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
60624448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
60724448Speter		 * is important that we should do this.
60824448Speter		 */
60977183Srwatson		if (oldcred->cr_svgid != gid) {
61077183Srwatson			change_svgid(newcred, gid);
61131891Ssef			setsugid(p);
61224448Speter		}
6138141Sache	}
61424448Speter	/*
61524448Speter	 * In all cases permitted cases, we are changing the egid.
61624448Speter	 * Copy credentials so other references do not see our changes.
61724448Speter	 */
61877183Srwatson	if (oldcred->cr_groups[0] != gid) {
61977183Srwatson		change_egid(newcred, gid);
62031891Ssef		setsugid(p);
62124448Speter	}
62277183Srwatson	p->p_ucred = newcred;
62377183Srwatson	crfree(oldcred);
6241541Srgrimes	return (0);
6251541Srgrimes}
6261541Srgrimes
62712221Sbde#ifndef _SYS_SYSPROTO_H_
6281541Srgrimesstruct setegid_args {
6291541Srgrimes	gid_t	egid;
6301541Srgrimes};
63112221Sbde#endif
6321541Srgrimes/* ARGSUSED */
6331549Srgrimesint
63430994Sphksetegid(p, uap)
6351541Srgrimes	struct proc *p;
6361541Srgrimes	struct setegid_args *uap;
6371541Srgrimes{
63877183Srwatson	struct ucred *newcred, *oldcred;
63977183Srwatson	gid_t egid;
6401541Srgrimes	int error;
6411541Srgrimes
6421541Srgrimes	egid = uap->egid;
64377183Srwatson	oldcred = p->p_ucred;
64477183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
64577183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
64677183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
6471541Srgrimes		return (error);
64877183Srwatson	newcred = crdup(oldcred);
64977183Srwatson	if (oldcred->cr_groups[0] != egid) {
65077183Srwatson		change_egid(newcred, egid);
65131891Ssef		setsugid(p);
65224449Speter	}
65377183Srwatson	p->p_ucred = newcred;
65477183Srwatson	crfree(oldcred);
6551541Srgrimes	return (0);
6561541Srgrimes}
6571541Srgrimes
65812221Sbde#ifndef _SYS_SYSPROTO_H_
6591541Srgrimesstruct setgroups_args {
6601541Srgrimes	u_int	gidsetsize;
6611541Srgrimes	gid_t	*gidset;
6621541Srgrimes};
66312221Sbde#endif
6641541Srgrimes/* ARGSUSED */
6651549Srgrimesint
66630994Sphksetgroups(p, uap)
6671541Srgrimes	struct proc *p;
6681541Srgrimes	struct setgroups_args *uap;
6691541Srgrimes{
67077183Srwatson	struct ucred *newcred, *oldcred;
67177183Srwatson	u_int ngrp;
6721541Srgrimes	int error;
6731541Srgrimes
67477183Srwatson	ngrp = uap->gidsetsize;
67577183Srwatson	oldcred = p->p_ucred;
67677183Srwatson	if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)))
6771541Srgrimes		return (error);
67824447Speter	if (ngrp > NGROUPS)
6791541Srgrimes		return (EINVAL);
68024447Speter	/*
68124447Speter	 * XXX A little bit lazy here.  We could test if anything has
68224447Speter	 * changed before crcopy() and setting P_SUGID.
68324447Speter	 */
68477183Srwatson	newcred = crdup(oldcred);
68524447Speter	if (ngrp < 1) {
68624447Speter		/*
68724447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
68824447Speter		 * groups vector on non-BSD systems (which generally do not
68924447Speter		 * have the egid in the groups[0]).  We risk security holes
69024447Speter		 * when running non-BSD software if we do not do the same.
69124447Speter		 */
69277183Srwatson		newcred->cr_ngroups = 1;
69324447Speter	} else {
69424447Speter		if ((error = copyin((caddr_t)uap->gidset,
69577183Srwatson		    (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) {
69677183Srwatson			crfree(newcred);
69724447Speter			return (error);
69877183Srwatson		}
69977183Srwatson		newcred->cr_ngroups = ngrp;
70024447Speter	}
70131891Ssef	setsugid(p);
70277183Srwatson	p->p_ucred = newcred;
70377183Srwatson	crfree(oldcred);
7041541Srgrimes	return (0);
7051541Srgrimes}
7061541Srgrimes
70712221Sbde#ifndef _SYS_SYSPROTO_H_
7081541Srgrimesstruct setreuid_args {
7099238Sache	uid_t	ruid;
7109238Sache	uid_t	euid;
7111541Srgrimes};
71212221Sbde#endif
7131541Srgrimes/* ARGSUSED */
7141549Srgrimesint
71530994Sphksetreuid(p, uap)
7161541Srgrimes	register struct proc *p;
7171541Srgrimes	struct setreuid_args *uap;
7181541Srgrimes{
71977183Srwatson	struct ucred *newcred, *oldcred;
72077183Srwatson	uid_t ruid, euid;
7218135Sache	int error;
7221541Srgrimes
7239238Sache	ruid = uap->ruid;
7249238Sache	euid = uap->euid;
72577183Srwatson	oldcred = p->p_ucred;
72677183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
72777183Srwatson	      ruid != oldcred->cr_svuid) ||
72877183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
72977183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
73077183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
7318135Sache		return (error);
73277183Srwatson	newcred = crdup(oldcred);
73377183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
73477183Srwatson		change_euid(newcred, euid);
73531891Ssef		setsugid(p);
73624450Speter	}
73777183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
73877183Srwatson		change_ruid(newcred, ruid);
73931891Ssef		setsugid(p);
7408135Sache	}
74177183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
74277183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
74377183Srwatson		change_svuid(newcred, newcred->cr_uid);
74431891Ssef		setsugid(p);
74524450Speter	}
74677183Srwatson	p->p_ucred = newcred;
74777183Srwatson	crfree(oldcred);
7488135Sache	return (0);
7491541Srgrimes}
7501541Srgrimes
75112221Sbde#ifndef _SYS_SYSPROTO_H_
7521541Srgrimesstruct setregid_args {
7539238Sache	gid_t	rgid;
7549238Sache	gid_t	egid;
7551541Srgrimes};
75612221Sbde#endif
7571541Srgrimes/* ARGSUSED */
7581549Srgrimesint
75930994Sphksetregid(p, uap)
7601541Srgrimes	register struct proc *p;
7611541Srgrimes	struct setregid_args *uap;
7621541Srgrimes{
76377183Srwatson	struct ucred *newcred, *oldcred;
76477183Srwatson	gid_t rgid, egid;
7658135Sache	int error;
7661541Srgrimes
7679238Sache	rgid = uap->rgid;
7689238Sache	egid = uap->egid;
76977183Srwatson	oldcred = p->p_ucred;
77077183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
77177183Srwatson	    rgid != oldcred->cr_svgid) ||
77277183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
77377183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
77477183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
7758135Sache		return (error);
7769238Sache
77777183Srwatson	newcred = crdup(oldcred);
77877183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
77977183Srwatson		change_egid(newcred, egid);
78031891Ssef		setsugid(p);
78124450Speter	}
78277183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
78377183Srwatson		change_rgid(newcred, rgid);
78431891Ssef		setsugid(p);
78524450Speter	}
78677183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
78777183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
78877183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
78931891Ssef		setsugid(p);
79024450Speter	}
79177812Sru	p->p_ucred = newcred;
79277812Sru	crfree(oldcred);
7938135Sache	return (0);
7941541Srgrimes}
7951541Srgrimes
79656115Speter/*
79756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
79856115Speter * saved uid is explicit.
79956115Speter */
80056115Speter
80124453Speter#ifndef _SYS_SYSPROTO_H_
80256115Speterstruct setresuid_args {
80356115Speter	uid_t	ruid;
80456115Speter	uid_t	euid;
80556115Speter	uid_t	suid;
80656115Speter};
80756115Speter#endif
80856115Speter/* ARGSUSED */
80956115Speterint
81056115Spetersetresuid(p, uap)
81156115Speter	register struct proc *p;
81256115Speter	struct setresuid_args *uap;
81356115Speter{
81477183Srwatson	struct ucred *newcred, *oldcred;
81577183Srwatson	uid_t ruid, euid, suid;
81656115Speter	int error;
81756115Speter
81856115Speter	ruid = uap->ruid;
81956115Speter	euid = uap->euid;
82056115Speter	suid = uap->suid;
82177183Srwatson	oldcred = p->p_ucred;
82277183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
82377183Srwatson	     ruid != oldcred->cr_svuid &&
82477183Srwatson	      ruid != oldcred->cr_uid) ||
82577183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
82677183Srwatson	    euid != oldcred->cr_svuid &&
82777183Srwatson	      euid != oldcred->cr_uid) ||
82877183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
82977183Srwatson	    suid != oldcred->cr_svuid &&
83077183Srwatson	      suid != oldcred->cr_uid)) &&
83177183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
83256115Speter		return (error);
83377183Srwatson
83477183Srwatson	newcred = crdup(oldcred);
83577183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
83677183Srwatson		change_euid(newcred, euid);
83756115Speter		setsugid(p);
83856115Speter	}
83977183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
84077183Srwatson		change_ruid(newcred, ruid);
84156115Speter		setsugid(p);
84256115Speter	}
84377183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
84477183Srwatson		change_svuid(newcred, suid);
84556115Speter		setsugid(p);
84656115Speter	}
84777183Srwatson	p->p_ucred = newcred;
84877183Srwatson	crfree(oldcred);
84956115Speter	return (0);
85056115Speter}
85156115Speter
85256115Speter/*
85356115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
85456115Speter * saved gid is explicit.
85556115Speter */
85656115Speter
85756115Speter#ifndef _SYS_SYSPROTO_H_
85856115Speterstruct setresgid_args {
85956115Speter	gid_t	rgid;
86056115Speter	gid_t	egid;
86156115Speter	gid_t	sgid;
86256115Speter};
86356115Speter#endif
86456115Speter/* ARGSUSED */
86556115Speterint
86656115Spetersetresgid(p, uap)
86756115Speter	register struct proc *p;
86856115Speter	struct setresgid_args *uap;
86956115Speter{
87077183Srwatson	struct ucred *newcred, *oldcred;
87177183Srwatson	gid_t rgid, egid, sgid;
87256115Speter	int error;
87356115Speter
87456115Speter	rgid = uap->rgid;
87556115Speter	egid = uap->egid;
87656115Speter	sgid = uap->sgid;
87777183Srwatson	oldcred = p->p_ucred;
87877183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
87977183Srwatson	      rgid != oldcred->cr_svgid &&
88077183Srwatson	      rgid != oldcred->cr_groups[0]) ||
88177183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
88277183Srwatson	      egid != oldcred->cr_svgid &&
88377183Srwatson	      egid != oldcred->cr_groups[0]) ||
88477183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
88577183Srwatson	      sgid != oldcred->cr_svgid &&
88677183Srwatson	      sgid != oldcred->cr_groups[0])) &&
88777183Srwatson	    (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
88856115Speter		return (error);
88956115Speter
89077183Srwatson	newcred = crdup(oldcred);
89177183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
89277183Srwatson		change_egid(newcred, egid);
89356115Speter		setsugid(p);
89456115Speter	}
89577183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
89677183Srwatson		change_rgid(newcred, rgid);
89756115Speter		setsugid(p);
89856115Speter	}
89977183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
90077183Srwatson		change_svgid(newcred, sgid);
90156115Speter		setsugid(p);
90256115Speter	}
90377183Srwatson	p->p_ucred = newcred;
90477183Srwatson	crfree(oldcred);
90556115Speter	return (0);
90656115Speter}
90756115Speter
90856115Speter#ifndef _SYS_SYSPROTO_H_
90956115Speterstruct getresuid_args {
91056115Speter	uid_t	*ruid;
91156115Speter	uid_t	*euid;
91256115Speter	uid_t	*suid;
91356115Speter};
91456115Speter#endif
91556115Speter/* ARGSUSED */
91656115Speterint
91756115Spetergetresuid(p, uap)
91856115Speter	register struct proc *p;
91956115Speter	struct getresuid_args *uap;
92056115Speter{
92177183Srwatson	struct ucred *cred = p->p_ucred;
92256115Speter	int error1 = 0, error2 = 0, error3 = 0;
92356115Speter
92456115Speter	if (uap->ruid)
92577183Srwatson		error1 = copyout((caddr_t)&cred->cr_ruid,
92677183Srwatson		    (caddr_t)uap->ruid, sizeof(cred->cr_ruid));
92756115Speter	if (uap->euid)
92877183Srwatson		error2 = copyout((caddr_t)&cred->cr_uid,
92977183Srwatson		    (caddr_t)uap->euid, sizeof(cred->cr_uid));
93056115Speter	if (uap->suid)
93177183Srwatson		error3 = copyout((caddr_t)&cred->cr_svuid,
93277183Srwatson		    (caddr_t)uap->suid, sizeof(cred->cr_svuid));
93356115Speter	return error1 ? error1 : (error2 ? error2 : error3);
93456115Speter}
93556115Speter
93656115Speter#ifndef _SYS_SYSPROTO_H_
93756115Speterstruct getresgid_args {
93856115Speter	gid_t	*rgid;
93956115Speter	gid_t	*egid;
94056115Speter	gid_t	*sgid;
94156115Speter};
94256115Speter#endif
94356115Speter/* ARGSUSED */
94456115Speterint
94556115Spetergetresgid(p, uap)
94656115Speter	register struct proc *p;
94756115Speter	struct getresgid_args *uap;
94856115Speter{
94977183Srwatson	struct ucred *cred = p->p_ucred;
95056115Speter	int error1 = 0, error2 = 0, error3 = 0;
95156115Speter
95256115Speter	if (uap->rgid)
95377183Srwatson		error1 = copyout((caddr_t)&cred->cr_rgid,
95477183Srwatson		    (caddr_t)uap->rgid, sizeof(cred->cr_rgid));
95556115Speter	if (uap->egid)
95677183Srwatson		error2 = copyout((caddr_t)&cred->cr_groups[0],
95777183Srwatson		    (caddr_t)uap->egid, sizeof(cred->cr_groups[0]));
95856115Speter	if (uap->sgid)
95977183Srwatson		error3 = copyout((caddr_t)&cred->cr_svgid,
96077183Srwatson		    (caddr_t)uap->sgid, sizeof(cred->cr_svgid));
96156115Speter	return error1 ? error1 : (error2 ? error2 : error3);
96256115Speter}
96356115Speter
96456115Speter
96556115Speter#ifndef _SYS_SYSPROTO_H_
96624453Speterstruct issetugid_args {
96724453Speter	int dummy;
96824453Speter};
96924453Speter#endif
97024453Speter/* ARGSUSED */
97124453Speterint
97230994Sphkissetugid(p, uap)
97324453Speter	register struct proc *p;
97424453Speter	struct issetugid_args *uap;
97524453Speter{
97624453Speter	/*
97724453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
97824453Speter	 * we use P_SUGID because we consider changing the owners as
97924453Speter	 * "tainting" as well.
98024453Speter	 * This is significant for procs that start as root and "become"
98124453Speter	 * a user without an exec - programs cannot know *everything*
98224453Speter	 * that libc *might* have put in their data segment.
98324453Speter	 */
98460216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
98524453Speter	return (0);
98624453Speter}
98724453Speter
98875426Srwatsonint
98975426Srwatson__setugid(p, uap)
99075426Srwatson	struct proc *p;
99175426Srwatson	struct __setugid_args *uap;
99275426Srwatson{
99375426Srwatson
99475426Srwatson#ifdef REGRESSION
99575426Srwatson	switch (uap->flag) {
99675426Srwatson	case 0:
99775426Srwatson		p->p_flag &= ~P_SUGID;
99875426Srwatson		return (0);
99975426Srwatson	case 1:
100075426Srwatson		p->p_flag |= P_SUGID;
100175426Srwatson		return (0);
100275426Srwatson	default:
100375426Srwatson		return (EINVAL);
100475426Srwatson	}
100575426Srwatson#else /* !REGRESSION */
100675426Srwatson	return (ENOSYS);
100775426Srwatson#endif /* !REGRESSION */
100875426Srwatson}
100975426Srwatson
10101541Srgrimes/*
10111541Srgrimes * Check if gid is a member of the group set.
10121541Srgrimes */
10131549Srgrimesint
10141541Srgrimesgroupmember(gid, cred)
10151541Srgrimes	gid_t gid;
101677183Srwatson	struct ucred *cred;
10171541Srgrimes{
10181541Srgrimes	register gid_t *gp;
10191541Srgrimes	gid_t *egp;
10201541Srgrimes
10211541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
10221541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
10231541Srgrimes		if (*gp == gid)
10241541Srgrimes			return (1);
10251541Srgrimes	return (0);
10261541Srgrimes}
10271541Srgrimes
102861287Srwatsonstatic int suser_permitted = 1;
102961287Srwatson
103061287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
103161287Srwatson    "processes with uid 0 have privilege");
103261287Srwatson
10331541Srgrimes/*
10341541Srgrimes * Test whether the specified credentials imply "super-user"
10351541Srgrimes * privilege; if so, and we have accounting info, set the flag
10361541Srgrimes * indicating use of super-powers.
10371541Srgrimes * Returns 0 or error.
10381541Srgrimes */
10391549Srgrimesint
104046112Sphksuser(p)
104172786Srwatson	struct proc *p;
104246112Sphk{
104346155Sphk	return suser_xxx(0, p, 0);
104446112Sphk}
104546112Sphk
104646112Sphkint
104746155Sphksuser_xxx(cred, proc, flag)
104872786Srwatson	struct ucred *cred;
104972786Srwatson	struct proc *proc;
105046155Sphk	int flag;
10511541Srgrimes{
105261282Srwatson	if (!suser_permitted)
105361282Srwatson		return (EPERM);
105446155Sphk	if (!cred && !proc) {
105546155Sphk		printf("suser_xxx(): THINK!\n");
105646155Sphk		return (EPERM);
10571541Srgrimes	}
105846155Sphk	if (!cred)
105946155Sphk		cred = proc->p_ucred;
106046155Sphk	if (cred->cr_uid != 0)
106146155Sphk		return (EPERM);
106272786Srwatson	if (jailed(cred) && !(flag & PRISON_ROOT))
106346155Sphk		return (EPERM);
106446155Sphk	return (0);
10651541Srgrimes}
10661541Srgrimes
106774956Srwatson/*
106874956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2
106974956Srwatson * Arguments: imutable credentials u1, u2
107074956Srwatson * Returns: 0 for permitted, an errno value otherwise
107174956Srwatson * Locks: none
107274956Srwatson * References: u1 and u2 must be valid for the lifetime of the call
107374956Srwatson *             u1 may equal u2, in which case only one reference is required
107474956Srwatson */
107574956Srwatsonint
107674956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2)
107765237Srwatson{
107872786Srwatson	int error;
107953518Sphk
108074956Srwatson	if ((error = prison_check(u1, u2)))
108172786Srwatson		return (error);
108277183Srwatson	if (!ps_showallprocs && u1->cr_ruid != u2->cr_ruid) {
108375005Srwatson		if (suser_xxx(u1, NULL, PRISON_ROOT) != 0)
108474956Srwatson			return (ESRCH);
108565293Srwatson	}
108665237Srwatson	return (0);
108765237Srwatson}
108865237Srwatson
108979335Srwatsonint
109079335Srwatsonp_cansee(struct proc *p1, struct proc *p2)
109174956Srwatson{
109274956Srwatson
109374956Srwatson	/* Wrap u_cansee() for all functionality. */
109474956Srwatson	return (u_cansee(p1->p_ucred, p2->p_ucred));
109574956Srwatson}
109674956Srwatson
109775437Srwatson/*
109875437Srwatson * Can process p1 send the signal signum to process p2?
109975437Srwatson */
110075437Srwatsonint
110175437Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum)
110253518Sphk{
110375437Srwatson	int	error;
110475437Srwatson
110553518Sphk	if (p1 == p2)
110653518Sphk		return (0);
110765237Srwatson
110875437Srwatson	/*
110975437Srwatson	 * Jail semantics limit the scope of signalling to p2 in the same
111075437Srwatson	 * jail as p1, if p1 is in jail.
111175437Srwatson	 */
111272786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
111372786Srwatson		return (error);
111465237Srwatson
111565237Srwatson	/*
111675437Srwatson	 * UNIX signalling semantics require that processes in the same
111775437Srwatson	 * session always be able to deliver SIGCONT to one another,
111875437Srwatson	 * overriding the remaining protections.
111965237Srwatson	 */
112075437Srwatson	if (signum == SIGCONT && p1->p_session == p2->p_session)
112153518Sphk		return (0);
112265237Srwatson
112375437Srwatson	/*
112475437Srwatson	 * UNIX uid semantics depend on the status of the P_SUGID
112575437Srwatson	 * bit on the target process.  If the bit is set, then more
112675437Srwatson	 * restricted signal sets are permitted.
112775437Srwatson	 */
112875437Srwatson	if (p2->p_flag & P_SUGID) {
112975437Srwatson		switch (signum) {
113075437Srwatson		case 0:
113175437Srwatson		case SIGKILL:
113275437Srwatson		case SIGINT:
113375437Srwatson		case SIGTERM:
113475437Srwatson		case SIGSTOP:
113575437Srwatson		case SIGTTIN:
113675437Srwatson		case SIGTTOU:
113775437Srwatson		case SIGTSTP:
113875437Srwatson		case SIGHUP:
113975437Srwatson		case SIGUSR1:
114075437Srwatson		case SIGUSR2:
114175437Srwatson			break;
114275437Srwatson		default:
114375437Srwatson			/* Not permitted, try privilege. */
114475437Srwatson			error = suser_xxx(NULL, p1, PRISON_ROOT);
114575437Srwatson			if (error)
114675437Srwatson				return (error);
114775437Srwatson		}
114865237Srwatson	}
114965237Srwatson
115075480Srwatson	/*
115175480Srwatson	 * Generally, the object credential's ruid or svuid must match the
115275480Srwatson	 * subject credential's ruid or euid.
115375480Srwatson	 */
115477183Srwatson	if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid &&
115577183Srwatson	    p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid &&
115677183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid &&
115777183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) {
115875480Srwatson		/* Not permitted, try privilege. */
115975480Srwatson		error = suser_xxx(NULL, p1, PRISON_ROOT);
116075480Srwatson		if (error)
116175480Srwatson			return (error);
116275480Srwatson	}
116375480Srwatson
116475437Srwatson        return (0);
116553518Sphk}
116653518Sphk
116779335Srwatsonint
116879335Srwatsonp_cansched(struct proc *p1, struct proc *p2)
116965237Srwatson{
117072786Srwatson	int error;
117165237Srwatson
117265237Srwatson	if (p1 == p2)
117365237Srwatson		return (0);
117465237Srwatson
117572786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
117672786Srwatson		return (error);
117765237Srwatson
117877183Srwatson	if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid)
117965237Srwatson		return (0);
118077183Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid)
118165237Srwatson		return (0);
118265237Srwatson
118379335Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT))
118465237Srwatson		return (0);
118565237Srwatson
118665237Srwatson#ifdef CAPABILITIES
118779335Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT))
118865237Srwatson		return (0);
118965237Srwatson#endif
119065237Srwatson
119165237Srwatson	return (EPERM);
119265237Srwatson}
119365237Srwatson
119479335Srwatsonint
119579335Srwatsonp_candebug(struct proc *p1, struct proc *p2)
119665237Srwatson{
119772786Srwatson	int error;
119865237Srwatson
119965237Srwatson	if (p1 == p2)
120065237Srwatson		return (0);
120165237Srwatson
120272786Srwatson	if ((error = prison_check(p1->p_ucred, p2->p_ucred)))
120372786Srwatson		return (error);
120465237Srwatson
120565237Srwatson	/* not owned by you, has done setuid (unless you're root) */
120665237Srwatson	/* add a CAP_SYS_PTRACE here? */
120777183Srwatson	if (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid ||
120877183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid ||
120977183Srwatson	    p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid ||
121079335Srwatson	    p2->p_flag & P_SUGID)
121165237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
121265237Srwatson			return (error);
121365237Srwatson
121465237Srwatson	/* can't trace init when securelevel > 0 */
121565237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
121665237Srwatson		return (EPERM);
121765237Srwatson
121865237Srwatson	return (0);
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);
125975632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
126065495Struckman	if (--cr->cr_ref == 0) {
126169239Salfred		mtx_destroy(&cr->cr_mtx);
126265495Struckman		/*
126365495Struckman		 * Some callers of crget(), such as nfs_statfs(),
126465495Struckman		 * allocate a temporary credential, but don't
126565495Struckman		 * allocate a uidinfo structure.
126665495Struckman		 */
126765495Struckman		if (cr->cr_uidinfo != NULL)
126865495Struckman			uifree(cr->cr_uidinfo);
126977277Srwatson		if (cr->cr_ruidinfo != NULL)
127077277Srwatson			uifree(cr->cr_ruidinfo);
127172786Srwatson		/*
127272786Srwatson		 * Free a prison, if any.
127372786Srwatson		 */
127472786Srwatson		if (jailed(cr))
127572786Srwatson			prison_free(cr->cr_prison);
12761541Srgrimes		FREE((caddr_t)cr, M_CRED);
127769239Salfred	} else {
127872200Sbmilekic		mtx_unlock(&cr->cr_mtx);
127965495Struckman	}
12801541Srgrimes}
12811541Srgrimes
12821541Srgrimes/*
12831541Srgrimes * Copy cred structure to a new one and free the old one.
12841541Srgrimes */
12851541Srgrimesstruct ucred *
12861541Srgrimescrcopy(cr)
12871541Srgrimes	struct ucred *cr;
12881541Srgrimes{
12891541Srgrimes	struct ucred *newcr;
12901541Srgrimes
129172200Sbmilekic	mtx_lock(&cr->cr_mtx);
129269239Salfred	if (cr->cr_ref == 1) {
129372200Sbmilekic		mtx_unlock(&cr->cr_mtx);
12941541Srgrimes		return (cr);
129569239Salfred	}
129672200Sbmilekic	mtx_unlock(&cr->cr_mtx);
129769239Salfred	newcr = crdup(cr);
12981541Srgrimes	crfree(cr);
12991541Srgrimes	return (newcr);
13001541Srgrimes}
13011541Srgrimes
13021541Srgrimes/*
13031541Srgrimes * Dup cred struct to a new held one.
13041541Srgrimes */
13051541Srgrimesstruct ucred *
13061541Srgrimescrdup(cr)
13071541Srgrimes	struct ucred *cr;
13081541Srgrimes{
13091541Srgrimes	struct ucred *newcr;
13101541Srgrimes
131169239Salfred	MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
13121541Srgrimes	*newcr = *cr;
131369239Salfred	mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF);
131465495Struckman	uihold(newcr->cr_uidinfo);
131577183Srwatson	uihold(newcr->cr_ruidinfo);
131672786Srwatson	if (jailed(newcr))
131772786Srwatson		prison_hold(newcr->cr_prison);
13181541Srgrimes	newcr->cr_ref = 1;
13191541Srgrimes	return (newcr);
13201541Srgrimes}
13211541Srgrimes
13221541Srgrimes/*
13231541Srgrimes * Get login name, if available.
13241541Srgrimes */
132512221Sbde#ifndef _SYS_SYSPROTO_H_
13261541Srgrimesstruct getlogin_args {
13271541Srgrimes	char	*namebuf;
13281541Srgrimes	u_int	namelen;
13291541Srgrimes};
133012221Sbde#endif
13311541Srgrimes/* ARGSUSED */
13321549Srgrimesint
133330994Sphkgetlogin(p, uap)
13341541Srgrimes	struct proc *p;
13351541Srgrimes	struct getlogin_args *uap;
13361541Srgrimes{
13371541Srgrimes
133823358Sache	if (uap->namelen > MAXLOGNAME)
133923359Sache		uap->namelen = MAXLOGNAME;
13401541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
13411541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
13421541Srgrimes}
13431541Srgrimes
13441541Srgrimes/*
13451541Srgrimes * Set login name.
13461541Srgrimes */
134712221Sbde#ifndef _SYS_SYSPROTO_H_
13481541Srgrimesstruct setlogin_args {
13491541Srgrimes	char	*namebuf;
13501541Srgrimes};
135112221Sbde#endif
13521541Srgrimes/* ARGSUSED */
13531549Srgrimesint
135430994Sphksetlogin(p, uap)
13551541Srgrimes	struct proc *p;
13561541Srgrimes	struct setlogin_args *uap;
13571541Srgrimes{
13581541Srgrimes	int error;
135923330Sache	char logintmp[MAXLOGNAME];
13601541Srgrimes
136146155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
13621541Srgrimes		return (error);
136322522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
136436845Sdfr	    sizeof(logintmp), (size_t *)0);
13651541Srgrimes	if (error == ENAMETOOLONG)
13661541Srgrimes		error = EINVAL;
136722522Sdavidn	else if (!error)
136822522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
136923330Sache		    sizeof(logintmp));
13701541Srgrimes	return (error);
13711541Srgrimes}
137231891Ssef
137331891Ssefvoid
137431891Ssefsetsugid(p)
137555338Sphk	struct proc *p;
137631891Ssef{
137731891Ssef	p->p_flag |= P_SUGID;
137855707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
137931891Ssef		p->p_stops = 0;
138031891Ssef}
138165495Struckman
138265495Struckman/*
138377183Srwatson * change_euid(): Change a process's effective uid.
138477183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
138577183Srwatson * References: newcred must be an exclusive credential reference for the
138677183Srwatson *             duration of the call.
138765495Struckman */
138865495Struckmanvoid
138977183Srwatsonchange_euid(newcred, euid)
139077183Srwatson	struct ucred *newcred;
139177183Srwatson	uid_t euid;
139265495Struckman{
139365495Struckman
139477183Srwatson	newcred->cr_uid = euid;
139577183Srwatson	uifree(newcred->cr_uidinfo);
139677183Srwatson	newcred->cr_uidinfo = uifind(euid);
139765495Struckman}
139865495Struckman
139965495Struckman/*
140077183Srwatson * change_egid(): Change a process's effective gid.
140177183Srwatson * Side effects: newcred->cr_gid will be modified.
140277183Srwatson * References: newcred must be an exclusive credential reference for the
140377183Srwatson *             duration of the call.
140465495Struckman */
140567629Sgallatinvoid
140677183Srwatsonchange_egid(newcred, egid)
140777183Srwatson	struct ucred *newcred;
140877183Srwatson	gid_t egid;
140965495Struckman{
141065495Struckman
141177183Srwatson	newcred->cr_groups[0] = egid;
141265495Struckman}
141377183Srwatson
141477183Srwatson/*
141577183Srwatson * change_ruid(): Change a process's real uid.
141677183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
141777183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
141877183Srwatson *               counts will be updated.
141977183Srwatson * References: newcred must be an exclusive credential reference for the
142077183Srwatson *             duration of the call.
142177183Srwatson */
142277183Srwatsonvoid
142377183Srwatsonchange_ruid(newcred, ruid)
142477183Srwatson	struct ucred *newcred;
142577183Srwatson	uid_t ruid;
142677183Srwatson{
142777183Srwatson
142877183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
142977183Srwatson	newcred->cr_ruid = ruid;
143077183Srwatson	uifree(newcred->cr_ruidinfo);
143177183Srwatson	newcred->cr_ruidinfo = uifind(ruid);
143277183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
143377183Srwatson}
143477183Srwatson
143577183Srwatson/*
143677183Srwatson * change_rgid(): Change a process's real gid.
143777183Srwatson * Side effects: newcred->cr_rgid will be updated.
143877183Srwatson * References: newcred must be an exclusive credential reference for the
143977183Srwatson *             duration of the call.
144077183Srwatson */
144177183Srwatsonvoid
144277183Srwatsonchange_rgid(newcred, rgid)
144377183Srwatson	struct ucred *newcred;
144477183Srwatson	gid_t rgid;
144577183Srwatson{
144677183Srwatson
144777183Srwatson	newcred->cr_rgid = rgid;
144877183Srwatson}
144977183Srwatson
145077183Srwatson/*
145177183Srwatson * change_svuid(): Change a process's saved uid.
145277183Srwatson * Side effects: newcred->cr_svuid will be updated.
145377183Srwatson * References: newcred must be an exclusive credential reference for the
145477183Srwatson *             duration of the call.
145577183Srwatson */
145677183Srwatsonvoid
145777183Srwatsonchange_svuid(newcred, svuid)
145877183Srwatson	struct ucred *newcred;
145977183Srwatson	uid_t svuid;
146077183Srwatson{
146177183Srwatson
146277183Srwatson	newcred->cr_svuid = svuid;
146377183Srwatson}
146477183Srwatson
146577183Srwatson/*
146677183Srwatson * change_svgid(): Change a process's saved gid.
146777183Srwatson * Side effects: newcred->cr_svgid will be updated.
146877183Srwatson * References: newcred must be an exclusive credential reference for the
146977183Srwatson *             duration of the call.
147077183Srwatson */
147177183Srwatsonvoid
147277183Srwatsonchange_svgid(newcred, svgid)
147377183Srwatson	struct ucred *newcred;
147477183Srwatson	gid_t svgid;
147577183Srwatson{
147677183Srwatson
147777183Srwatson	newcred->cr_svgid = svgid;
147877183Srwatson}
1479