kern_prot.c revision 65237
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 65237 2000-08-30 04:49:09Z rwatson $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
4631778Seivind#include "opt_compat.h"
4731778Seivind
481541Srgrimes#include <sys/param.h>
491541Srgrimes#include <sys/acct.h>
501541Srgrimes#include <sys/systm.h>
5112221Sbde#include <sys/sysproto.h>
5241059Speter#include <sys/kernel.h>
531541Srgrimes#include <sys/proc.h>
541541Srgrimes#include <sys/malloc.h>
5531891Ssef#include <sys/pioctl.h>
5661287Srwatson#include <sys/sysctl.h>
571541Srgrimes
5830354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
5930354Sphk
6012221Sbde#ifndef _SYS_SYSPROTO_H_
6111332Sswallacestruct getpid_args {
621541Srgrimes	int	dummy;
631541Srgrimes};
6412221Sbde#endif
651541Srgrimes
6658717Sdillon/*
6758717Sdillon * NOT MP SAFE due to p_pptr access
6858717Sdillon */
691541Srgrimes/* ARGSUSED */
701549Srgrimesint
7130994Sphkgetpid(p, uap)
721541Srgrimes	struct proc *p;
7311332Sswallace	struct getpid_args *uap;
741541Srgrimes{
751541Srgrimes
7630994Sphk	p->p_retval[0] = p->p_pid;
771541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
7830994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
791541Srgrimes#endif
801541Srgrimes	return (0);
811541Srgrimes}
821541Srgrimes
8312221Sbde#ifndef _SYS_SYSPROTO_H_
8411332Sswallacestruct getppid_args {
8511332Sswallace        int     dummy;
8611332Sswallace};
8712221Sbde#endif
881541Srgrimes/* ARGSUSED */
891549Srgrimesint
9030994Sphkgetppid(p, uap)
911541Srgrimes	struct proc *p;
9211332Sswallace	struct getppid_args *uap;
931541Srgrimes{
941541Srgrimes
9530994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
961541Srgrimes	return (0);
971541Srgrimes}
981541Srgrimes
9958717Sdillon/*
10058717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter
10158717Sdillon *
10258717Sdillon * MP SAFE
10358717Sdillon */
10412221Sbde#ifndef _SYS_SYSPROTO_H_
10511332Sswallacestruct getpgrp_args {
10611332Sswallace        int     dummy;
10711332Sswallace};
10812221Sbde#endif
10911332Sswallace
1101549Srgrimesint
11130994Sphkgetpgrp(p, uap)
1121541Srgrimes	struct proc *p;
11311332Sswallace	struct getpgrp_args *uap;
1141541Srgrimes{
1151541Srgrimes
11630994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1171541Srgrimes	return (0);
1181541Srgrimes}
1191541Srgrimes
12028401Speter/* Get an arbitary pid's process group id */
12112221Sbde#ifndef _SYS_SYSPROTO_H_
12228401Speterstruct getpgid_args {
12328401Speter	pid_t	pid;
12428401Speter};
12528401Speter#endif
12628401Speter
12728401Speterint
12830994Sphkgetpgid(p, uap)
12928401Speter	struct proc *p;
13028401Speter	struct getpgid_args *uap;
13128401Speter{
13241726Struckman	struct proc *pt;
13341726Struckman
13441726Struckman	pt = p;
13528401Speter	if (uap->pid == 0)
13628401Speter		goto found;
13728401Speter
13841726Struckman	if ((pt = pfind(uap->pid)) == 0)
13928401Speter		return ESRCH;
14028401Speterfound:
14141726Struckman	p->p_retval[0] = pt->p_pgrp->pg_id;
14228401Speter	return 0;
14328401Speter}
14428401Speter
14528401Speter/*
14628401Speter * Get an arbitary pid's session id.
14728401Speter */
14828401Speter#ifndef _SYS_SYSPROTO_H_
14928401Speterstruct getsid_args {
15028401Speter	pid_t	pid;
15128401Speter};
15228401Speter#endif
15328401Speter
15428401Speterint
15530994Sphkgetsid(p, uap)
15628401Speter	struct proc *p;
15728401Speter	struct getsid_args *uap;
15828401Speter{
15941726Struckman	struct proc *pt;
16041726Struckman
16141726Struckman	pt = p;
16228401Speter	if (uap->pid == 0)
16328401Speter		goto found;
16428401Speter
16541726Struckman	if ((pt == pfind(uap->pid)) == 0)
16628401Speter		return ESRCH;
16728401Speterfound:
16841726Struckman	p->p_retval[0] = pt->p_session->s_sid;
16928401Speter	return 0;
17028401Speter}
17128401Speter
17228401Speter
17358941Sdillon/*
17458941Sdillon * getuid() - MP SAFE
17558941Sdillon */
17628401Speter#ifndef _SYS_SYSPROTO_H_
17711332Sswallacestruct getuid_args {
17811332Sswallace        int     dummy;
17911332Sswallace};
18012221Sbde#endif
18111332Sswallace
1821541Srgrimes/* ARGSUSED */
1831549Srgrimesint
18430994Sphkgetuid(p, uap)
1851541Srgrimes	struct proc *p;
18611332Sswallace	struct getuid_args *uap;
1871541Srgrimes{
1881541Srgrimes
18930994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
1901541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
19130994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
1921541Srgrimes#endif
1931541Srgrimes	return (0);
1941541Srgrimes}
1951541Srgrimes
19658941Sdillon/*
19758941Sdillon * geteuid() - MP SAFE
19858941Sdillon */
19912221Sbde#ifndef _SYS_SYSPROTO_H_
20011332Sswallacestruct geteuid_args {
20111332Sswallace        int     dummy;
20211332Sswallace};
20312221Sbde#endif
20411332Sswallace
2051541Srgrimes/* ARGSUSED */
2061549Srgrimesint
20730994Sphkgeteuid(p, uap)
2081541Srgrimes	struct proc *p;
20911332Sswallace	struct geteuid_args *uap;
2101541Srgrimes{
2111541Srgrimes
21230994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2131541Srgrimes	return (0);
2141541Srgrimes}
2151541Srgrimes
21658941Sdillon/*
21758941Sdillon * getgid() - MP SAFE
21858941Sdillon */
21912221Sbde#ifndef _SYS_SYSPROTO_H_
22011332Sswallacestruct getgid_args {
22111332Sswallace        int     dummy;
22211332Sswallace};
22312221Sbde#endif
22411332Sswallace
2251541Srgrimes/* ARGSUSED */
2261549Srgrimesint
22730994Sphkgetgid(p, uap)
2281541Srgrimes	struct proc *p;
22911332Sswallace	struct getgid_args *uap;
2301541Srgrimes{
2311541Srgrimes
23230994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2331541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
23430994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2351541Srgrimes#endif
2361541Srgrimes	return (0);
2371541Srgrimes}
2381541Srgrimes
2391541Srgrimes/*
2401541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2411541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2421541Srgrimes * correctly in a library function.
2431541Srgrimes */
24412221Sbde#ifndef _SYS_SYSPROTO_H_
24511332Sswallacestruct getegid_args {
24611332Sswallace        int     dummy;
24711332Sswallace};
24812221Sbde#endif
24911332Sswallace
2501541Srgrimes/* ARGSUSED */
2511549Srgrimesint
25230994Sphkgetegid(p, uap)
2531541Srgrimes	struct proc *p;
25411332Sswallace	struct getegid_args *uap;
2551541Srgrimes{
2561541Srgrimes
25730994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2581541Srgrimes	return (0);
2591541Srgrimes}
2601541Srgrimes
26112221Sbde#ifndef _SYS_SYSPROTO_H_
2621541Srgrimesstruct getgroups_args {
2631541Srgrimes	u_int	gidsetsize;
2641541Srgrimes	gid_t	*gidset;
2651541Srgrimes};
26612221Sbde#endif
2671549Srgrimesint
26830994Sphkgetgroups(p, uap)
2691541Srgrimes	struct proc *p;
2701541Srgrimes	register struct	getgroups_args *uap;
2711541Srgrimes{
2721541Srgrimes	register struct pcred *pc = p->p_cred;
2731541Srgrimes	register u_int ngrp;
2741541Srgrimes	int error;
2751541Srgrimes
2761541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
27730994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2781541Srgrimes		return (0);
2791541Srgrimes	}
2801541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2811541Srgrimes		return (EINVAL);
2821541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2833098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2843098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2851541Srgrimes		return (error);
28630994Sphk	p->p_retval[0] = ngrp;
2871541Srgrimes	return (0);
2881541Srgrimes}
2891541Srgrimes
29012221Sbde#ifndef _SYS_SYSPROTO_H_
29112207Sbdestruct setsid_args {
29211332Sswallace        int     dummy;
29311332Sswallace};
29412221Sbde#endif
29511332Sswallace
2961541Srgrimes/* ARGSUSED */
2971549Srgrimesint
29830994Sphksetsid(p, uap)
2991541Srgrimes	register struct proc *p;
30012207Sbde	struct setsid_args *uap;
3011541Srgrimes{
3021541Srgrimes
3031541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
3041541Srgrimes		return (EPERM);
3051541Srgrimes	} else {
3061541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
30730994Sphk		p->p_retval[0] = p->p_pid;
3081541Srgrimes		return (0);
3091541Srgrimes	}
3101541Srgrimes}
3111541Srgrimes
3121541Srgrimes/*
3131541Srgrimes * set process group (setpgid/old setpgrp)
3141541Srgrimes *
3151541Srgrimes * caller does setpgid(targpid, targpgid)
3161541Srgrimes *
3171541Srgrimes * pid must be caller or child of caller (ESRCH)
3181541Srgrimes * if a child
3191541Srgrimes *	pid must be in same session (EPERM)
3201541Srgrimes *	pid can't have done an exec (EACCES)
3211541Srgrimes * if pgid != pid
3221541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3231541Srgrimes * pid must not be session leader (EPERM)
3241541Srgrimes */
32512221Sbde#ifndef _SYS_SYSPROTO_H_
3261541Srgrimesstruct setpgid_args {
3271541Srgrimes	int	pid;	/* target process id */
3281541Srgrimes	int	pgid;	/* target pgrp id */
3291541Srgrimes};
33012221Sbde#endif
3311541Srgrimes/* ARGSUSED */
3321549Srgrimesint
33330994Sphksetpgid(curp, uap)
3341541Srgrimes	struct proc *curp;
3351541Srgrimes	register struct setpgid_args *uap;
3361541Srgrimes{
3371541Srgrimes	register struct proc *targp;		/* target process */
3381541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
3391541Srgrimes
34020677Sbde	if (uap->pgid < 0)
34120677Sbde		return (EINVAL);
3421541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3431541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3441541Srgrimes			return (ESRCH);
34515985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3461541Srgrimes			return (EPERM);
3471541Srgrimes		if (targp->p_flag & P_EXEC)
3481541Srgrimes			return (EACCES);
3491541Srgrimes	} else
3501541Srgrimes		targp = curp;
3511541Srgrimes	if (SESS_LEADER(targp))
3521541Srgrimes		return (EPERM);
3531541Srgrimes	if (uap->pgid == 0)
3541541Srgrimes		uap->pgid = targp->p_pid;
3551541Srgrimes	else if (uap->pgid != targp->p_pid)
3561541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3571541Srgrimes	            pgrp->pg_session != curp->p_session)
3581541Srgrimes			return (EPERM);
3591541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3601541Srgrimes}
3611541Srgrimes
36224448Speter/*
36324448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
36424448Speter * compatable.  It says that setting the uid/gid to euid/egid is a special
36524448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
36624448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
36724448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
36824448Speter * does not set the saved id - this is dangerous for traditional BSD
36924448Speter * programs.  For this reason, we *really* do not want to set
37024448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
37124448Speter */
37224448Speter#define POSIX_APPENDIX_B_4_2_2
37324448Speter
37412221Sbde#ifndef _SYS_SYSPROTO_H_
3751541Srgrimesstruct setuid_args {
3761541Srgrimes	uid_t	uid;
3771541Srgrimes};
37812221Sbde#endif
3791541Srgrimes/* ARGSUSED */
3801549Srgrimesint
38130994Sphksetuid(p, uap)
3821541Srgrimes	struct proc *p;
3831541Srgrimes	struct setuid_args *uap;
3841541Srgrimes{
3851541Srgrimes	register struct pcred *pc = p->p_cred;
3861541Srgrimes	register uid_t uid;
3871541Srgrimes	int error;
3881541Srgrimes
38924448Speter	/*
39024448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
39124448Speter	 *
39224448Speter	 * Note that setuid(geteuid()) is a special case of
39324448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
39424448Speter	 * to use this clause to be compatable with traditional BSD
39524448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
39624448Speter	 * three id's (assuming you have privs).
39724448Speter	 *
39824448Speter	 * Notes on the logic.  We do things in three steps.
39924448Speter	 * 1: We determine if the euid is going to change, and do EPERM
40024448Speter	 *    right away.  We unconditionally change the euid later if this
40124448Speter	 *    test is satisfied, simplifying that part of the logic.
40224448Speter	 * 2: We determine if the real and/or saved uid's are going to
40324448Speter	 *    change.  Determined by compile options.
40424448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
40524448Speter	 */
4061541Srgrimes	uid = uap->uid;
40724448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
40817994Sache#ifdef _POSIX_SAVED_IDS
40924448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
41017994Sache#endif
41124448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
41224448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
41324448Speter#endif
41446155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4151541Srgrimes		return (error);
41624448Speter
41724448Speter#ifdef _POSIX_SAVED_IDS
4181541Srgrimes	/*
41924448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
42024448Speter	 * If so, we are changing the real uid and/or saved uid.
4211541Srgrimes	 */
42217994Sache	if (
42324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
42424448Speter	    uid == pc->pc_ucred->cr_uid ||
42517994Sache#endif
42646155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
42717994Sache#endif
42824448Speter	{
42924448Speter		/*
43024448Speter		 * Transfer proc count to new user.
43124448Speter		 */
43224448Speter		if (uid != pc->p_ruid) {
43361976Salfred			(void)chgproccnt(pc->p_ruid, -1, 0);
43461976Salfred			(void)chgproccnt(uid, 1, 0);
43524448Speter		}
43624448Speter		/*
43724448Speter		 * Set real uid
43824448Speter		 */
43924448Speter		if (uid != pc->p_ruid) {
44024448Speter			pc->p_ruid = uid;
44131891Ssef			setsugid(p);
44224448Speter		}
44324448Speter		/*
44424448Speter		 * Set saved uid
44524448Speter		 *
44624448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
44724448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
44824448Speter		 * is important that we should do this.
44924448Speter		 */
45024448Speter		if (pc->p_svuid != uid) {
45124448Speter			pc->p_svuid = uid;
45231891Ssef			setsugid(p);
45324448Speter		}
4548141Sache	}
45524448Speter
45624448Speter	/*
45724448Speter	 * In all permitted cases, we are changing the euid.
45824448Speter	 * Copy credentials so other references do not see our changes.
45924448Speter	 */
46024448Speter	if (pc->pc_ucred->cr_uid != uid) {
46124448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
46224448Speter		pc->pc_ucred->cr_uid = uid;
46331891Ssef		setsugid(p);
46424448Speter	}
4651541Srgrimes	return (0);
4661541Srgrimes}
4671541Srgrimes
46812221Sbde#ifndef _SYS_SYSPROTO_H_
4691541Srgrimesstruct seteuid_args {
4701541Srgrimes	uid_t	euid;
4711541Srgrimes};
47212221Sbde#endif
4731541Srgrimes/* ARGSUSED */
4741549Srgrimesint
47530994Sphkseteuid(p, uap)
4761541Srgrimes	struct proc *p;
4771541Srgrimes	struct seteuid_args *uap;
4781541Srgrimes{
4791541Srgrimes	register struct pcred *pc = p->p_cred;
4801541Srgrimes	register uid_t euid;
4811541Srgrimes	int error;
4821541Srgrimes
4831541Srgrimes	euid = uap->euid;
48424449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
48524449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
48646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
4871541Srgrimes		return (error);
4881541Srgrimes	/*
4891541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4901541Srgrimes	 * not see our changes.
4911541Srgrimes	 */
49224449Speter	if (pc->pc_ucred->cr_uid != euid) {
49324449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
49424449Speter		pc->pc_ucred->cr_uid = euid;
49531891Ssef		setsugid(p);
49624449Speter	}
4971541Srgrimes	return (0);
4981541Srgrimes}
4991541Srgrimes
50012221Sbde#ifndef _SYS_SYSPROTO_H_
5011541Srgrimesstruct setgid_args {
5021541Srgrimes	gid_t	gid;
5031541Srgrimes};
50412221Sbde#endif
5051541Srgrimes/* ARGSUSED */
5061549Srgrimesint
50730994Sphksetgid(p, uap)
5081541Srgrimes	struct proc *p;
5091541Srgrimes	struct setgid_args *uap;
5101541Srgrimes{
5111541Srgrimes	register struct pcred *pc = p->p_cred;
5121541Srgrimes	register gid_t gid;
5131541Srgrimes	int error;
5141541Srgrimes
51524448Speter	/*
51624448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
51724448Speter	 *
51824448Speter	 * Note that setgid(getegid()) is a special case of
51924448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52024448Speter	 * to use this clause to be compatable with traditional BSD
52124448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
52224448Speter	 * three id's (assuming you have privs).
52324448Speter	 *
52424448Speter	 * For notes on the logic here, see setuid() above.
52524448Speter	 */
5261541Srgrimes	gid = uap->gid;
52724448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
52817994Sache#ifdef _POSIX_SAVED_IDS
52924448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
53017994Sache#endif
53124448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
53224448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
53324448Speter#endif
53446155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5351541Srgrimes		return (error);
53624448Speter
53717994Sache#ifdef _POSIX_SAVED_IDS
53824448Speter	/*
53924448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
54024448Speter	 * If so, we are changing the real uid and saved gid.
54124448Speter	 */
54224448Speter	if (
54324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
54424448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
54517994Sache#endif
54646155Sphk	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
54724448Speter#endif
54824448Speter	{
54924448Speter		/*
55024448Speter		 * Set real gid
55124448Speter		 */
55224448Speter		if (pc->p_rgid != gid) {
55324448Speter			pc->p_rgid = gid;
55431891Ssef			setsugid(p);
55524448Speter		}
55624448Speter		/*
55724448Speter		 * Set saved gid
55824448Speter		 *
55924448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
56024448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
56124448Speter		 * is important that we should do this.
56224448Speter		 */
56324448Speter		if (pc->p_svgid != gid) {
56424448Speter			pc->p_svgid = gid;
56531891Ssef			setsugid(p);
56624448Speter		}
5678141Sache	}
56824448Speter	/*
56924448Speter	 * In all cases permitted cases, we are changing the egid.
57024448Speter	 * Copy credentials so other references do not see our changes.
57124448Speter	 */
57224448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
57324448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
57424448Speter		pc->pc_ucred->cr_groups[0] = gid;
57531891Ssef		setsugid(p);
57624448Speter	}
5771541Srgrimes	return (0);
5781541Srgrimes}
5791541Srgrimes
58012221Sbde#ifndef _SYS_SYSPROTO_H_
5811541Srgrimesstruct setegid_args {
5821541Srgrimes	gid_t	egid;
5831541Srgrimes};
58412221Sbde#endif
5851541Srgrimes/* ARGSUSED */
5861549Srgrimesint
58730994Sphksetegid(p, uap)
5881541Srgrimes	struct proc *p;
5891541Srgrimes	struct setegid_args *uap;
5901541Srgrimes{
5911541Srgrimes	register struct pcred *pc = p->p_cred;
5921541Srgrimes	register gid_t egid;
5931541Srgrimes	int error;
5941541Srgrimes
5951541Srgrimes	egid = uap->egid;
59624449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
59724449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
59846155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)))
5991541Srgrimes		return (error);
60024449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
60124449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
60224449Speter		pc->pc_ucred->cr_groups[0] = egid;
60331891Ssef		setsugid(p);
60424449Speter	}
6051541Srgrimes	return (0);
6061541Srgrimes}
6071541Srgrimes
60812221Sbde#ifndef _SYS_SYSPROTO_H_
6091541Srgrimesstruct setgroups_args {
6101541Srgrimes	u_int	gidsetsize;
6111541Srgrimes	gid_t	*gidset;
6121541Srgrimes};
61312221Sbde#endif
6141541Srgrimes/* ARGSUSED */
6151549Srgrimesint
61630994Sphksetgroups(p, uap)
6171541Srgrimes	struct proc *p;
6181541Srgrimes	struct setgroups_args *uap;
6191541Srgrimes{
6201541Srgrimes	register struct pcred *pc = p->p_cred;
6211541Srgrimes	register u_int ngrp;
6221541Srgrimes	int error;
6231541Srgrimes
62446155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
6251541Srgrimes		return (error);
62612063Sdg	ngrp = uap->gidsetsize;
62724447Speter	if (ngrp > NGROUPS)
6281541Srgrimes		return (EINVAL);
62924447Speter	/*
63024447Speter	 * XXX A little bit lazy here.  We could test if anything has
63124447Speter	 * changed before crcopy() and setting P_SUGID.
63224447Speter	 */
6331541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
63424447Speter	if (ngrp < 1) {
63524447Speter		/*
63624447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
63724447Speter		 * groups vector on non-BSD systems (which generally do not
63824447Speter		 * have the egid in the groups[0]).  We risk security holes
63924447Speter		 * when running non-BSD software if we do not do the same.
64024447Speter		 */
64124447Speter		pc->pc_ucred->cr_ngroups = 1;
64224447Speter	} else {
64324447Speter		if ((error = copyin((caddr_t)uap->gidset,
64424447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
64524447Speter			return (error);
64624447Speter		pc->pc_ucred->cr_ngroups = ngrp;
64724447Speter	}
64831891Ssef	setsugid(p);
6491541Srgrimes	return (0);
6501541Srgrimes}
6511541Srgrimes
65212221Sbde#ifndef _SYS_SYSPROTO_H_
6531541Srgrimesstruct setreuid_args {
6549238Sache	uid_t	ruid;
6559238Sache	uid_t	euid;
6561541Srgrimes};
65712221Sbde#endif
6581541Srgrimes/* ARGSUSED */
6591549Srgrimesint
66030994Sphksetreuid(p, uap)
6611541Srgrimes	register struct proc *p;
6621541Srgrimes	struct setreuid_args *uap;
6631541Srgrimes{
6641541Srgrimes	register struct pcred *pc = p->p_cred;
6659238Sache	register uid_t ruid, euid;
6668135Sache	int error;
6671541Srgrimes
6689238Sache	ruid = uap->ruid;
6699238Sache	euid = uap->euid;
67043311Sdillon	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
67143311Sdillon	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
67243311Sdillon	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
67346155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
6748135Sache		return (error);
6759238Sache
67624450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
67724450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
6789238Sache		pc->pc_ucred->cr_uid = euid;
67931891Ssef		setsugid(p);
68024450Speter	}
68124450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
68261976Salfred		(void)chgproccnt(pc->p_ruid, -1, 0);
68361976Salfred		(void)chgproccnt(ruid, 1, 0);
6849238Sache		pc->p_ruid = ruid;
68531891Ssef		setsugid(p);
6868135Sache	}
68724559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
68824559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6898111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
69031891Ssef		setsugid(p);
69124450Speter	}
6928135Sache	return (0);
6931541Srgrimes}
6941541Srgrimes
69512221Sbde#ifndef _SYS_SYSPROTO_H_
6961541Srgrimesstruct setregid_args {
6979238Sache	gid_t	rgid;
6989238Sache	gid_t	egid;
6991541Srgrimes};
70012221Sbde#endif
7011541Srgrimes/* ARGSUSED */
7021549Srgrimesint
70330994Sphksetregid(p, uap)
7041541Srgrimes	register struct proc *p;
7051541Srgrimes	struct setregid_args *uap;
7061541Srgrimes{
7071541Srgrimes	register struct pcred *pc = p->p_cred;
7089238Sache	register gid_t rgid, egid;
7098135Sache	int error;
7101541Srgrimes
7119238Sache	rgid = uap->rgid;
7129238Sache	egid = uap->egid;
71343311Sdillon	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
71443311Sdillon	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
71543311Sdillon	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
71646155Sphk	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
7178135Sache		return (error);
7189238Sache
71924450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
72024450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
7219238Sache		pc->pc_ucred->cr_groups[0] = egid;
72231891Ssef		setsugid(p);
72324450Speter	}
72424450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7259238Sache		pc->p_rgid = rgid;
72631891Ssef		setsugid(p);
72724450Speter	}
72824559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
72924559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7308111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
73131891Ssef		setsugid(p);
73224450Speter	}
7338135Sache	return (0);
7341541Srgrimes}
7351541Srgrimes
73656115Speter/*
73756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the
73856115Speter * saved uid is explicit.
73956115Speter */
74056115Speter
74124453Speter#ifndef _SYS_SYSPROTO_H_
74256115Speterstruct setresuid_args {
74356115Speter	uid_t	ruid;
74456115Speter	uid_t	euid;
74556115Speter	uid_t	suid;
74656115Speter};
74756115Speter#endif
74856115Speter/* ARGSUSED */
74956115Speterint
75056115Spetersetresuid(p, uap)
75156115Speter	register struct proc *p;
75256115Speter	struct setresuid_args *uap;
75356115Speter{
75456115Speter	register struct pcred *pc = p->p_cred;
75556115Speter	register uid_t ruid, euid, suid;
75656115Speter	int error;
75756115Speter
75856115Speter	ruid = uap->ruid;
75956115Speter	euid = uap->euid;
76056115Speter	suid = uap->suid;
76156115Speter	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid &&
76256115Speter	      ruid != pc->pc_ucred->cr_uid) ||
76356115Speter	     (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid &&
76456115Speter	      euid != pc->pc_ucred->cr_uid) ||
76556115Speter	     (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid &&
76656115Speter	      suid != pc->pc_ucred->cr_uid)) &&
76756115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
76856115Speter		return (error);
76956115Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
77056115Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
77156115Speter		pc->pc_ucred->cr_uid = euid;
77256115Speter		setsugid(p);
77356115Speter	}
77456115Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
77561976Salfred		(void)chgproccnt(pc->p_ruid, -1, 0);
77661976Salfred		(void)chgproccnt(ruid, 1, 0);
77756115Speter		pc->p_ruid = ruid;
77856115Speter		setsugid(p);
77956115Speter	}
78056115Speter	if (suid != (uid_t)-1 && pc->p_svuid != suid) {
78156115Speter		pc->p_svuid = suid;
78256115Speter		setsugid(p);
78356115Speter	}
78456115Speter	return (0);
78556115Speter}
78656115Speter
78756115Speter/*
78856115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the
78956115Speter * saved gid is explicit.
79056115Speter */
79156115Speter
79256115Speter#ifndef _SYS_SYSPROTO_H_
79356115Speterstruct setresgid_args {
79456115Speter	gid_t	rgid;
79556115Speter	gid_t	egid;
79656115Speter	gid_t	sgid;
79756115Speter};
79856115Speter#endif
79956115Speter/* ARGSUSED */
80056115Speterint
80156115Spetersetresgid(p, uap)
80256115Speter	register struct proc *p;
80356115Speter	struct setresgid_args *uap;
80456115Speter{
80556115Speter	register struct pcred *pc = p->p_cred;
80656115Speter	register gid_t rgid, egid, sgid;
80756115Speter	int error;
80856115Speter
80956115Speter	rgid = uap->rgid;
81056115Speter	egid = uap->egid;
81156115Speter	sgid = uap->sgid;
81256115Speter	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid &&
81356115Speter	      rgid != pc->pc_ucred->cr_groups[0]) ||
81456115Speter	     (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid &&
81556115Speter	      egid != pc->pc_ucred->cr_groups[0]) ||
81656115Speter	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
81756115Speter	      sgid != pc->pc_ucred->cr_groups[0])) &&
81856115Speter	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
81956115Speter		return (error);
82056115Speter
82156115Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
82256115Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
82356115Speter		pc->pc_ucred->cr_groups[0] = egid;
82456115Speter		setsugid(p);
82556115Speter	}
82656115Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
82756115Speter		pc->p_rgid = rgid;
82856115Speter		setsugid(p);
82956115Speter	}
83056115Speter	if (sgid != (gid_t)-1 && pc->p_svgid != sgid) {
83156115Speter		pc->p_svgid = sgid;
83256115Speter		setsugid(p);
83356115Speter	}
83456115Speter	return (0);
83556115Speter}
83656115Speter
83756115Speter#ifndef _SYS_SYSPROTO_H_
83856115Speterstruct getresuid_args {
83956115Speter	uid_t	*ruid;
84056115Speter	uid_t	*euid;
84156115Speter	uid_t	*suid;
84256115Speter};
84356115Speter#endif
84456115Speter/* ARGSUSED */
84556115Speterint
84656115Spetergetresuid(p, uap)
84756115Speter	register struct proc *p;
84856115Speter	struct getresuid_args *uap;
84956115Speter{
85056115Speter	struct pcred *pc = p->p_cred;
85156115Speter	int error1 = 0, error2 = 0, error3 = 0;
85256115Speter
85356115Speter	if (uap->ruid)
85456115Speter		error1 = copyout((caddr_t)&pc->p_ruid,
85556115Speter		    (caddr_t)uap->ruid, sizeof(pc->p_ruid));
85656115Speter	if (uap->euid)
85756115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid,
85856115Speter		    (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid));
85956115Speter	if (uap->suid)
86056115Speter		error3 = copyout((caddr_t)&pc->p_svuid,
86156115Speter		    (caddr_t)uap->suid, sizeof(pc->p_svuid));
86256115Speter	return error1 ? error1 : (error2 ? error2 : error3);
86356115Speter}
86456115Speter
86556115Speter#ifndef _SYS_SYSPROTO_H_
86656115Speterstruct getresgid_args {
86756115Speter	gid_t	*rgid;
86856115Speter	gid_t	*egid;
86956115Speter	gid_t	*sgid;
87056115Speter};
87156115Speter#endif
87256115Speter/* ARGSUSED */
87356115Speterint
87456115Spetergetresgid(p, uap)
87556115Speter	register struct proc *p;
87656115Speter	struct getresgid_args *uap;
87756115Speter{
87856115Speter	struct pcred *pc = p->p_cred;
87956115Speter	int error1 = 0, error2 = 0, error3 = 0;
88056115Speter
88156115Speter	if (uap->rgid)
88256115Speter		error1 = copyout((caddr_t)&pc->p_rgid,
88356115Speter		    (caddr_t)uap->rgid, sizeof(pc->p_rgid));
88456115Speter	if (uap->egid)
88556115Speter		error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0],
88656115Speter		    (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0]));
88756115Speter	if (uap->sgid)
88856115Speter		error3 = copyout((caddr_t)&pc->p_svgid,
88956115Speter		    (caddr_t)uap->sgid, sizeof(pc->p_svgid));
89056115Speter	return error1 ? error1 : (error2 ? error2 : error3);
89156115Speter}
89256115Speter
89356115Speter
89456115Speter#ifndef _SYS_SYSPROTO_H_
89524453Speterstruct issetugid_args {
89624453Speter	int dummy;
89724453Speter};
89824453Speter#endif
89924453Speter/* ARGSUSED */
90024453Speterint
90130994Sphkissetugid(p, uap)
90224453Speter	register struct proc *p;
90324453Speter	struct issetugid_args *uap;
90424453Speter{
90524453Speter	/*
90624453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
90724453Speter	 * we use P_SUGID because we consider changing the owners as
90824453Speter	 * "tainting" as well.
90924453Speter	 * This is significant for procs that start as root and "become"
91024453Speter	 * a user without an exec - programs cannot know *everything*
91124453Speter	 * that libc *might* have put in their data segment.
91224453Speter	 */
91360216Speter	p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
91424453Speter	return (0);
91524453Speter}
91624453Speter
9171541Srgrimes/*
9181541Srgrimes * Check if gid is a member of the group set.
9191541Srgrimes */
9201549Srgrimesint
9211541Srgrimesgroupmember(gid, cred)
9221541Srgrimes	gid_t gid;
9231541Srgrimes	register struct ucred *cred;
9241541Srgrimes{
9251541Srgrimes	register gid_t *gp;
9261541Srgrimes	gid_t *egp;
9271541Srgrimes
9281541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
9291541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
9301541Srgrimes		if (*gp == gid)
9311541Srgrimes			return (1);
9321541Srgrimes	return (0);
9331541Srgrimes}
9341541Srgrimes
93561287Srwatsonstatic int suser_permitted = 1;
93661287Srwatson
93761287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
93861287Srwatson    "processes with uid 0 have privilege");
93961287Srwatson
9401541Srgrimes/*
9411541Srgrimes * Test whether the specified credentials imply "super-user"
9421541Srgrimes * privilege; if so, and we have accounting info, set the flag
9431541Srgrimes * indicating use of super-powers.
9441541Srgrimes * Returns 0 or error.
9451541Srgrimes */
9461549Srgrimesint
94746112Sphksuser(p)
94865237Srwatson	const struct proc *p;
94946112Sphk{
95046155Sphk	return suser_xxx(0, p, 0);
95146112Sphk}
95246112Sphk
95346112Sphkint
95446155Sphksuser_xxx(cred, proc, flag)
95565237Srwatson	const struct ucred *cred;
95665237Srwatson	const struct proc *proc;
95746155Sphk	int flag;
9581541Srgrimes{
95961282Srwatson	if (!suser_permitted)
96061282Srwatson		return (EPERM);
96146155Sphk	if (!cred && !proc) {
96246155Sphk		printf("suser_xxx(): THINK!\n");
96346155Sphk		return (EPERM);
9641541Srgrimes	}
96546155Sphk	if (!cred)
96646155Sphk		cred = proc->p_ucred;
96746155Sphk	if (cred->cr_uid != 0)
96846155Sphk		return (EPERM);
96946155Sphk	if (proc && proc->p_prison && !(flag & PRISON_ROOT))
97046155Sphk		return (EPERM);
97146155Sphk	return (0);
9721541Srgrimes}
9731541Srgrimes
97465237Srwatsonstatic int
97565237Srwatsonp_cansee(const struct proc *p1, const struct proc *p2, int *privused)
97665237Srwatson{
97753518Sphk
97865237Srwatson	if (privused != NULL)
97965237Srwatson		*privused = 0;
98065237Srwatson
98165237Srwatson	if (!PRISON_CHECK(p1, p2))
98265237Srwatson		return (ESRCH);
98365237Srwatson
98465237Srwatson	if (!ps_showallprocs && (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) &&
98565237Srwatson	    suser_xxx(NULL, p1, PRISON_ROOT))
98665237Srwatson		return (ESRCH);
98765237Srwatson
98865237Srwatson	return (0);
98965237Srwatson}
99065237Srwatson
99165237Srwatsonstatic int
99265237Srwatsonp_cankill(const struct proc *p1, const struct proc *p2, int *privused)
99353518Sphk{
99453518Sphk
99565237Srwatson	if (privused != NULL)
99665237Srwatson		*privused = 0;
99765237Srwatson
99853518Sphk	if (p1 == p2)
99953518Sphk		return (0);
100065237Srwatson
100153518Sphk	if (!PRISON_CHECK(p1, p2))
100253518Sphk		return (ESRCH);
100365237Srwatson
100453518Sphk	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
100553518Sphk		return (0);
100653518Sphk	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
100753518Sphk		return (0);
100865237Srwatson	/*
100965237Srwatson	 * XXX should a process be able to affect another process
101065237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
101165237Srwatson	 */
101253518Sphk	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
101353518Sphk		return (0);
101453518Sphk	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
101553518Sphk		return (0);
101665237Srwatson
101765237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
101865237Srwatson		if (privused != NULL)
101965237Srwatson			*privused = 1;
102053518Sphk		return (0);
102165237Srwatson	}
102265237Srwatson
102365237Srwatson#ifdef CAPABILITIES
102465237Srwatson	if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) {
102565237Srwatson		if (privused != NULL)
102665237Srwatson			*privused = 1;
102765237Srwatson		return (0);
102865237Srwatson	}
102965237Srwatson#endif
103065237Srwatson
103153518Sphk	return (EPERM);
103253518Sphk}
103353518Sphk
103465237Srwatsonstatic int
103565237Srwatsonp_cansched(const struct proc *p1, const struct proc *p2, int *privused)
103665237Srwatson{
103765237Srwatson
103865237Srwatson	if (privused != NULL)
103965237Srwatson		*privused = 0;
104065237Srwatson
104165237Srwatson	if (p1 == p2)
104265237Srwatson		return (0);
104365237Srwatson
104465237Srwatson	if (!PRISON_CHECK(p1, p2))
104565237Srwatson		return (ESRCH);
104665237Srwatson
104765237Srwatson	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
104865237Srwatson		return (0);
104965237Srwatson	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
105065237Srwatson		return (0);
105165237Srwatson	/*
105265237Srwatson	 * XXX should a process be able to affect another process
105365237Srwatson	 * acting as the same uid (i.e., a userland nfsd or the like?)
105465237Srwatson	 */
105565237Srwatson	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
105665237Srwatson		return (0);
105765237Srwatson	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
105865237Srwatson		return (0);
105965237Srwatson
106065237Srwatson	if (!suser_xxx(0, p1, PRISON_ROOT)) {
106165237Srwatson		if (privused != NULL)
106265237Srwatson			*privused = 1;
106365237Srwatson		return (0);
106465237Srwatson	}
106565237Srwatson
106665237Srwatson#ifdef CAPABILITIES
106765237Srwatson	if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) {
106865237Srwatson		if (privused != NULL)
106965237Srwatson			*privused = 1;
107065237Srwatson		return (0);
107165237Srwatson	}
107265237Srwatson#endif
107365237Srwatson
107465237Srwatson	return (EPERM);
107565237Srwatson}
107665237Srwatson
107765237Srwatsonstatic int
107865237Srwatsonp_candebug(const struct proc *p1, const struct proc *p2, int *privused)
107965237Srwatson{
108065237Srwatson	int	error;
108165237Srwatson
108265237Srwatson	if (privused != NULL)
108365237Srwatson		*privused = 0;
108465237Srwatson
108565237Srwatson	/* XXX it is authorized, but semantics don't permit it */
108665237Srwatson	if (p1 == p2)
108765237Srwatson		return (0);
108865237Srwatson
108965237Srwatson	if (!PRISON_CHECK(p1, p2))
109065237Srwatson		return (ESRCH);
109165237Srwatson
109265237Srwatson	/* not owned by you, has done setuid (unless you're root) */
109365237Srwatson	/* add a CAP_SYS_PTRACE here? */
109465237Srwatson	if ((p1->p_cred->p_ruid != p2->p_cred->p_ruid) ||
109565237Srwatson	    (p2->p_flag & P_SUGID)) {
109665237Srwatson		if ((error = suser_xxx(0, p1, PRISON_ROOT)))
109765237Srwatson			return (error);
109865237Srwatson		if (privused != NULL)
109965237Srwatson			*privused = 1;
110065237Srwatson	}
110165237Srwatson
110265237Srwatson	/* can't trace init when securelevel > 0 */
110365237Srwatson	if (securelevel > 0 && p2->p_pid == 1)
110465237Srwatson		return (EPERM);
110565237Srwatson
110665237Srwatson	return (0);
110765237Srwatson}
110865237Srwatson
110965237Srwatsonint
111065237Srwatsonp_can(const struct proc *p1, const struct proc *p2, int operation,
111165237Srwatson    int *privused)
111265237Srwatson{
111365237Srwatson
111465237Srwatson	switch(operation) {
111565237Srwatson	case P_CAN_SEE:
111665237Srwatson		return (p_cansee(p1, p2, privused));
111765237Srwatson
111865237Srwatson	case P_CAN_KILL:
111965237Srwatson		return (p_cankill(p1, p2, privused));
112065237Srwatson
112165237Srwatson	case P_CAN_SCHED:
112265237Srwatson		return (p_cansched(p1, p2, privused));
112365237Srwatson
112465237Srwatson	case P_CAN_DEBUG:
112565237Srwatson		return (p_candebug(p1, p2, privused));
112665237Srwatson
112765237Srwatson	default:
112865237Srwatson		panic("p_can: invalid operation");
112965237Srwatson	}
113065237Srwatson}
113165237Srwatson
113265237Srwatson
113353518Sphk/*
11341541Srgrimes * Allocate a zeroed cred structure.
11351541Srgrimes */
11361541Srgrimesstruct ucred *
11371541Srgrimescrget()
11381541Srgrimes{
11391541Srgrimes	register struct ucred *cr;
11401541Srgrimes
11411541Srgrimes	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
11421541Srgrimes	bzero((caddr_t)cr, sizeof(*cr));
11431541Srgrimes	cr->cr_ref = 1;
11441541Srgrimes	return (cr);
11451541Srgrimes}
11461541Srgrimes
11471541Srgrimes/*
11481541Srgrimes * Free a cred structure.
11491541Srgrimes * Throws away space when ref count gets to 0.
11501541Srgrimes */
11511549Srgrimesvoid
11521541Srgrimescrfree(cr)
11531541Srgrimes	struct ucred *cr;
11541541Srgrimes{
11551541Srgrimes	if (--cr->cr_ref == 0)
11561541Srgrimes		FREE((caddr_t)cr, M_CRED);
11571541Srgrimes}
11581541Srgrimes
11591541Srgrimes/*
11601541Srgrimes * Copy cred structure to a new one and free the old one.
11611541Srgrimes */
11621541Srgrimesstruct ucred *
11631541Srgrimescrcopy(cr)
11641541Srgrimes	struct ucred *cr;
11651541Srgrimes{
11661541Srgrimes	struct ucred *newcr;
11671541Srgrimes
11681541Srgrimes	if (cr->cr_ref == 1)
11691541Srgrimes		return (cr);
11701541Srgrimes	newcr = crget();
11711541Srgrimes	*newcr = *cr;
11721541Srgrimes	crfree(cr);
11731541Srgrimes	newcr->cr_ref = 1;
11741541Srgrimes	return (newcr);
11751541Srgrimes}
11761541Srgrimes
11771541Srgrimes/*
11781541Srgrimes * Dup cred struct to a new held one.
11791541Srgrimes */
11801541Srgrimesstruct ucred *
11811541Srgrimescrdup(cr)
11821541Srgrimes	struct ucred *cr;
11831541Srgrimes{
11841541Srgrimes	struct ucred *newcr;
11851541Srgrimes
11861541Srgrimes	newcr = crget();
11871541Srgrimes	*newcr = *cr;
11881541Srgrimes	newcr->cr_ref = 1;
11891541Srgrimes	return (newcr);
11901541Srgrimes}
11911541Srgrimes
11921541Srgrimes/*
11931541Srgrimes * Get login name, if available.
11941541Srgrimes */
119512221Sbde#ifndef _SYS_SYSPROTO_H_
11961541Srgrimesstruct getlogin_args {
11971541Srgrimes	char	*namebuf;
11981541Srgrimes	u_int	namelen;
11991541Srgrimes};
120012221Sbde#endif
12011541Srgrimes/* ARGSUSED */
12021549Srgrimesint
120330994Sphkgetlogin(p, uap)
12041541Srgrimes	struct proc *p;
12051541Srgrimes	struct getlogin_args *uap;
12061541Srgrimes{
12071541Srgrimes
120823358Sache	if (uap->namelen > MAXLOGNAME)
120923359Sache		uap->namelen = MAXLOGNAME;
12101541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
12111541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
12121541Srgrimes}
12131541Srgrimes
12141541Srgrimes/*
12151541Srgrimes * Set login name.
12161541Srgrimes */
121712221Sbde#ifndef _SYS_SYSPROTO_H_
12181541Srgrimesstruct setlogin_args {
12191541Srgrimes	char	*namebuf;
12201541Srgrimes};
122112221Sbde#endif
12221541Srgrimes/* ARGSUSED */
12231549Srgrimesint
122430994Sphksetlogin(p, uap)
12251541Srgrimes	struct proc *p;
12261541Srgrimes	struct setlogin_args *uap;
12271541Srgrimes{
12281541Srgrimes	int error;
122923330Sache	char logintmp[MAXLOGNAME];
12301541Srgrimes
123146155Sphk	if ((error = suser_xxx(0, p, PRISON_ROOT)))
12321541Srgrimes		return (error);
123322522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
123436845Sdfr	    sizeof(logintmp), (size_t *)0);
12351541Srgrimes	if (error == ENAMETOOLONG)
12361541Srgrimes		error = EINVAL;
123722522Sdavidn	else if (!error)
123822522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
123923330Sache		    sizeof(logintmp));
12401541Srgrimes	return (error);
12411541Srgrimes}
124231891Ssef
124331891Ssefvoid
124431891Ssefsetsugid(p)
124555338Sphk	struct proc *p;
124631891Ssef{
124731891Ssef	p->p_flag |= P_SUGID;
124855707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
124931891Ssef		p->p_stops = 0;
125031891Ssef}
1251