kern_prot.c revision 41726
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
3941726Struckman * $Id: kern_prot.c,v 1.42 1998/11/10 09:16:29 peter Exp $
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>
5518013Sbde#include <sys/unistd.h>
5631891Ssef#include <sys/pioctl.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
661541Srgrimes/* ARGSUSED */
671549Srgrimesint
6830994Sphkgetpid(p, uap)
691541Srgrimes	struct proc *p;
7011332Sswallace	struct getpid_args *uap;
711541Srgrimes{
721541Srgrimes
7330994Sphk	p->p_retval[0] = p->p_pid;
741541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
7530994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
761541Srgrimes#endif
771541Srgrimes	return (0);
781541Srgrimes}
791541Srgrimes
8012221Sbde#ifndef _SYS_SYSPROTO_H_
8111332Sswallacestruct getppid_args {
8211332Sswallace        int     dummy;
8311332Sswallace};
8412221Sbde#endif
851541Srgrimes/* ARGSUSED */
861549Srgrimesint
8730994Sphkgetppid(p, uap)
881541Srgrimes	struct proc *p;
8911332Sswallace	struct getppid_args *uap;
901541Srgrimes{
911541Srgrimes
9230994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
931541Srgrimes	return (0);
941541Srgrimes}
951541Srgrimes
961541Srgrimes/* Get process group ID; note that POSIX getpgrp takes no parameter */
9712221Sbde#ifndef _SYS_SYSPROTO_H_
9811332Sswallacestruct getpgrp_args {
9911332Sswallace        int     dummy;
10011332Sswallace};
10112221Sbde#endif
10211332Sswallace
1031549Srgrimesint
10430994Sphkgetpgrp(p, uap)
1051541Srgrimes	struct proc *p;
10611332Sswallace	struct getpgrp_args *uap;
1071541Srgrimes{
1081541Srgrimes
10930994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1101541Srgrimes	return (0);
1111541Srgrimes}
1121541Srgrimes
11328401Speter/* Get an arbitary pid's process group id */
11412221Sbde#ifndef _SYS_SYSPROTO_H_
11528401Speterstruct getpgid_args {
11628401Speter	pid_t	pid;
11728401Speter};
11828401Speter#endif
11928401Speter
12028401Speterint
12130994Sphkgetpgid(p, uap)
12228401Speter	struct proc *p;
12328401Speter	struct getpgid_args *uap;
12428401Speter{
12541726Struckman	struct proc *pt;
12641726Struckman
12741726Struckman	pt = p;
12828401Speter	if (uap->pid == 0)
12928401Speter		goto found;
13028401Speter
13141726Struckman	if ((pt = pfind(uap->pid)) == 0)
13228401Speter		return ESRCH;
13328401Speterfound:
13441726Struckman	p->p_retval[0] = pt->p_pgrp->pg_id;
13528401Speter	return 0;
13628401Speter}
13728401Speter
13828401Speter/*
13928401Speter * Get an arbitary pid's session id.
14028401Speter */
14128401Speter#ifndef _SYS_SYSPROTO_H_
14228401Speterstruct getsid_args {
14328401Speter	pid_t	pid;
14428401Speter};
14528401Speter#endif
14628401Speter
14728401Speterint
14830994Sphkgetsid(p, uap)
14928401Speter	struct proc *p;
15028401Speter	struct getsid_args *uap;
15128401Speter{
15241726Struckman	struct proc *pt;
15341726Struckman
15441726Struckman	pt = p;
15528401Speter	if (uap->pid == 0)
15628401Speter		goto found;
15728401Speter
15841726Struckman	if ((pt == pfind(uap->pid)) == 0)
15928401Speter		return ESRCH;
16028401Speterfound:
16141726Struckman	p->p_retval[0] = pt->p_session->s_sid;
16228401Speter	return 0;
16328401Speter}
16428401Speter
16528401Speter
16628401Speter#ifndef _SYS_SYSPROTO_H_
16711332Sswallacestruct getuid_args {
16811332Sswallace        int     dummy;
16911332Sswallace};
17012221Sbde#endif
17111332Sswallace
1721541Srgrimes/* ARGSUSED */
1731549Srgrimesint
17430994Sphkgetuid(p, uap)
1751541Srgrimes	struct proc *p;
17611332Sswallace	struct getuid_args *uap;
1771541Srgrimes{
1781541Srgrimes
17930994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
1801541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
18130994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
1821541Srgrimes#endif
1831541Srgrimes	return (0);
1841541Srgrimes}
1851541Srgrimes
18612221Sbde#ifndef _SYS_SYSPROTO_H_
18711332Sswallacestruct geteuid_args {
18811332Sswallace        int     dummy;
18911332Sswallace};
19012221Sbde#endif
19111332Sswallace
1921541Srgrimes/* ARGSUSED */
1931549Srgrimesint
19430994Sphkgeteuid(p, uap)
1951541Srgrimes	struct proc *p;
19611332Sswallace	struct geteuid_args *uap;
1971541Srgrimes{
1981541Srgrimes
19930994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
2001541Srgrimes	return (0);
2011541Srgrimes}
2021541Srgrimes
20312221Sbde#ifndef _SYS_SYSPROTO_H_
20411332Sswallacestruct getgid_args {
20511332Sswallace        int     dummy;
20611332Sswallace};
20712221Sbde#endif
20811332Sswallace
2091541Srgrimes/* ARGSUSED */
2101549Srgrimesint
21130994Sphkgetgid(p, uap)
2121541Srgrimes	struct proc *p;
21311332Sswallace	struct getgid_args *uap;
2141541Srgrimes{
2151541Srgrimes
21630994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2171541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
21830994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2191541Srgrimes#endif
2201541Srgrimes	return (0);
2211541Srgrimes}
2221541Srgrimes
2231541Srgrimes/*
2241541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2251541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2261541Srgrimes * correctly in a library function.
2271541Srgrimes */
22812221Sbde#ifndef _SYS_SYSPROTO_H_
22911332Sswallacestruct getegid_args {
23011332Sswallace        int     dummy;
23111332Sswallace};
23212221Sbde#endif
23311332Sswallace
2341541Srgrimes/* ARGSUSED */
2351549Srgrimesint
23630994Sphkgetegid(p, uap)
2371541Srgrimes	struct proc *p;
23811332Sswallace	struct getegid_args *uap;
2391541Srgrimes{
2401541Srgrimes
24130994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2421541Srgrimes	return (0);
2431541Srgrimes}
2441541Srgrimes
24512221Sbde#ifndef _SYS_SYSPROTO_H_
2461541Srgrimesstruct getgroups_args {
2471541Srgrimes	u_int	gidsetsize;
2481541Srgrimes	gid_t	*gidset;
2491541Srgrimes};
25012221Sbde#endif
2511549Srgrimesint
25230994Sphkgetgroups(p, uap)
2531541Srgrimes	struct proc *p;
2541541Srgrimes	register struct	getgroups_args *uap;
2551541Srgrimes{
2561541Srgrimes	register struct pcred *pc = p->p_cred;
2571541Srgrimes	register u_int ngrp;
2581541Srgrimes	int error;
2591541Srgrimes
2601541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
26130994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2621541Srgrimes		return (0);
2631541Srgrimes	}
2641541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2651541Srgrimes		return (EINVAL);
2661541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2673098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2683098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2691541Srgrimes		return (error);
27030994Sphk	p->p_retval[0] = ngrp;
2711541Srgrimes	return (0);
2721541Srgrimes}
2731541Srgrimes
27412221Sbde#ifndef _SYS_SYSPROTO_H_
27512207Sbdestruct setsid_args {
27611332Sswallace        int     dummy;
27711332Sswallace};
27812221Sbde#endif
27911332Sswallace
2801541Srgrimes/* ARGSUSED */
2811549Srgrimesint
28230994Sphksetsid(p, uap)
2831541Srgrimes	register struct proc *p;
28412207Sbde	struct setsid_args *uap;
2851541Srgrimes{
2861541Srgrimes
2871541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
2881541Srgrimes		return (EPERM);
2891541Srgrimes	} else {
2901541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
29130994Sphk		p->p_retval[0] = p->p_pid;
2921541Srgrimes		return (0);
2931541Srgrimes	}
2941541Srgrimes}
2951541Srgrimes
2961541Srgrimes/*
2971541Srgrimes * set process group (setpgid/old setpgrp)
2981541Srgrimes *
2991541Srgrimes * caller does setpgid(targpid, targpgid)
3001541Srgrimes *
3011541Srgrimes * pid must be caller or child of caller (ESRCH)
3021541Srgrimes * if a child
3031541Srgrimes *	pid must be in same session (EPERM)
3041541Srgrimes *	pid can't have done an exec (EACCES)
3051541Srgrimes * if pgid != pid
3061541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3071541Srgrimes * pid must not be session leader (EPERM)
3081541Srgrimes */
30912221Sbde#ifndef _SYS_SYSPROTO_H_
3101541Srgrimesstruct setpgid_args {
3111541Srgrimes	int	pid;	/* target process id */
3121541Srgrimes	int	pgid;	/* target pgrp id */
3131541Srgrimes};
31412221Sbde#endif
3151541Srgrimes/* ARGSUSED */
3161549Srgrimesint
31730994Sphksetpgid(curp, uap)
3181541Srgrimes	struct proc *curp;
3191541Srgrimes	register struct setpgid_args *uap;
3201541Srgrimes{
3211541Srgrimes	register struct proc *targp;		/* target process */
3221541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
3231541Srgrimes
32420677Sbde	if (uap->pgid < 0)
32520677Sbde		return (EINVAL);
3261541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3271541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3281541Srgrimes			return (ESRCH);
32915985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3301541Srgrimes			return (EPERM);
3311541Srgrimes		if (targp->p_flag & P_EXEC)
3321541Srgrimes			return (EACCES);
3331541Srgrimes	} else
3341541Srgrimes		targp = curp;
3351541Srgrimes	if (SESS_LEADER(targp))
3361541Srgrimes		return (EPERM);
3371541Srgrimes	if (uap->pgid == 0)
3381541Srgrimes		uap->pgid = targp->p_pid;
3391541Srgrimes	else if (uap->pgid != targp->p_pid)
3401541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3411541Srgrimes	            pgrp->pg_session != curp->p_session)
3421541Srgrimes			return (EPERM);
3431541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3441541Srgrimes}
3451541Srgrimes
34624448Speter/*
34724448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
34824448Speter * compatable.  It says that setting the uid/gid to euid/egid is a special
34924448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
35024448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
35124448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
35224448Speter * does not set the saved id - this is dangerous for traditional BSD
35324448Speter * programs.  For this reason, we *really* do not want to set
35424448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
35524448Speter */
35624448Speter#define POSIX_APPENDIX_B_4_2_2
35724448Speter
35812221Sbde#ifndef _SYS_SYSPROTO_H_
3591541Srgrimesstruct setuid_args {
3601541Srgrimes	uid_t	uid;
3611541Srgrimes};
36212221Sbde#endif
3631541Srgrimes/* ARGSUSED */
3641549Srgrimesint
36530994Sphksetuid(p, uap)
3661541Srgrimes	struct proc *p;
3671541Srgrimes	struct setuid_args *uap;
3681541Srgrimes{
3691541Srgrimes	register struct pcred *pc = p->p_cred;
3701541Srgrimes	register uid_t uid;
3711541Srgrimes	int error;
3721541Srgrimes
37324448Speter	/*
37424448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
37524448Speter	 *
37624448Speter	 * Note that setuid(geteuid()) is a special case of
37724448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
37824448Speter	 * to use this clause to be compatable with traditional BSD
37924448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
38024448Speter	 * three id's (assuming you have privs).
38124448Speter	 *
38224448Speter	 * Notes on the logic.  We do things in three steps.
38324448Speter	 * 1: We determine if the euid is going to change, and do EPERM
38424448Speter	 *    right away.  We unconditionally change the euid later if this
38524448Speter	 *    test is satisfied, simplifying that part of the logic.
38624448Speter	 * 2: We determine if the real and/or saved uid's are going to
38724448Speter	 *    change.  Determined by compile options.
38824448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
38924448Speter	 */
3901541Srgrimes	uid = uap->uid;
39124448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
39217994Sache#ifdef _POSIX_SAVED_IDS
39324448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
39417994Sache#endif
39524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
39624448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
39724448Speter#endif
3988162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
3991541Srgrimes		return (error);
40024448Speter
40124448Speter#ifdef _POSIX_SAVED_IDS
4021541Srgrimes	/*
40324448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
40424448Speter	 * If so, we are changing the real uid and/or saved uid.
4051541Srgrimes	 */
40617994Sache	if (
40724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
40824448Speter	    uid == pc->pc_ucred->cr_uid ||
40917994Sache#endif
41024448Speter	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
41117994Sache#endif
41224448Speter	{
41324448Speter		/*
41424448Speter		 * Transfer proc count to new user.
41524448Speter		 */
41624448Speter		if (uid != pc->p_ruid) {
41724448Speter			(void)chgproccnt(pc->p_ruid, -1);
41824448Speter			(void)chgproccnt(uid, 1);
41924448Speter		}
42024448Speter		/*
42124448Speter		 * Set real uid
42224448Speter		 */
42324448Speter		if (uid != pc->p_ruid) {
42424448Speter			pc->p_ruid = uid;
42531891Ssef			setsugid(p);
42624448Speter		}
42724448Speter		/*
42824448Speter		 * Set saved uid
42924448Speter		 *
43024448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
43124448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
43224448Speter		 * is important that we should do this.
43324448Speter		 */
43424448Speter		if (pc->p_svuid != uid) {
43524448Speter			pc->p_svuid = uid;
43631891Ssef			setsugid(p);
43724448Speter		}
4388141Sache	}
43924448Speter
44024448Speter	/*
44124448Speter	 * In all permitted cases, we are changing the euid.
44224448Speter	 * Copy credentials so other references do not see our changes.
44324448Speter	 */
44424448Speter	if (pc->pc_ucred->cr_uid != uid) {
44524448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
44624448Speter		pc->pc_ucred->cr_uid = uid;
44731891Ssef		setsugid(p);
44824448Speter	}
4491541Srgrimes	return (0);
4501541Srgrimes}
4511541Srgrimes
45212221Sbde#ifndef _SYS_SYSPROTO_H_
4531541Srgrimesstruct seteuid_args {
4541541Srgrimes	uid_t	euid;
4551541Srgrimes};
45612221Sbde#endif
4571541Srgrimes/* ARGSUSED */
4581549Srgrimesint
45930994Sphkseteuid(p, uap)
4601541Srgrimes	struct proc *p;
4611541Srgrimes	struct seteuid_args *uap;
4621541Srgrimes{
4631541Srgrimes	register struct pcred *pc = p->p_cred;
4641541Srgrimes	register uid_t euid;
4651541Srgrimes	int error;
4661541Srgrimes
4671541Srgrimes	euid = uap->euid;
46824449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
46924449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
4701541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4711541Srgrimes		return (error);
4721541Srgrimes	/*
4731541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4741541Srgrimes	 * not see our changes.
4751541Srgrimes	 */
47624449Speter	if (pc->pc_ucred->cr_uid != euid) {
47724449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
47824449Speter		pc->pc_ucred->cr_uid = euid;
47931891Ssef		setsugid(p);
48024449Speter	}
4811541Srgrimes	return (0);
4821541Srgrimes}
4831541Srgrimes
48412221Sbde#ifndef _SYS_SYSPROTO_H_
4851541Srgrimesstruct setgid_args {
4861541Srgrimes	gid_t	gid;
4871541Srgrimes};
48812221Sbde#endif
4891541Srgrimes/* ARGSUSED */
4901549Srgrimesint
49130994Sphksetgid(p, uap)
4921541Srgrimes	struct proc *p;
4931541Srgrimes	struct setgid_args *uap;
4941541Srgrimes{
4951541Srgrimes	register struct pcred *pc = p->p_cred;
4961541Srgrimes	register gid_t gid;
4971541Srgrimes	int error;
4981541Srgrimes
49924448Speter	/*
50024448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
50124448Speter	 *
50224448Speter	 * Note that setgid(getegid()) is a special case of
50324448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
50424448Speter	 * to use this clause to be compatable with traditional BSD
50524448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
50624448Speter	 * three id's (assuming you have privs).
50724448Speter	 *
50824448Speter	 * For notes on the logic here, see setuid() above.
50924448Speter	 */
5101541Srgrimes	gid = uap->gid;
51124448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
51217994Sache#ifdef _POSIX_SAVED_IDS
51324448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
51417994Sache#endif
51524448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
51624448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
51724448Speter#endif
5188162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
5191541Srgrimes		return (error);
52024448Speter
52117994Sache#ifdef _POSIX_SAVED_IDS
52224448Speter	/*
52324448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
52424448Speter	 * If so, we are changing the real uid and saved gid.
52524448Speter	 */
52624448Speter	if (
52724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
52824448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
52917994Sache#endif
53024448Speter	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
53124448Speter#endif
53224448Speter	{
53324448Speter		/*
53424448Speter		 * Set real gid
53524448Speter		 */
53624448Speter		if (pc->p_rgid != gid) {
53724448Speter			pc->p_rgid = gid;
53831891Ssef			setsugid(p);
53924448Speter		}
54024448Speter		/*
54124448Speter		 * Set saved gid
54224448Speter		 *
54324448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
54424448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
54524448Speter		 * is important that we should do this.
54624448Speter		 */
54724448Speter		if (pc->p_svgid != gid) {
54824448Speter			pc->p_svgid = gid;
54931891Ssef			setsugid(p);
55024448Speter		}
5518141Sache	}
55224448Speter	/*
55324448Speter	 * In all cases permitted cases, we are changing the egid.
55424448Speter	 * Copy credentials so other references do not see our changes.
55524448Speter	 */
55624448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
55724448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
55824448Speter		pc->pc_ucred->cr_groups[0] = gid;
55931891Ssef		setsugid(p);
56024448Speter	}
5611541Srgrimes	return (0);
5621541Srgrimes}
5631541Srgrimes
56412221Sbde#ifndef _SYS_SYSPROTO_H_
5651541Srgrimesstruct setegid_args {
5661541Srgrimes	gid_t	egid;
5671541Srgrimes};
56812221Sbde#endif
5691541Srgrimes/* ARGSUSED */
5701549Srgrimesint
57130994Sphksetegid(p, uap)
5721541Srgrimes	struct proc *p;
5731541Srgrimes	struct setegid_args *uap;
5741541Srgrimes{
5751541Srgrimes	register struct pcred *pc = p->p_cred;
5761541Srgrimes	register gid_t egid;
5771541Srgrimes	int error;
5781541Srgrimes
5791541Srgrimes	egid = uap->egid;
58024449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
58124449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
5821541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
5831541Srgrimes		return (error);
58424449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
58524449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
58624449Speter		pc->pc_ucred->cr_groups[0] = egid;
58731891Ssef		setsugid(p);
58824449Speter	}
5891541Srgrimes	return (0);
5901541Srgrimes}
5911541Srgrimes
59212221Sbde#ifndef _SYS_SYSPROTO_H_
5931541Srgrimesstruct setgroups_args {
5941541Srgrimes	u_int	gidsetsize;
5951541Srgrimes	gid_t	*gidset;
5961541Srgrimes};
59712221Sbde#endif
5981541Srgrimes/* ARGSUSED */
5991549Srgrimesint
60030994Sphksetgroups(p, uap)
6011541Srgrimes	struct proc *p;
6021541Srgrimes	struct setgroups_args *uap;
6031541Srgrimes{
6041541Srgrimes	register struct pcred *pc = p->p_cred;
6051541Srgrimes	register u_int ngrp;
6061541Srgrimes	int error;
6071541Srgrimes
6083098Sphk	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
6091541Srgrimes		return (error);
61012063Sdg	ngrp = uap->gidsetsize;
61124447Speter	if (ngrp > NGROUPS)
6121541Srgrimes		return (EINVAL);
61324447Speter	/*
61424447Speter	 * XXX A little bit lazy here.  We could test if anything has
61524447Speter	 * changed before crcopy() and setting P_SUGID.
61624447Speter	 */
6171541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
61824447Speter	if (ngrp < 1) {
61924447Speter		/*
62024447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
62124447Speter		 * groups vector on non-BSD systems (which generally do not
62224447Speter		 * have the egid in the groups[0]).  We risk security holes
62324447Speter		 * when running non-BSD software if we do not do the same.
62424447Speter		 */
62524447Speter		pc->pc_ucred->cr_ngroups = 1;
62624447Speter	} else {
62724447Speter		if ((error = copyin((caddr_t)uap->gidset,
62824447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
62924447Speter			return (error);
63024447Speter		pc->pc_ucred->cr_ngroups = ngrp;
63124447Speter	}
63231891Ssef	setsugid(p);
6331541Srgrimes	return (0);
6341541Srgrimes}
6351541Srgrimes
63612221Sbde#ifndef _SYS_SYSPROTO_H_
6371541Srgrimesstruct setreuid_args {
6389238Sache	uid_t	ruid;
6399238Sache	uid_t	euid;
6401541Srgrimes};
64112221Sbde#endif
6421541Srgrimes/* ARGSUSED */
6431549Srgrimesint
64430994Sphksetreuid(p, uap)
6451541Srgrimes	register struct proc *p;
6461541Srgrimes	struct setreuid_args *uap;
6471541Srgrimes{
6481541Srgrimes	register struct pcred *pc = p->p_cred;
6499238Sache	register uid_t ruid, euid;
6508135Sache	int error;
6511541Srgrimes
6529238Sache	ruid = uap->ruid;
6539238Sache	euid = uap->euid;
6549238Sache	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
65524559Speter	     euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
65624559Speter	     euid != pc->p_ruid && euid != pc->p_svuid) &&
6578135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
6588135Sache		return (error);
6599238Sache
66024450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
66124450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
6629238Sache		pc->pc_ucred->cr_uid = euid;
66331891Ssef		setsugid(p);
66424450Speter	}
66524450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
6669238Sache		(void)chgproccnt(pc->p_ruid, -1);
6679238Sache		(void)chgproccnt(ruid, 1);
6689238Sache		pc->p_ruid = ruid;
66931891Ssef		setsugid(p);
6708135Sache	}
67124559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
67224559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6738111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
67431891Ssef		setsugid(p);
67524450Speter	}
6768135Sache	return (0);
6771541Srgrimes}
6781541Srgrimes
67912221Sbde#ifndef _SYS_SYSPROTO_H_
6801541Srgrimesstruct setregid_args {
6819238Sache	gid_t	rgid;
6829238Sache	gid_t	egid;
6831541Srgrimes};
68412221Sbde#endif
6851541Srgrimes/* ARGSUSED */
6861549Srgrimesint
68730994Sphksetregid(p, uap)
6881541Srgrimes	register struct proc *p;
6891541Srgrimes	struct setregid_args *uap;
6901541Srgrimes{
6911541Srgrimes	register struct pcred *pc = p->p_cred;
6929238Sache	register gid_t rgid, egid;
6938135Sache	int error;
6941541Srgrimes
6959238Sache	rgid = uap->rgid;
6969238Sache	egid = uap->egid;
6979238Sache	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
69824559Speter	     egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
69924559Speter	     egid != pc->p_rgid && egid != pc->p_svgid) &&
7008135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
7018135Sache		return (error);
7029238Sache
70324450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
70424450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
7059238Sache		pc->pc_ucred->cr_groups[0] = egid;
70631891Ssef		setsugid(p);
70724450Speter	}
70824450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7099238Sache		pc->p_rgid = rgid;
71031891Ssef		setsugid(p);
71124450Speter	}
71224559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
71324559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7148111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
71531891Ssef		setsugid(p);
71624450Speter	}
7178135Sache	return (0);
7181541Srgrimes}
7191541Srgrimes
72024453Speter#ifndef _SYS_SYSPROTO_H_
72124453Speterstruct issetugid_args {
72224453Speter	int dummy;
72324453Speter};
72424453Speter#endif
72524453Speter/* ARGSUSED */
72624453Speterint
72730994Sphkissetugid(p, uap)
72824453Speter	register struct proc *p;
72924453Speter	struct issetugid_args *uap;
73024453Speter{
73124453Speter	/*
73224453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
73324453Speter	 * we use P_SUGID because we consider changing the owners as
73424453Speter	 * "tainting" as well.
73524453Speter	 * This is significant for procs that start as root and "become"
73624453Speter	 * a user without an exec - programs cannot know *everything*
73724453Speter	 * that libc *might* have put in their data segment.
73824453Speter	 */
73924453Speter	if (p->p_flag & P_SUGID)
74024453Speter		return (1);
74124453Speter	return (0);
74224453Speter}
74324453Speter
7441541Srgrimes/*
7451541Srgrimes * Check if gid is a member of the group set.
7461541Srgrimes */
7471549Srgrimesint
7481541Srgrimesgroupmember(gid, cred)
7491541Srgrimes	gid_t gid;
7501541Srgrimes	register struct ucred *cred;
7511541Srgrimes{
7521541Srgrimes	register gid_t *gp;
7531541Srgrimes	gid_t *egp;
7541541Srgrimes
7551541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
7561541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
7571541Srgrimes		if (*gp == gid)
7581541Srgrimes			return (1);
7591541Srgrimes	return (0);
7601541Srgrimes}
7611541Srgrimes
7621541Srgrimes/*
7631541Srgrimes * Test whether the specified credentials imply "super-user"
7641541Srgrimes * privilege; if so, and we have accounting info, set the flag
7651541Srgrimes * indicating use of super-powers.
7661541Srgrimes * Returns 0 or error.
7671541Srgrimes */
7681549Srgrimesint
7691541Srgrimessuser(cred, acflag)
7701541Srgrimes	struct ucred *cred;
7718011Sbde	u_short *acflag;
7721541Srgrimes{
7731541Srgrimes	if (cred->cr_uid == 0) {
7741541Srgrimes		if (acflag)
7751541Srgrimes			*acflag |= ASU;
7761541Srgrimes		return (0);
7771541Srgrimes	}
7781541Srgrimes	return (EPERM);
7791541Srgrimes}
7801541Srgrimes
7811541Srgrimes/*
7821541Srgrimes * Allocate a zeroed cred structure.
7831541Srgrimes */
7841541Srgrimesstruct ucred *
7851541Srgrimescrget()
7861541Srgrimes{
7871541Srgrimes	register struct ucred *cr;
7881541Srgrimes
7891541Srgrimes	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
7901541Srgrimes	bzero((caddr_t)cr, sizeof(*cr));
7911541Srgrimes	cr->cr_ref = 1;
7921541Srgrimes	return (cr);
7931541Srgrimes}
7941541Srgrimes
7951541Srgrimes/*
7961541Srgrimes * Free a cred structure.
7971541Srgrimes * Throws away space when ref count gets to 0.
7981541Srgrimes */
7991549Srgrimesvoid
8001541Srgrimescrfree(cr)
8011541Srgrimes	struct ucred *cr;
8021541Srgrimes{
8031541Srgrimes	if (--cr->cr_ref == 0)
8041541Srgrimes		FREE((caddr_t)cr, M_CRED);
8051541Srgrimes}
8061541Srgrimes
8071541Srgrimes/*
8081541Srgrimes * Copy cred structure to a new one and free the old one.
8091541Srgrimes */
8101541Srgrimesstruct ucred *
8111541Srgrimescrcopy(cr)
8121541Srgrimes	struct ucred *cr;
8131541Srgrimes{
8141541Srgrimes	struct ucred *newcr;
8151541Srgrimes
8161541Srgrimes	if (cr->cr_ref == 1)
8171541Srgrimes		return (cr);
8181541Srgrimes	newcr = crget();
8191541Srgrimes	*newcr = *cr;
8201541Srgrimes	crfree(cr);
8211541Srgrimes	newcr->cr_ref = 1;
8221541Srgrimes	return (newcr);
8231541Srgrimes}
8241541Srgrimes
8251541Srgrimes/*
8261541Srgrimes * Dup cred struct to a new held one.
8271541Srgrimes */
8281541Srgrimesstruct ucred *
8291541Srgrimescrdup(cr)
8301541Srgrimes	struct ucred *cr;
8311541Srgrimes{
8321541Srgrimes	struct ucred *newcr;
8331541Srgrimes
8341541Srgrimes	newcr = crget();
8351541Srgrimes	*newcr = *cr;
8361541Srgrimes	newcr->cr_ref = 1;
8371541Srgrimes	return (newcr);
8381541Srgrimes}
8391541Srgrimes
8401541Srgrimes/*
8411541Srgrimes * Get login name, if available.
8421541Srgrimes */
84312221Sbde#ifndef _SYS_SYSPROTO_H_
8441541Srgrimesstruct getlogin_args {
8451541Srgrimes	char	*namebuf;
8461541Srgrimes	u_int	namelen;
8471541Srgrimes};
84812221Sbde#endif
8491541Srgrimes/* ARGSUSED */
8501549Srgrimesint
85130994Sphkgetlogin(p, uap)
8521541Srgrimes	struct proc *p;
8531541Srgrimes	struct getlogin_args *uap;
8541541Srgrimes{
8551541Srgrimes
85623358Sache	if (uap->namelen > MAXLOGNAME)
85723359Sache		uap->namelen = MAXLOGNAME;
8581541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
8591541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
8601541Srgrimes}
8611541Srgrimes
8621541Srgrimes/*
8631541Srgrimes * Set login name.
8641541Srgrimes */
86512221Sbde#ifndef _SYS_SYSPROTO_H_
8661541Srgrimesstruct setlogin_args {
8671541Srgrimes	char	*namebuf;
8681541Srgrimes};
86912221Sbde#endif
8701541Srgrimes/* ARGSUSED */
8711549Srgrimesint
87230994Sphksetlogin(p, uap)
8731541Srgrimes	struct proc *p;
8741541Srgrimes	struct setlogin_args *uap;
8751541Srgrimes{
8761541Srgrimes	int error;
87723330Sache	char logintmp[MAXLOGNAME];
8781541Srgrimes
8793098Sphk	if ((error = suser(p->p_ucred, &p->p_acflag)))
8801541Srgrimes		return (error);
88122522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
88236845Sdfr	    sizeof(logintmp), (size_t *)0);
8831541Srgrimes	if (error == ENAMETOOLONG)
8841541Srgrimes		error = EINVAL;
88522522Sdavidn	else if (!error)
88622522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
88723330Sache		    sizeof(logintmp));
8881541Srgrimes	return (error);
8891541Srgrimes}
89031891Ssef
89131891Ssefvoid
89231891Ssefsetsugid(p)
89331891Ssef     struct proc *p;
89431891Ssef{
89531891Ssef	p->p_flag |= P_SUGID;
89631891Ssef	if (!(p->p_pfsflags & PF_ISUGID))
89731891Ssef		p->p_stops = 0;
89831891Ssef}
899