kern_prot.c revision 24450
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
3924450Speter * $Id: kern_prot.c,v 1.29 1997/03/31 13:41:49 peter Exp $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
461541Srgrimes#include <sys/param.h>
471541Srgrimes#include <sys/acct.h>
481541Srgrimes#include <sys/systm.h>
4912221Sbde#include <sys/sysproto.h>
501541Srgrimes#include <sys/ucred.h>
511541Srgrimes#include <sys/proc.h>
521541Srgrimes#include <sys/timeb.h>
531541Srgrimes#include <sys/times.h>
541541Srgrimes#include <sys/malloc.h>
5518013Sbde#include <sys/unistd.h>
561541Srgrimes
5712221Sbde#ifndef _SYS_SYSPROTO_H_
5811332Sswallacestruct getpid_args {
591541Srgrimes	int	dummy;
601541Srgrimes};
6112221Sbde#endif
621541Srgrimes
631541Srgrimes/* ARGSUSED */
641549Srgrimesint
651541Srgrimesgetpid(p, uap, retval)
661541Srgrimes	struct proc *p;
6711332Sswallace	struct getpid_args *uap;
681541Srgrimes	int *retval;
691541Srgrimes{
701541Srgrimes
711541Srgrimes	*retval = p->p_pid;
721541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
731541Srgrimes	retval[1] = p->p_pptr->p_pid;
741541Srgrimes#endif
751541Srgrimes	return (0);
761541Srgrimes}
771541Srgrimes
7812221Sbde#ifndef _SYS_SYSPROTO_H_
7911332Sswallacestruct getppid_args {
8011332Sswallace        int     dummy;
8111332Sswallace};
8212221Sbde#endif
831541Srgrimes/* ARGSUSED */
841549Srgrimesint
851541Srgrimesgetppid(p, uap, retval)
861541Srgrimes	struct proc *p;
8711332Sswallace	struct getppid_args *uap;
881541Srgrimes	int *retval;
891541Srgrimes{
901541Srgrimes
911541Srgrimes	*retval = 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
1031541Srgrimesgetpgrp(p, uap, retval)
1041541Srgrimes	struct proc *p;
10511332Sswallace	struct getpgrp_args *uap;
1061541Srgrimes	int *retval;
1071541Srgrimes{
1081541Srgrimes
1091541Srgrimes	*retval = p->p_pgrp->pg_id;
1101541Srgrimes	return (0);
1111541Srgrimes}
1121541Srgrimes
11312221Sbde#ifndef _SYS_SYSPROTO_H_
11411332Sswallacestruct getuid_args {
11511332Sswallace        int     dummy;
11611332Sswallace};
11712221Sbde#endif
11811332Sswallace
1191541Srgrimes/* ARGSUSED */
1201549Srgrimesint
1211541Srgrimesgetuid(p, uap, retval)
1221541Srgrimes	struct proc *p;
12311332Sswallace	struct getuid_args *uap;
1241541Srgrimes	int *retval;
1251541Srgrimes{
1261541Srgrimes
1271541Srgrimes	*retval = p->p_cred->p_ruid;
1281541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1291541Srgrimes	retval[1] = p->p_ucred->cr_uid;
1301541Srgrimes#endif
1311541Srgrimes	return (0);
1321541Srgrimes}
1331541Srgrimes
13412221Sbde#ifndef _SYS_SYSPROTO_H_
13511332Sswallacestruct geteuid_args {
13611332Sswallace        int     dummy;
13711332Sswallace};
13812221Sbde#endif
13911332Sswallace
1401541Srgrimes/* ARGSUSED */
1411549Srgrimesint
1421541Srgrimesgeteuid(p, uap, retval)
1431541Srgrimes	struct proc *p;
14411332Sswallace	struct geteuid_args *uap;
1451541Srgrimes	int *retval;
1461541Srgrimes{
1471541Srgrimes
1481541Srgrimes	*retval = p->p_ucred->cr_uid;
1491541Srgrimes	return (0);
1501541Srgrimes}
1511541Srgrimes
15212221Sbde#ifndef _SYS_SYSPROTO_H_
15311332Sswallacestruct getgid_args {
15411332Sswallace        int     dummy;
15511332Sswallace};
15612221Sbde#endif
15711332Sswallace
1581541Srgrimes/* ARGSUSED */
1591549Srgrimesint
1601541Srgrimesgetgid(p, uap, retval)
1611541Srgrimes	struct proc *p;
16211332Sswallace	struct getgid_args *uap;
1631541Srgrimes	int *retval;
1641541Srgrimes{
1651541Srgrimes
1661541Srgrimes	*retval = p->p_cred->p_rgid;
1671541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1681541Srgrimes	retval[1] = p->p_ucred->cr_groups[0];
1691541Srgrimes#endif
1701541Srgrimes	return (0);
1711541Srgrimes}
1721541Srgrimes
1731541Srgrimes/*
1741541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
1751541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
1761541Srgrimes * correctly in a library function.
1771541Srgrimes */
17812221Sbde#ifndef _SYS_SYSPROTO_H_
17911332Sswallacestruct getegid_args {
18011332Sswallace        int     dummy;
18111332Sswallace};
18212221Sbde#endif
18311332Sswallace
1841541Srgrimes/* ARGSUSED */
1851549Srgrimesint
1861541Srgrimesgetegid(p, uap, retval)
1871541Srgrimes	struct proc *p;
18811332Sswallace	struct getegid_args *uap;
1891541Srgrimes	int *retval;
1901541Srgrimes{
1911541Srgrimes
1921541Srgrimes	*retval = p->p_ucred->cr_groups[0];
1931541Srgrimes	return (0);
1941541Srgrimes}
1951541Srgrimes
19612221Sbde#ifndef _SYS_SYSPROTO_H_
1971541Srgrimesstruct getgroups_args {
1981541Srgrimes	u_int	gidsetsize;
1991541Srgrimes	gid_t	*gidset;
2001541Srgrimes};
20112221Sbde#endif
2021549Srgrimesint
2031541Srgrimesgetgroups(p, uap, retval)
2041541Srgrimes	struct proc *p;
2051541Srgrimes	register struct	getgroups_args *uap;
2061541Srgrimes	int *retval;
2071541Srgrimes{
2081541Srgrimes	register struct pcred *pc = p->p_cred;
2091541Srgrimes	register u_int ngrp;
2101541Srgrimes	int error;
2111541Srgrimes
2121541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
2131541Srgrimes		*retval = pc->pc_ucred->cr_ngroups;
2141541Srgrimes		return (0);
2151541Srgrimes	}
2161541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2171541Srgrimes		return (EINVAL);
2181541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2193098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2203098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2211541Srgrimes		return (error);
2221541Srgrimes	*retval = ngrp;
2231541Srgrimes	return (0);
2241541Srgrimes}
2251541Srgrimes
22612221Sbde#ifndef _SYS_SYSPROTO_H_
22712207Sbdestruct setsid_args {
22811332Sswallace        int     dummy;
22911332Sswallace};
23012221Sbde#endif
23111332Sswallace
2321541Srgrimes/* ARGSUSED */
2331549Srgrimesint
2341541Srgrimessetsid(p, uap, retval)
2351541Srgrimes	register struct proc *p;
23612207Sbde	struct setsid_args *uap;
2371541Srgrimes	int *retval;
2381541Srgrimes{
2391541Srgrimes
2401541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
2411541Srgrimes		return (EPERM);
2421541Srgrimes	} else {
2431541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
2441541Srgrimes		*retval = p->p_pid;
2451541Srgrimes		return (0);
2461541Srgrimes	}
2471541Srgrimes}
2481541Srgrimes
2491541Srgrimes/*
2501541Srgrimes * set process group (setpgid/old setpgrp)
2511541Srgrimes *
2521541Srgrimes * caller does setpgid(targpid, targpgid)
2531541Srgrimes *
2541541Srgrimes * pid must be caller or child of caller (ESRCH)
2551541Srgrimes * if a child
2561541Srgrimes *	pid must be in same session (EPERM)
2571541Srgrimes *	pid can't have done an exec (EACCES)
2581541Srgrimes * if pgid != pid
2591541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
2601541Srgrimes * pid must not be session leader (EPERM)
2611541Srgrimes */
26212221Sbde#ifndef _SYS_SYSPROTO_H_
2631541Srgrimesstruct setpgid_args {
2641541Srgrimes	int	pid;	/* target process id */
2651541Srgrimes	int	pgid;	/* target pgrp id */
2661541Srgrimes};
26712221Sbde#endif
2681541Srgrimes/* ARGSUSED */
2691549Srgrimesint
2701541Srgrimessetpgid(curp, uap, retval)
2711541Srgrimes	struct proc *curp;
2721541Srgrimes	register struct setpgid_args *uap;
2731541Srgrimes	int *retval;
2741541Srgrimes{
2751541Srgrimes	register struct proc *targp;		/* target process */
2761541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
2771541Srgrimes
27820677Sbde	if (uap->pgid < 0)
27920677Sbde		return (EINVAL);
2801541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
2811541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
2821541Srgrimes			return (ESRCH);
28315985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
2841541Srgrimes			return (EPERM);
2851541Srgrimes		if (targp->p_flag & P_EXEC)
2861541Srgrimes			return (EACCES);
2871541Srgrimes	} else
2881541Srgrimes		targp = curp;
2891541Srgrimes	if (SESS_LEADER(targp))
2901541Srgrimes		return (EPERM);
2911541Srgrimes	if (uap->pgid == 0)
2921541Srgrimes		uap->pgid = targp->p_pid;
2931541Srgrimes	else if (uap->pgid != targp->p_pid)
2941541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
2951541Srgrimes	            pgrp->pg_session != curp->p_session)
2961541Srgrimes			return (EPERM);
2971541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
2981541Srgrimes}
2991541Srgrimes
30024448Speter/*
30124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
30224448Speter * compatable.  It says that setting the uid/gid to euid/egid is a special
30324448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
30424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
30524448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
30624448Speter * does not set the saved id - this is dangerous for traditional BSD
30724448Speter * programs.  For this reason, we *really* do not want to set
30824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
30924448Speter */
31024448Speter#define POSIX_APPENDIX_B_4_2_2
31124448Speter
31212221Sbde#ifndef _SYS_SYSPROTO_H_
3131541Srgrimesstruct setuid_args {
3141541Srgrimes	uid_t	uid;
3151541Srgrimes};
31612221Sbde#endif
3171541Srgrimes/* ARGSUSED */
3181549Srgrimesint
3191541Srgrimessetuid(p, uap, retval)
3201541Srgrimes	struct proc *p;
3211541Srgrimes	struct setuid_args *uap;
3221541Srgrimes	int *retval;
3231541Srgrimes{
3241541Srgrimes	register struct pcred *pc = p->p_cred;
3251541Srgrimes	register uid_t uid;
3261541Srgrimes	int error;
3271541Srgrimes
32824448Speter	/*
32924448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
33024448Speter	 *
33124448Speter	 * Note that setuid(geteuid()) is a special case of
33224448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
33324448Speter	 * to use this clause to be compatable with traditional BSD
33424448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
33524448Speter	 * three id's (assuming you have privs).
33624448Speter	 *
33724448Speter	 * Notes on the logic.  We do things in three steps.
33824448Speter	 * 1: We determine if the euid is going to change, and do EPERM
33924448Speter	 *    right away.  We unconditionally change the euid later if this
34024448Speter	 *    test is satisfied, simplifying that part of the logic.
34124448Speter	 * 2: We determine if the real and/or saved uid's are going to
34224448Speter	 *    change.  Determined by compile options.
34324448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
34424448Speter	 */
3451541Srgrimes	uid = uap->uid;
34624448Speter	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
34717994Sache#ifdef _POSIX_SAVED_IDS
34824448Speter	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
34917994Sache#endif
35024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
35124448Speter	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
35224448Speter#endif
3538162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
3541541Srgrimes		return (error);
35524448Speter
35624448Speter#ifdef _POSIX_SAVED_IDS
3571541Srgrimes	/*
35824448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
35924448Speter	 * If so, we are changing the real uid and/or saved uid.
3601541Srgrimes	 */
36117994Sache	if (
36224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
36324448Speter	    uid == pc->pc_ucred->cr_uid ||
36417994Sache#endif
36524448Speter	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
36617994Sache#endif
36724448Speter	{
36824448Speter		/*
36924448Speter		 * Transfer proc count to new user.
37024448Speter		 */
37124448Speter		if (uid != pc->p_ruid) {
37224448Speter			(void)chgproccnt(pc->p_ruid, -1);
37324448Speter			(void)chgproccnt(uid, 1);
37424448Speter		}
37524448Speter		/*
37624448Speter		 * Set real uid
37724448Speter		 */
37824448Speter		if (uid != pc->p_ruid) {
37924448Speter			p->p_flag |= P_SUGID;
38024448Speter			pc->p_ruid = uid;
38124448Speter		}
38224448Speter		/*
38324448Speter		 * Set saved uid
38424448Speter		 *
38524448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
38624448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
38724448Speter		 * is important that we should do this.
38824448Speter		 */
38924448Speter		if (pc->p_svuid != uid) {
39024448Speter			p->p_flag |= P_SUGID;
39124448Speter			pc->p_svuid = uid;
39224448Speter		}
3938141Sache	}
39424448Speter
39524448Speter	/*
39624448Speter	 * In all permitted cases, we are changing the euid.
39724448Speter	 * Copy credentials so other references do not see our changes.
39824448Speter	 */
39924448Speter	if (pc->pc_ucred->cr_uid != uid) {
40024448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
40124448Speter		pc->pc_ucred->cr_uid = uid;
40224448Speter		p->p_flag |= P_SUGID;
40324448Speter	}
4041541Srgrimes	return (0);
4051541Srgrimes}
4061541Srgrimes
40712221Sbde#ifndef _SYS_SYSPROTO_H_
4081541Srgrimesstruct seteuid_args {
4091541Srgrimes	uid_t	euid;
4101541Srgrimes};
41112221Sbde#endif
4121541Srgrimes/* ARGSUSED */
4131549Srgrimesint
4141541Srgrimesseteuid(p, uap, retval)
4151541Srgrimes	struct proc *p;
4161541Srgrimes	struct seteuid_args *uap;
4171541Srgrimes	int *retval;
4181541Srgrimes{
4191541Srgrimes	register struct pcred *pc = p->p_cred;
4201541Srgrimes	register uid_t euid;
4211541Srgrimes	int error;
4221541Srgrimes
4231541Srgrimes	euid = uap->euid;
42424449Speter	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
42524449Speter	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
4261541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4271541Srgrimes		return (error);
4281541Srgrimes	/*
4291541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
4301541Srgrimes	 * not see our changes.
4311541Srgrimes	 */
43224449Speter	if (pc->pc_ucred->cr_uid != euid) {
43324449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
43424449Speter		pc->pc_ucred->cr_uid = euid;
43524449Speter		p->p_flag |= P_SUGID;
43624449Speter	}
4371541Srgrimes	return (0);
4381541Srgrimes}
4391541Srgrimes
44012221Sbde#ifndef _SYS_SYSPROTO_H_
4411541Srgrimesstruct setgid_args {
4421541Srgrimes	gid_t	gid;
4431541Srgrimes};
44412221Sbde#endif
4451541Srgrimes/* ARGSUSED */
4461549Srgrimesint
4471541Srgrimessetgid(p, uap, retval)
4481541Srgrimes	struct proc *p;
4491541Srgrimes	struct setgid_args *uap;
4501541Srgrimes	int *retval;
4511541Srgrimes{
4521541Srgrimes	register struct pcred *pc = p->p_cred;
4531541Srgrimes	register gid_t gid;
4541541Srgrimes	int error;
4551541Srgrimes
45624448Speter	/*
45724448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
45824448Speter	 *
45924448Speter	 * Note that setgid(getegid()) is a special case of
46024448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
46124448Speter	 * to use this clause to be compatable with traditional BSD
46224448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
46324448Speter	 * three id's (assuming you have privs).
46424448Speter	 *
46524448Speter	 * For notes on the logic here, see setuid() above.
46624448Speter	 */
4671541Srgrimes	gid = uap->gid;
46824448Speter	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
46917994Sache#ifdef _POSIX_SAVED_IDS
47024448Speter	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
47117994Sache#endif
47224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
47324448Speter	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
47424448Speter#endif
4758162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4761541Srgrimes		return (error);
47724448Speter
47817994Sache#ifdef _POSIX_SAVED_IDS
47924448Speter	/*
48024448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
48124448Speter	 * If so, we are changing the real uid and saved gid.
48224448Speter	 */
48324448Speter	if (
48424448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
48524448Speter	    gid == pc->pc_ucred->cr_groups[0] ||
48617994Sache#endif
48724448Speter	    suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */
48824448Speter#endif
48924448Speter	{
49024448Speter		/*
49124448Speter		 * Set real gid
49224448Speter		 */
49324448Speter		if (pc->p_rgid != gid) {
49424448Speter			p->p_flag |= P_SUGID;
49524448Speter			pc->p_rgid = gid;
49624448Speter		}
49724448Speter		/*
49824448Speter		 * Set saved gid
49924448Speter		 *
50024448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
50124448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
50224448Speter		 * is important that we should do this.
50324448Speter		 */
50424448Speter		if (pc->p_svgid != gid) {
50524448Speter			p->p_flag |= P_SUGID;
50624448Speter			pc->p_svgid = gid;
50724448Speter		}
5088141Sache	}
50924448Speter	/*
51024448Speter	 * In all cases permitted cases, we are changing the egid.
51124448Speter	 * Copy credentials so other references do not see our changes.
51224448Speter	 */
51324448Speter	if (pc->pc_ucred->cr_groups[0] != gid) {
51424448Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
51524448Speter		pc->pc_ucred->cr_groups[0] = gid;
51624448Speter		p->p_flag |= P_SUGID;
51724448Speter	}
5181541Srgrimes	return (0);
5191541Srgrimes}
5201541Srgrimes
52112221Sbde#ifndef _SYS_SYSPROTO_H_
5221541Srgrimesstruct setegid_args {
5231541Srgrimes	gid_t	egid;
5241541Srgrimes};
52512221Sbde#endif
5261541Srgrimes/* ARGSUSED */
5271549Srgrimesint
5281541Srgrimessetegid(p, uap, retval)
5291541Srgrimes	struct proc *p;
5301541Srgrimes	struct setegid_args *uap;
5311541Srgrimes	int *retval;
5321541Srgrimes{
5331541Srgrimes	register struct pcred *pc = p->p_cred;
5341541Srgrimes	register gid_t egid;
5351541Srgrimes	int error;
5361541Srgrimes
5371541Srgrimes	egid = uap->egid;
53824449Speter	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
53924449Speter	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
5401541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
5411541Srgrimes		return (error);
54224449Speter	if (pc->pc_ucred->cr_groups[0] != egid) {
54324449Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
54424449Speter		pc->pc_ucred->cr_groups[0] = egid;
54524449Speter		p->p_flag |= P_SUGID;
54624449Speter	}
5471541Srgrimes	return (0);
5481541Srgrimes}
5491541Srgrimes
55012221Sbde#ifndef _SYS_SYSPROTO_H_
5511541Srgrimesstruct setgroups_args {
5521541Srgrimes	u_int	gidsetsize;
5531541Srgrimes	gid_t	*gidset;
5541541Srgrimes};
55512221Sbde#endif
5561541Srgrimes/* ARGSUSED */
5571549Srgrimesint
5581541Srgrimessetgroups(p, uap, retval)
5591541Srgrimes	struct proc *p;
5601541Srgrimes	struct setgroups_args *uap;
5611541Srgrimes	int *retval;
5621541Srgrimes{
5631541Srgrimes	register struct pcred *pc = p->p_cred;
5641541Srgrimes	register u_int ngrp;
5651541Srgrimes	int error;
5661541Srgrimes
5673098Sphk	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
5681541Srgrimes		return (error);
56912063Sdg	ngrp = uap->gidsetsize;
57024447Speter	if (ngrp > NGROUPS)
5711541Srgrimes		return (EINVAL);
57224447Speter	/*
57324447Speter	 * XXX A little bit lazy here.  We could test if anything has
57424447Speter	 * changed before crcopy() and setting P_SUGID.
57524447Speter	 */
5761541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
57724447Speter	if (ngrp < 1) {
57824447Speter		/*
57924447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
58024447Speter		 * groups vector on non-BSD systems (which generally do not
58124447Speter		 * have the egid in the groups[0]).  We risk security holes
58224447Speter		 * when running non-BSD software if we do not do the same.
58324447Speter		 */
58424447Speter		pc->pc_ucred->cr_ngroups = 1;
58524447Speter	} else {
58624447Speter		if ((error = copyin((caddr_t)uap->gidset,
58724447Speter		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
58824447Speter			return (error);
58924447Speter		pc->pc_ucred->cr_ngroups = ngrp;
59024447Speter	}
5911541Srgrimes	p->p_flag |= P_SUGID;
5921541Srgrimes	return (0);
5931541Srgrimes}
5941541Srgrimes
59512221Sbde#ifndef _SYS_SYSPROTO_H_
5961541Srgrimesstruct setreuid_args {
5979238Sache	uid_t	ruid;
5989238Sache	uid_t	euid;
5991541Srgrimes};
60012221Sbde#endif
6011541Srgrimes/* ARGSUSED */
6021549Srgrimesint
6038019Sachesetreuid(p, uap, retval)
6041541Srgrimes	register struct proc *p;
6051541Srgrimes	struct setreuid_args *uap;
6061541Srgrimes	int *retval;
6071541Srgrimes{
6081541Srgrimes	register struct pcred *pc = p->p_cred;
6099238Sache	register uid_t ruid, euid;
6108135Sache	int error;
6111541Srgrimes
6129238Sache	ruid = uap->ruid;
6139238Sache	euid = uap->euid;
6149238Sache	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
6159238Sache	     euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) &&
6168135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
6178135Sache		return (error);
6189238Sache
61924450Speter	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
62024450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
6219238Sache		pc->pc_ucred->cr_uid = euid;
62224450Speter		p->p_flag |= P_SUGID;
62324450Speter	}
62424450Speter	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
6259238Sache		(void)chgproccnt(pc->p_ruid, -1);
6269238Sache		(void)chgproccnt(ruid, 1);
6279238Sache		pc->p_ruid = ruid;
62824450Speter		p->p_flag |= P_SUGID;
6298135Sache	}
63024450Speter	if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) {
6318111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
63224450Speter		p->p_flag |= P_SUGID;
63324450Speter	}
6348135Sache	return (0);
6351541Srgrimes}
6361541Srgrimes
63712221Sbde#ifndef _SYS_SYSPROTO_H_
6381541Srgrimesstruct setregid_args {
6399238Sache	gid_t	rgid;
6409238Sache	gid_t	egid;
6411541Srgrimes};
64212221Sbde#endif
6431541Srgrimes/* ARGSUSED */
6441549Srgrimesint
6458019Sachesetregid(p, uap, retval)
6461541Srgrimes	register struct proc *p;
6471541Srgrimes	struct setregid_args *uap;
6481541Srgrimes	int *retval;
6491541Srgrimes{
6501541Srgrimes	register struct pcred *pc = p->p_cred;
6519238Sache	register gid_t rgid, egid;
6528135Sache	int error;
6531541Srgrimes
6549238Sache	rgid = uap->rgid;
6559238Sache	egid = uap->egid;
6569238Sache	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
6579238Sache	     egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) &&
6588135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
6598135Sache		return (error);
6609238Sache
66124450Speter	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
66224450Speter		pc->pc_ucred = crcopy(pc->pc_ucred);
6639238Sache		pc->pc_ucred->cr_groups[0] = egid;
66424450Speter		p->p_flag |= P_SUGID;
66524450Speter	}
66624450Speter	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
6679238Sache		pc->p_rgid = rgid;
66824450Speter		p->p_flag |= P_SUGID;
66924450Speter	}
67024450Speter	if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) {
6718111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
67224450Speter		p->p_flag |= P_SUGID;
67324450Speter	}
6748135Sache	return (0);
6751541Srgrimes}
6761541Srgrimes
6771541Srgrimes/*
6781541Srgrimes * Check if gid is a member of the group set.
6791541Srgrimes */
6801549Srgrimesint
6811541Srgrimesgroupmember(gid, cred)
6821541Srgrimes	gid_t gid;
6831541Srgrimes	register struct ucred *cred;
6841541Srgrimes{
6851541Srgrimes	register gid_t *gp;
6861541Srgrimes	gid_t *egp;
6871541Srgrimes
6881541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
6891541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
6901541Srgrimes		if (*gp == gid)
6911541Srgrimes			return (1);
6921541Srgrimes	return (0);
6931541Srgrimes}
6941541Srgrimes
6951541Srgrimes/*
6961541Srgrimes * Test whether the specified credentials imply "super-user"
6971541Srgrimes * privilege; if so, and we have accounting info, set the flag
6981541Srgrimes * indicating use of super-powers.
6991541Srgrimes * Returns 0 or error.
7001541Srgrimes */
7011549Srgrimesint
7021541Srgrimessuser(cred, acflag)
7031541Srgrimes	struct ucred *cred;
7048011Sbde	u_short *acflag;
7051541Srgrimes{
7061541Srgrimes	if (cred->cr_uid == 0) {
7071541Srgrimes		if (acflag)
7081541Srgrimes			*acflag |= ASU;
7091541Srgrimes		return (0);
7101541Srgrimes	}
7111541Srgrimes	return (EPERM);
7121541Srgrimes}
7131541Srgrimes
7141541Srgrimes/*
7151541Srgrimes * Allocate a zeroed cred structure.
7161541Srgrimes */
7171541Srgrimesstruct ucred *
7181541Srgrimescrget()
7191541Srgrimes{
7201541Srgrimes	register struct ucred *cr;
7211541Srgrimes
7221541Srgrimes	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
7231541Srgrimes	bzero((caddr_t)cr, sizeof(*cr));
7241541Srgrimes	cr->cr_ref = 1;
7251541Srgrimes	return (cr);
7261541Srgrimes}
7271541Srgrimes
7281541Srgrimes/*
7291541Srgrimes * Free a cred structure.
7301541Srgrimes * Throws away space when ref count gets to 0.
7311541Srgrimes */
7321549Srgrimesvoid
7331541Srgrimescrfree(cr)
7341541Srgrimes	struct ucred *cr;
7351541Srgrimes{
7361541Srgrimes	int s;
7371541Srgrimes
7381541Srgrimes	s = splimp();				/* ??? */
7391541Srgrimes	if (--cr->cr_ref == 0)
7401541Srgrimes		FREE((caddr_t)cr, M_CRED);
7411541Srgrimes	(void) splx(s);
7421541Srgrimes}
7431541Srgrimes
7441541Srgrimes/*
7451541Srgrimes * Copy cred structure to a new one and free the old one.
7461541Srgrimes */
7471541Srgrimesstruct ucred *
7481541Srgrimescrcopy(cr)
7491541Srgrimes	struct ucred *cr;
7501541Srgrimes{
7511541Srgrimes	struct ucred *newcr;
7521541Srgrimes
7531541Srgrimes	if (cr->cr_ref == 1)
7541541Srgrimes		return (cr);
7551541Srgrimes	newcr = crget();
7561541Srgrimes	*newcr = *cr;
7571541Srgrimes	crfree(cr);
7581541Srgrimes	newcr->cr_ref = 1;
7591541Srgrimes	return (newcr);
7601541Srgrimes}
7611541Srgrimes
7621541Srgrimes/*
7631541Srgrimes * Dup cred struct to a new held one.
7641541Srgrimes */
7651541Srgrimesstruct ucred *
7661541Srgrimescrdup(cr)
7671541Srgrimes	struct ucred *cr;
7681541Srgrimes{
7691541Srgrimes	struct ucred *newcr;
7701541Srgrimes
7711541Srgrimes	newcr = crget();
7721541Srgrimes	*newcr = *cr;
7731541Srgrimes	newcr->cr_ref = 1;
7741541Srgrimes	return (newcr);
7751541Srgrimes}
7761541Srgrimes
7771541Srgrimes/*
7781541Srgrimes * Get login name, if available.
7791541Srgrimes */
78012221Sbde#ifndef _SYS_SYSPROTO_H_
7811541Srgrimesstruct getlogin_args {
7821541Srgrimes	char	*namebuf;
7831541Srgrimes	u_int	namelen;
7841541Srgrimes};
78512221Sbde#endif
7861541Srgrimes/* ARGSUSED */
7871549Srgrimesint
7881541Srgrimesgetlogin(p, uap, retval)
7891541Srgrimes	struct proc *p;
7901541Srgrimes	struct getlogin_args *uap;
7911541Srgrimes	int *retval;
7921541Srgrimes{
7931541Srgrimes
79423358Sache	if (uap->namelen > MAXLOGNAME)
79523359Sache		uap->namelen = MAXLOGNAME;
7961541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
7971541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
7981541Srgrimes}
7991541Srgrimes
8001541Srgrimes/*
8011541Srgrimes * Set login name.
8021541Srgrimes */
80312221Sbde#ifndef _SYS_SYSPROTO_H_
8041541Srgrimesstruct setlogin_args {
8051541Srgrimes	char	*namebuf;
8061541Srgrimes};
80712221Sbde#endif
8081541Srgrimes/* ARGSUSED */
8091549Srgrimesint
8101541Srgrimessetlogin(p, uap, retval)
8111541Srgrimes	struct proc *p;
8121541Srgrimes	struct setlogin_args *uap;
8131541Srgrimes	int *retval;
8141541Srgrimes{
8151541Srgrimes	int error;
81623330Sache	char logintmp[MAXLOGNAME];
8171541Srgrimes
8183098Sphk	if ((error = suser(p->p_ucred, &p->p_acflag)))
8191541Srgrimes		return (error);
82022522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
82122522Sdavidn	    sizeof(logintmp), (u_int *)0);
8221541Srgrimes	if (error == ENAMETOOLONG)
8231541Srgrimes		error = EINVAL;
82422522Sdavidn	else if (!error)
82522522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
82623330Sache		    sizeof(logintmp));
8271541Srgrimes	return (error);
8281541Srgrimes}
829