kern_prot.c revision 31891
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
3931891Ssef * $Id: kern_prot.c,v 1.38 1997/12/16 17:40:16 eivind 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>
521541Srgrimes#include <sys/proc.h>
531541Srgrimes#include <sys/malloc.h>
5418013Sbde#include <sys/unistd.h>
5531891Ssef#include <sys/pioctl.h>
561541Srgrimes
5730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
5830354Sphk
5912221Sbde#ifndef _SYS_SYSPROTO_H_
6011332Sswallacestruct getpid_args {
611541Srgrimes	int	dummy;
621541Srgrimes};
6312221Sbde#endif
641541Srgrimes
651541Srgrimes/* ARGSUSED */
661549Srgrimesint
6730994Sphkgetpid(p, uap)
681541Srgrimes	struct proc *p;
6911332Sswallace	struct getpid_args *uap;
701541Srgrimes{
711541Srgrimes
7230994Sphk	p->p_retval[0] = p->p_pid;
731541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
7430994Sphk	p->p_retval[1] = p->p_pptr->p_pid;
751541Srgrimes#endif
761541Srgrimes	return (0);
771541Srgrimes}
781541Srgrimes
7912221Sbde#ifndef _SYS_SYSPROTO_H_
8011332Sswallacestruct getppid_args {
8111332Sswallace        int     dummy;
8211332Sswallace};
8312221Sbde#endif
841541Srgrimes/* ARGSUSED */
851549Srgrimesint
8630994Sphkgetppid(p, uap)
871541Srgrimes	struct proc *p;
8811332Sswallace	struct getppid_args *uap;
891541Srgrimes{
901541Srgrimes
9130994Sphk	p->p_retval[0] = p->p_pptr->p_pid;
921541Srgrimes	return (0);
931541Srgrimes}
941541Srgrimes
951541Srgrimes/* Get process group ID; note that POSIX getpgrp takes no parameter */
9612221Sbde#ifndef _SYS_SYSPROTO_H_
9711332Sswallacestruct getpgrp_args {
9811332Sswallace        int     dummy;
9911332Sswallace};
10012221Sbde#endif
10111332Sswallace
1021549Srgrimesint
10330994Sphkgetpgrp(p, uap)
1041541Srgrimes	struct proc *p;
10511332Sswallace	struct getpgrp_args *uap;
1061541Srgrimes{
1071541Srgrimes
10830994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
1091541Srgrimes	return (0);
1101541Srgrimes}
1111541Srgrimes
11228401Speter/* Get an arbitary pid's process group id */
11312221Sbde#ifndef _SYS_SYSPROTO_H_
11428401Speterstruct getpgid_args {
11528401Speter	pid_t	pid;
11628401Speter};
11728401Speter#endif
11828401Speter
11928401Speterint
12030994Sphkgetpgid(p, uap)
12128401Speter	struct proc *p;
12228401Speter	struct getpgid_args *uap;
12328401Speter{
12428401Speter	if (uap->pid == 0)
12528401Speter		goto found;
12628401Speter
12728401Speter	if ((p == pfind(uap->pid)) == 0)
12828401Speter		return ESRCH;
12928401Speterfound:
13030994Sphk	p->p_retval[0] = p->p_pgrp->pg_id;
13128401Speter	return 0;
13228401Speter}
13328401Speter
13428401Speter/*
13528401Speter * Get an arbitary pid's session id.
13628401Speter */
13728401Speter#ifndef _SYS_SYSPROTO_H_
13828401Speterstruct getsid_args {
13928401Speter	pid_t	pid;
14028401Speter};
14128401Speter#endif
14228401Speter
14328401Speterint
14430994Sphkgetsid(p, uap)
14528401Speter	struct proc *p;
14628401Speter	struct getsid_args *uap;
14728401Speter{
14828401Speter	if (uap->pid == 0)
14928401Speter		goto found;
15028401Speter
15128401Speter	if ((p == pfind(uap->pid)) == 0)
15228401Speter		return ESRCH;
15328401Speterfound:
15430994Sphk	p->p_retval[0] = p->p_pgrp->pg_session->s_leader->p_pid;
15528401Speter	return 0;
15628401Speter}
15728401Speter
15828401Speter
15928401Speter#ifndef _SYS_SYSPROTO_H_
16011332Sswallacestruct getuid_args {
16111332Sswallace        int     dummy;
16211332Sswallace};
16312221Sbde#endif
16411332Sswallace
1651541Srgrimes/* ARGSUSED */
1661549Srgrimesint
16730994Sphkgetuid(p, uap)
1681541Srgrimes	struct proc *p;
16911332Sswallace	struct getuid_args *uap;
1701541Srgrimes{
1711541Srgrimes
17230994Sphk	p->p_retval[0] = p->p_cred->p_ruid;
1731541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
17430994Sphk	p->p_retval[1] = p->p_ucred->cr_uid;
1751541Srgrimes#endif
1761541Srgrimes	return (0);
1771541Srgrimes}
1781541Srgrimes
17912221Sbde#ifndef _SYS_SYSPROTO_H_
18011332Sswallacestruct geteuid_args {
18111332Sswallace        int     dummy;
18211332Sswallace};
18312221Sbde#endif
18411332Sswallace
1851541Srgrimes/* ARGSUSED */
1861549Srgrimesint
18730994Sphkgeteuid(p, uap)
1881541Srgrimes	struct proc *p;
18911332Sswallace	struct geteuid_args *uap;
1901541Srgrimes{
1911541Srgrimes
19230994Sphk	p->p_retval[0] = p->p_ucred->cr_uid;
1931541Srgrimes	return (0);
1941541Srgrimes}
1951541Srgrimes
19612221Sbde#ifndef _SYS_SYSPROTO_H_
19711332Sswallacestruct getgid_args {
19811332Sswallace        int     dummy;
19911332Sswallace};
20012221Sbde#endif
20111332Sswallace
2021541Srgrimes/* ARGSUSED */
2031549Srgrimesint
20430994Sphkgetgid(p, uap)
2051541Srgrimes	struct proc *p;
20611332Sswallace	struct getgid_args *uap;
2071541Srgrimes{
2081541Srgrimes
20930994Sphk	p->p_retval[0] = p->p_cred->p_rgid;
2101541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
21130994Sphk	p->p_retval[1] = p->p_ucred->cr_groups[0];
2121541Srgrimes#endif
2131541Srgrimes	return (0);
2141541Srgrimes}
2151541Srgrimes
2161541Srgrimes/*
2171541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2181541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2191541Srgrimes * correctly in a library function.
2201541Srgrimes */
22112221Sbde#ifndef _SYS_SYSPROTO_H_
22211332Sswallacestruct getegid_args {
22311332Sswallace        int     dummy;
22411332Sswallace};
22512221Sbde#endif
22611332Sswallace
2271541Srgrimes/* ARGSUSED */
2281549Srgrimesint
22930994Sphkgetegid(p, uap)
2301541Srgrimes	struct proc *p;
23111332Sswallace	struct getegid_args *uap;
2321541Srgrimes{
2331541Srgrimes
23430994Sphk	p->p_retval[0] = p->p_ucred->cr_groups[0];
2351541Srgrimes	return (0);
2361541Srgrimes}
2371541Srgrimes
23812221Sbde#ifndef _SYS_SYSPROTO_H_
2391541Srgrimesstruct getgroups_args {
2401541Srgrimes	u_int	gidsetsize;
2411541Srgrimes	gid_t	*gidset;
2421541Srgrimes};
24312221Sbde#endif
2441549Srgrimesint
24530994Sphkgetgroups(p, uap)
2461541Srgrimes	struct proc *p;
2471541Srgrimes	register struct	getgroups_args *uap;
2481541Srgrimes{
2491541Srgrimes	register struct pcred *pc = p->p_cred;
2501541Srgrimes	register u_int ngrp;
2511541Srgrimes	int error;
2521541Srgrimes
2531541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
25430994Sphk		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
2551541Srgrimes		return (0);
2561541Srgrimes	}
2571541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2581541Srgrimes		return (EINVAL);
2591541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2603098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2613098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2621541Srgrimes		return (error);
26330994Sphk	p->p_retval[0] = ngrp;
2641541Srgrimes	return (0);
2651541Srgrimes}
2661541Srgrimes
26712221Sbde#ifndef _SYS_SYSPROTO_H_
26812207Sbdestruct setsid_args {
26911332Sswallace        int     dummy;
27011332Sswallace};
27112221Sbde#endif
27211332Sswallace
2731541Srgrimes/* ARGSUSED */
2741549Srgrimesint
27530994Sphksetsid(p, uap)
2761541Srgrimes	register struct proc *p;
27712207Sbde	struct setsid_args *uap;
2781541Srgrimes{
2791541Srgrimes
2801541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
2811541Srgrimes		return (EPERM);
2821541Srgrimes	} else {
2831541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
28430994Sphk		p->p_retval[0] = p->p_pid;
2851541Srgrimes		return (0);
2861541Srgrimes	}
2871541Srgrimes}
2881541Srgrimes
2891541Srgrimes/*
2901541Srgrimes * set process group (setpgid/old setpgrp)
2911541Srgrimes *
2921541Srgrimes * caller does setpgid(targpid, targpgid)
2931541Srgrimes *
2941541Srgrimes * pid must be caller or child of caller (ESRCH)
2951541Srgrimes * if a child
2961541Srgrimes *	pid must be in same session (EPERM)
2971541Srgrimes *	pid can't have done an exec (EACCES)
2981541Srgrimes * if pgid != pid
2991541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3001541Srgrimes * pid must not be session leader (EPERM)
3011541Srgrimes */
30212221Sbde#ifndef _SYS_SYSPROTO_H_
3031541Srgrimesstruct setpgid_args {
3041541Srgrimes	int	pid;	/* target process id */
3051541Srgrimes	int	pgid;	/* target pgrp id */
3061541Srgrimes};
30712221Sbde#endif
3081541Srgrimes/* ARGSUSED */
3091549Srgrimesint
31030994Sphksetpgid(curp, uap)
3111541Srgrimes	struct proc *curp;
3121541Srgrimes	register struct setpgid_args *uap;
3131541Srgrimes{
3141541Srgrimes	register struct proc *targp;		/* target process */
3151541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
3161541Srgrimes
31720677Sbde	if (uap->pgid < 0)
31820677Sbde		return (EINVAL);
3191541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
3201541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
3211541Srgrimes			return (ESRCH);
32215985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
3231541Srgrimes			return (EPERM);
3241541Srgrimes		if (targp->p_flag & P_EXEC)
3251541Srgrimes			return (EACCES);
3261541Srgrimes	} else
3271541Srgrimes		targp = curp;
3281541Srgrimes	if (SESS_LEADER(targp))
3291541Srgrimes		return (EPERM);
3301541Srgrimes	if (uap->pgid == 0)
3311541Srgrimes		uap->pgid = targp->p_pid;
3321541Srgrimes	else if (uap->pgid != targp->p_pid)
3331541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
3341541Srgrimes	            pgrp->pg_session != curp->p_session)
3351541Srgrimes			return (EPERM);
3361541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
3371541Srgrimes}
3381541Srgrimes
33924448Speter/*
34024448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
34124448Speter * compatable.  It says that setting the uid/gid to euid/egid is a special
34224448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
34324448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
34424448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
34524448Speter * does not set the saved id - this is dangerous for traditional BSD
34624448Speter * programs.  For this reason, we *really* do not want to set
34724448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
34824448Speter */
34924448Speter#define POSIX_APPENDIX_B_4_2_2
35024448Speter
35112221Sbde#ifndef _SYS_SYSPROTO_H_
3521541Srgrimesstruct setuid_args {
3531541Srgrimes	uid_t	uid;
3541541Srgrimes};
35512221Sbde#endif
3561541Srgrimes/* ARGSUSED */
3571549Srgrimesint
35830994Sphksetuid(p, uap)
3591541Srgrimes	struct proc *p;
3601541Srgrimes	struct setuid_args *uap;
3611541Srgrimes{
3621541Srgrimes	register struct pcred *pc = p->p_cred;
3631541Srgrimes	register uid_t uid;
3641541Srgrimes	int error;
3651541Srgrimes
36624448Speter	/*
36724448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
36824448Speter	 *
36924448Speter	 * Note that setuid(geteuid()) is a special case of
37024448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
37124448Speter	 * to use this clause to be compatable with traditional BSD
37224448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
37324448Speter	 * three id's (assuming you have privs).
37424448Speter	 *
37524448Speter	 * Notes on the logic.  We do things in three steps.
37624448Speter	 * 1: We determine if the euid is going to change, and do EPERM
37724448Speter	 *    right away.  We unconditionally change the euid later if this
37824448Speter	 *    test is satisfied, simplifying that part of the logic.
37924448Speter	 * 2: We determine if the real and/or saved uid's are going to
38024448Speter	 *    change.  Determined by compile options.
38124448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
38224448Speter	 */
3831541Srgrimes	uid = uap->uid;
38424448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
38517994Sache#ifdef _POSIX_SAVED_IDS
38624448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
38717994Sache#endif
38824448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
38924448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
39024448Speter#endif
3918162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
3921541Srgrimes		return (error);
39324448Speter
39424448Speter#ifdef _POSIX_SAVED_IDS
3951541Srgrimes	/*
39624448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
39724448Speter	 * If so, we are changing the real uid and/or saved uid.
3981541Srgrimes	 */
39917994Sache	if (
40024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
40124448Speter	    uid == pc->pc_ucred->cr_uid ||
40217994Sache#endif
40324448Speter	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
40417994Sache#endif
40524448Speter	{
40624448Speter		/*
40724448Speter		 * Transfer proc count to new user.
40824448Speter		 */
40924448Speter		if (uid != pc->p_ruid) {
41024448Speter			(void)chgproccnt(pc->p_ruid, -1);
41124448Speter			(void)chgproccnt(uid, 1);
41224448Speter		}
41324448Speter		/*
41424448Speter		 * Set real uid
41524448Speter		 */
41624448Speter		if (uid != pc->p_ruid) {
41724448Speter			pc->p_ruid = uid;
41831891Ssef			setsugid(p);
41924448Speter		}
42024448Speter		/*
42124448Speter		 * Set saved uid
42224448Speter		 *
42324448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
42424448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
42524448Speter		 * is important that we should do this.
42624448Speter		 */
42724448Speter		if (pc->p_svuid != uid) {
42824448Speter			pc->p_svuid = uid;
42931891Ssef			setsugid(p);
43024448Speter		}
4318141Sache	}
43224448Speter
43324448Speter	/*
43424448Speter	 * In all permitted cases, we are changing the euid.
43524448Speter	 * Copy credentials so other references do not see our changes.
43624448Speter	 */
43724448Speter	if (pc->pc_ucred->cr_uid != uid) {
43824448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
43924448Speter		pc->pc_ucred->cr_uid = uid;
44031891Ssef		setsugid(p);
44124448Speter	}
4421541Srgrimes	return (0);
4431541Srgrimes}
4441541Srgrimes
44512221Sbde#ifndef _SYS_SYSPROTO_H_
4461541Srgrimesstruct seteuid_args {
4471541Srgrimes	uid_t	euid;
4481541Srgrimes};
44912221Sbde#endif
4501541Srgrimes/* ARGSUSED */
4511549Srgrimesint
45230994Sphkseteuid(p, uap)
4531541Srgrimes	struct proc *p;
4541541Srgrimes	struct seteuid_args *uap;
4551541Srgrimes{
4561541Srgrimes	register struct pcred *pc = p->p_cred;
4571541Srgrimes	register uid_t euid;
4581541Srgrimes	int error;
4591541Srgrimes
4601541Srgrimes	euid = uap->euid;
46124449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
46224449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
4631541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4641541Srgrimes		return (error);
4651541Srgrimes	/*
4661541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4671541Srgrimes	 * not see our changes.
4681541Srgrimes	 */
46924449Speter	if (pc->pc_ucred->cr_uid != euid) {
47024449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
47124449Speter		pc->pc_ucred->cr_uid = euid;
47231891Ssef		setsugid(p);
47324449Speter	}
4741541Srgrimes	return (0);
4751541Srgrimes}
4761541Srgrimes
47712221Sbde#ifndef _SYS_SYSPROTO_H_
4781541Srgrimesstruct setgid_args {
4791541Srgrimes	gid_t	gid;
4801541Srgrimes};
48112221Sbde#endif
4821541Srgrimes/* ARGSUSED */
4831549Srgrimesint
48430994Sphksetgid(p, uap)
4851541Srgrimes	struct proc *p;
4861541Srgrimes	struct setgid_args *uap;
4871541Srgrimes{
4881541Srgrimes	register struct pcred *pc = p->p_cred;
4891541Srgrimes	register gid_t gid;
4901541Srgrimes	int error;
4911541Srgrimes
49224448Speter	/*
49324448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
49424448Speter	 *
49524448Speter	 * Note that setgid(getegid()) is a special case of
49624448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
49724448Speter	 * to use this clause to be compatable with traditional BSD
49824448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
49924448Speter	 * three id's (assuming you have privs).
50024448Speter	 *
50124448Speter	 * For notes on the logic here, see setuid() above.
50224448Speter	 */
5031541Srgrimes	gid = uap->gid;
50424448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
50517994Sache#ifdef _POSIX_SAVED_IDS
50624448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
50717994Sache#endif
50824448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
50924448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
51024448Speter#endif
5118162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
5121541Srgrimes		return (error);
51324448Speter
51417994Sache#ifdef _POSIX_SAVED_IDS
51524448Speter	/*
51624448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
51724448Speter	 * If so, we are changing the real uid and saved gid.
51824448Speter	 */
51924448Speter	if (
52024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
52124448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
52217994Sache#endif
52324448Speter	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
52424448Speter#endif
52524448Speter	{
52624448Speter		/*
52724448Speter		 * Set real gid
52824448Speter		 */
52924448Speter		if (pc->p_rgid != gid) {
53024448Speter			pc->p_rgid = gid;
53131891Ssef			setsugid(p);
53224448Speter		}
53324448Speter		/*
53424448Speter		 * Set saved gid
53524448Speter		 *
53624448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
53724448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
53824448Speter		 * is important that we should do this.
53924448Speter		 */
54024448Speter		if (pc->p_svgid != gid) {
54124448Speter			pc->p_svgid = gid;
54231891Ssef			setsugid(p);
54324448Speter		}
5448141Sache	}
54524448Speter	/*
54624448Speter	 * In all cases permitted cases, we are changing the egid.
54724448Speter	 * Copy credentials so other references do not see our changes.
54824448Speter	 */
54924448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
55024448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
55124448Speter		pc->pc_ucred->cr_groups[0] = gid;
55231891Ssef		setsugid(p);
55324448Speter	}
5541541Srgrimes	return (0);
5551541Srgrimes}
5561541Srgrimes
55712221Sbde#ifndef _SYS_SYSPROTO_H_
5581541Srgrimesstruct setegid_args {
5591541Srgrimes	gid_t	egid;
5601541Srgrimes};
56112221Sbde#endif
5621541Srgrimes/* ARGSUSED */
5631549Srgrimesint
56430994Sphksetegid(p, uap)
5651541Srgrimes	struct proc *p;
5661541Srgrimes	struct setegid_args *uap;
5671541Srgrimes{
5681541Srgrimes	register struct pcred *pc = p->p_cred;
5691541Srgrimes	register gid_t egid;
5701541Srgrimes	int error;
5711541Srgrimes
5721541Srgrimes	egid = uap->egid;
57324449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
57424449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
5751541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
5761541Srgrimes		return (error);
57724449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
57824449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
57924449Speter		pc->pc_ucred->cr_groups[0] = egid;
58031891Ssef		setsugid(p);
58124449Speter	}
5821541Srgrimes	return (0);
5831541Srgrimes}
5841541Srgrimes
58512221Sbde#ifndef _SYS_SYSPROTO_H_
5861541Srgrimesstruct setgroups_args {
5871541Srgrimes	u_int	gidsetsize;
5881541Srgrimes	gid_t	*gidset;
5891541Srgrimes};
59012221Sbde#endif
5911541Srgrimes/* ARGSUSED */
5921549Srgrimesint
59330994Sphksetgroups(p, uap)
5941541Srgrimes	struct proc *p;
5951541Srgrimes	struct setgroups_args *uap;
5961541Srgrimes{
5971541Srgrimes	register struct pcred *pc = p->p_cred;
5981541Srgrimes	register u_int ngrp;
5991541Srgrimes	int error;
6001541Srgrimes
6013098Sphk	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
6021541Srgrimes		return (error);
60312063Sdg	ngrp = uap->gidsetsize;
60424447Speter	if (ngrp > NGROUPS)
6051541Srgrimes		return (EINVAL);
60624447Speter	/*
60724447Speter	 * XXX A little bit lazy here.  We could test if anything has
60824447Speter	 * changed before crcopy() and setting P_SUGID.
60924447Speter	 */
6101541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
61124447Speter	if (ngrp < 1) {
61224447Speter		/*
61324447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
61424447Speter		 * groups vector on non-BSD systems (which generally do not
61524447Speter		 * have the egid in the groups[0]).  We risk security holes
61624447Speter		 * when running non-BSD software if we do not do the same.
61724447Speter		 */
61824447Speter		pc->pc_ucred->cr_ngroups = 1;
61924447Speter	} else {
62024447Speter		if ((error = copyin((caddr_t)uap->gidset,
62124447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
62224447Speter			return (error);
62324447Speter		pc->pc_ucred->cr_ngroups = ngrp;
62424447Speter	}
62531891Ssef	setsugid(p);
6261541Srgrimes	return (0);
6271541Srgrimes}
6281541Srgrimes
62912221Sbde#ifndef _SYS_SYSPROTO_H_
6301541Srgrimesstruct setreuid_args {
6319238Sache	uid_t	ruid;
6329238Sache	uid_t	euid;
6331541Srgrimes};
63412221Sbde#endif
6351541Srgrimes/* ARGSUSED */
6361549Srgrimesint
63730994Sphksetreuid(p, uap)
6381541Srgrimes	register struct proc *p;
6391541Srgrimes	struct setreuid_args *uap;
6401541Srgrimes{
6411541Srgrimes	register struct pcred *pc = p->p_cred;
6429238Sache	register uid_t ruid, euid;
6438135Sache	int error;
6441541Srgrimes
6459238Sache	ruid = uap->ruid;
6469238Sache	euid = uap->euid;
6479238Sache	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
64824559Speter	     euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
64924559Speter	     euid != pc->p_ruid && euid != pc->p_svuid) &&
6508135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
6518135Sache		return (error);
6529238Sache
65324450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
65424450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
6559238Sache		pc->pc_ucred->cr_uid = euid;
65631891Ssef		setsugid(p);
65724450Speter	}
65824450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
6599238Sache		(void)chgproccnt(pc->p_ruid, -1);
6609238Sache		(void)chgproccnt(ruid, 1);
6619238Sache		pc->p_ruid = ruid;
66231891Ssef		setsugid(p);
6638135Sache	}
66424559Speter	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
66524559Speter	    pc->p_svuid != pc->pc_ucred->cr_uid) {
6668111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
66731891Ssef		setsugid(p);
66824450Speter	}
6698135Sache	return (0);
6701541Srgrimes}
6711541Srgrimes
67212221Sbde#ifndef _SYS_SYSPROTO_H_
6731541Srgrimesstruct setregid_args {
6749238Sache	gid_t	rgid;
6759238Sache	gid_t	egid;
6761541Srgrimes};
67712221Sbde#endif
6781541Srgrimes/* ARGSUSED */
6791549Srgrimesint
68030994Sphksetregid(p, uap)
6811541Srgrimes	register struct proc *p;
6821541Srgrimes	struct setregid_args *uap;
6831541Srgrimes{
6841541Srgrimes	register struct pcred *pc = p->p_cred;
6859238Sache	register gid_t rgid, egid;
6868135Sache	int error;
6871541Srgrimes
6889238Sache	rgid = uap->rgid;
6899238Sache	egid = uap->egid;
6909238Sache	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
69124559Speter	     egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
69224559Speter	     egid != pc->p_rgid && egid != pc->p_svgid) &&
6938135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
6948135Sache		return (error);
6959238Sache
69624450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
69724450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
6989238Sache		pc->pc_ucred->cr_groups[0] = egid;
69931891Ssef		setsugid(p);
70024450Speter	}
70124450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
7029238Sache		pc->p_rgid = rgid;
70331891Ssef		setsugid(p);
70424450Speter	}
70524559Speter	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
70624559Speter	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
7078111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
70831891Ssef		setsugid(p);
70924450Speter	}
7108135Sache	return (0);
7111541Srgrimes}
7121541Srgrimes
71324453Speter#ifndef _SYS_SYSPROTO_H_
71424453Speterstruct issetugid_args {
71524453Speter	int dummy;
71624453Speter};
71724453Speter#endif
71824453Speter/* ARGSUSED */
71924453Speterint
72030994Sphkissetugid(p, uap)
72124453Speter	register struct proc *p;
72224453Speter	struct issetugid_args *uap;
72324453Speter{
72424453Speter	/*
72524453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
72624453Speter	 * we use P_SUGID because we consider changing the owners as
72724453Speter	 * "tainting" as well.
72824453Speter	 * This is significant for procs that start as root and "become"
72924453Speter	 * a user without an exec - programs cannot know *everything*
73024453Speter	 * that libc *might* have put in their data segment.
73124453Speter	 */
73224453Speter	if (p->p_flag & P_SUGID)
73324453Speter		return (1);
73424453Speter	return (0);
73524453Speter}
73624453Speter
7371541Srgrimes/*
7381541Srgrimes * Check if gid is a member of the group set.
7391541Srgrimes */
7401549Srgrimesint
7411541Srgrimesgroupmember(gid, cred)
7421541Srgrimes	gid_t gid;
7431541Srgrimes	register struct ucred *cred;
7441541Srgrimes{
7451541Srgrimes	register gid_t *gp;
7461541Srgrimes	gid_t *egp;
7471541Srgrimes
7481541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
7491541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
7501541Srgrimes		if (*gp == gid)
7511541Srgrimes			return (1);
7521541Srgrimes	return (0);
7531541Srgrimes}
7541541Srgrimes
7551541Srgrimes/*
7561541Srgrimes * Test whether the specified credentials imply "super-user"
7571541Srgrimes * privilege; if so, and we have accounting info, set the flag
7581541Srgrimes * indicating use of super-powers.
7591541Srgrimes * Returns 0 or error.
7601541Srgrimes */
7611549Srgrimesint
7621541Srgrimessuser(cred, acflag)
7631541Srgrimes	struct ucred *cred;
7648011Sbde	u_short *acflag;
7651541Srgrimes{
7661541Srgrimes	if (cred->cr_uid == 0) {
7671541Srgrimes		if (acflag)
7681541Srgrimes			*acflag |= ASU;
7691541Srgrimes		return (0);
7701541Srgrimes	}
7711541Srgrimes	return (EPERM);
7721541Srgrimes}
7731541Srgrimes
7741541Srgrimes/*
7751541Srgrimes * Allocate a zeroed cred structure.
7761541Srgrimes */
7771541Srgrimesstruct ucred *
7781541Srgrimescrget()
7791541Srgrimes{
7801541Srgrimes	register struct ucred *cr;
7811541Srgrimes
7821541Srgrimes	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
7831541Srgrimes	bzero((caddr_t)cr, sizeof(*cr));
7841541Srgrimes	cr->cr_ref = 1;
7851541Srgrimes	return (cr);
7861541Srgrimes}
7871541Srgrimes
7881541Srgrimes/*
7891541Srgrimes * Free a cred structure.
7901541Srgrimes * Throws away space when ref count gets to 0.
7911541Srgrimes */
7921549Srgrimesvoid
7931541Srgrimescrfree(cr)
7941541Srgrimes	struct ucred *cr;
7951541Srgrimes{
7961541Srgrimes	if (--cr->cr_ref == 0)
7971541Srgrimes		FREE((caddr_t)cr, M_CRED);
7981541Srgrimes}
7991541Srgrimes
8001541Srgrimes/*
8011541Srgrimes * Copy cred structure to a new one and free the old one.
8021541Srgrimes */
8031541Srgrimesstruct ucred *
8041541Srgrimescrcopy(cr)
8051541Srgrimes	struct ucred *cr;
8061541Srgrimes{
8071541Srgrimes	struct ucred *newcr;
8081541Srgrimes
8091541Srgrimes	if (cr->cr_ref == 1)
8101541Srgrimes		return (cr);
8111541Srgrimes	newcr = crget();
8121541Srgrimes	*newcr = *cr;
8131541Srgrimes	crfree(cr);
8141541Srgrimes	newcr->cr_ref = 1;
8151541Srgrimes	return (newcr);
8161541Srgrimes}
8171541Srgrimes
8181541Srgrimes/*
8191541Srgrimes * Dup cred struct to a new held one.
8201541Srgrimes */
8211541Srgrimesstruct ucred *
8221541Srgrimescrdup(cr)
8231541Srgrimes	struct ucred *cr;
8241541Srgrimes{
8251541Srgrimes	struct ucred *newcr;
8261541Srgrimes
8271541Srgrimes	newcr = crget();
8281541Srgrimes	*newcr = *cr;
8291541Srgrimes	newcr->cr_ref = 1;
8301541Srgrimes	return (newcr);
8311541Srgrimes}
8321541Srgrimes
8331541Srgrimes/*
8341541Srgrimes * Get login name, if available.
8351541Srgrimes */
83612221Sbde#ifndef _SYS_SYSPROTO_H_
8371541Srgrimesstruct getlogin_args {
8381541Srgrimes	char	*namebuf;
8391541Srgrimes	u_int	namelen;
8401541Srgrimes};
84112221Sbde#endif
8421541Srgrimes/* ARGSUSED */
8431549Srgrimesint
84430994Sphkgetlogin(p, uap)
8451541Srgrimes	struct proc *p;
8461541Srgrimes	struct getlogin_args *uap;
8471541Srgrimes{
8481541Srgrimes
84923358Sache	if (uap->namelen > MAXLOGNAME)
85023359Sache		uap->namelen = MAXLOGNAME;
8511541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
8521541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
8531541Srgrimes}
8541541Srgrimes
8551541Srgrimes/*
8561541Srgrimes * Set login name.
8571541Srgrimes */
85812221Sbde#ifndef _SYS_SYSPROTO_H_
8591541Srgrimesstruct setlogin_args {
8601541Srgrimes	char	*namebuf;
8611541Srgrimes};
86212221Sbde#endif
8631541Srgrimes/* ARGSUSED */
8641549Srgrimesint
86530994Sphksetlogin(p, uap)
8661541Srgrimes	struct proc *p;
8671541Srgrimes	struct setlogin_args *uap;
8681541Srgrimes{
8691541Srgrimes	int error;
87023330Sache	char logintmp[MAXLOGNAME];
8711541Srgrimes
8723098Sphk	if ((error = suser(p->p_ucred, &p->p_acflag)))
8731541Srgrimes		return (error);
87422522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
87522522Sdavidn	    sizeof(logintmp), (u_int *)0);
8761541Srgrimes	if (error == ENAMETOOLONG)
8771541Srgrimes		error = EINVAL;
87822522Sdavidn	else if (!error)
87922522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
88023330Sache		    sizeof(logintmp));
8811541Srgrimes	return (error);
8821541Srgrimes}
88331891Ssef
88431891Ssefvoid
88531891Ssefsetsugid(p)
88631891Ssef     struct proc *p;
88731891Ssef{
88831891Ssef	p->p_flag |= P_SUGID;
88931891Ssef	if (!(p->p_pfsflags & PF_ISUGID))
89031891Ssef		p->p_stops = 0;
89131891Ssef}
892