kern_prot.c revision 170587
1139804Simp/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3165897Srwatson *	The Regents of the University of California.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
5165897Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson.
6165897Srwatson * All rights reserved.
7165897Srwatson *
81541Srgrimes * All or some portions of this file are derived from material licensed
91541Srgrimes * to the University of California by American Telephone and Telegraph
101541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
111541Srgrimes * the permission of UNIX System Laboratories, Inc.
121541Srgrimes *
131541Srgrimes * Redistribution and use in source and binary forms, with or without
141541Srgrimes * modification, are permitted provided that the following conditions
151541Srgrimes * are met:
161541Srgrimes * 1. Redistributions of source code must retain the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer.
181541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191541Srgrimes *    notice, this list of conditions and the following disclaimer in the
201541Srgrimes *    documentation and/or other materials provided with the distribution.
211541Srgrimes * 4. Neither the name of the University nor the names of its contributors
221541Srgrimes *    may be used to endorse or promote products derived from this software
231541Srgrimes *    without specific prior written permission.
241541Srgrimes *
251541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351541Srgrimes * SUCH DAMAGE.
361541Srgrimes *
371541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
381541Srgrimes */
391541Srgrimes
401541Srgrimes/*
411541Srgrimes * System calls related to processes and protection
421541Srgrimes */
431541Srgrimes
44116182Sobrien#include <sys/cdefs.h>
45116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_prot.c 170587 2007-06-12 00:12:01Z rwatson $");
46116182Sobrien
4731778Seivind#include "opt_compat.h"
48101001Srwatson#include "opt_mac.h"
4931778Seivind
501541Srgrimes#include <sys/param.h>
5176166Smarkm#include <sys/systm.h>
521541Srgrimes#include <sys/acct.h>
53132548Srwatson#include <sys/kdb.h>
5441059Speter#include <sys/kernel.h>
5570317Sjake#include <sys/lock.h>
5691140Stanimura#include <sys/malloc.h>
5776166Smarkm#include <sys/mutex.h>
58150634Sjhb#include <sys/refcount.h>
5991140Stanimura#include <sys/sx.h>
60164032Srwatson#include <sys/priv.h>
611541Srgrimes#include <sys/proc.h>
6276166Smarkm#include <sys/sysproto.h>
6387218Srwatson#include <sys/jail.h>
6431891Ssef#include <sys/pioctl.h>
6565495Struckman#include <sys/resourcevar.h>
6692976Srwatson#include <sys/socket.h>
6792976Srwatson#include <sys/socketvar.h>
68160139Sjhb#include <sys/syscallsubr.h>
6961287Srwatson#include <sys/sysctl.h>
701541Srgrimes
71155370Swsalamon#include <security/audit/audit.h>
72163606Srwatson#include <security/mac/mac_framework.h>
73155370Swsalamon
7430354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
7530354Sphk
76162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy");
7787138Srwatson
7812221Sbde#ifndef _SYS_SYSPROTO_H_
7911332Sswallacestruct getpid_args {
801541Srgrimes	int	dummy;
811541Srgrimes};
8212221Sbde#endif
831541Srgrimes/* ARGSUSED */
841549Srgrimesint
8593580Sjhbgetpid(struct thread *td, struct getpid_args *uap)
861541Srgrimes{
8783366Sjulian	struct proc *p = td->td_proc;
881541Srgrimes
8983366Sjulian	td->td_retval[0] = p->p_pid;
90130344Sphk#if defined(COMPAT_43)
9174728Sjhb	PROC_LOCK(p);
9283366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
9374728Sjhb	PROC_UNLOCK(p);
941541Srgrimes#endif
951541Srgrimes	return (0);
961541Srgrimes}
971541Srgrimes
9812221Sbde#ifndef _SYS_SYSPROTO_H_
9911332Sswallacestruct getppid_args {
10011332Sswallace        int     dummy;
10111332Sswallace};
10212221Sbde#endif
1031541Srgrimes/* ARGSUSED */
1041549Srgrimesint
10593580Sjhbgetppid(struct thread *td, struct getppid_args *uap)
1061541Srgrimes{
10783366Sjulian	struct proc *p = td->td_proc;
1081541Srgrimes
10974728Sjhb	PROC_LOCK(p);
11083366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
11174728Sjhb	PROC_UNLOCK(p);
1121541Srgrimes	return (0);
1131541Srgrimes}
1141541Srgrimes
11587466Srwatson/*
11687218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
11758717Sdillon */
11812221Sbde#ifndef _SYS_SYSPROTO_H_
11911332Sswallacestruct getpgrp_args {
12011332Sswallace        int     dummy;
12111332Sswallace};
12212221Sbde#endif
1231549Srgrimesint
12493580Sjhbgetpgrp(struct thread *td, struct getpgrp_args *uap)
1251541Srgrimes{
12683366Sjulian	struct proc *p = td->td_proc;
1271541Srgrimes
12891140Stanimura	PROC_LOCK(p);
12983366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
13091140Stanimura	PROC_UNLOCK(p);
1311541Srgrimes	return (0);
1321541Srgrimes}
1331541Srgrimes
13428401Speter/* Get an arbitary pid's process group id */
13512221Sbde#ifndef _SYS_SYSPROTO_H_
13628401Speterstruct getpgid_args {
13728401Speter	pid_t	pid;
13828401Speter};
13928401Speter#endif
14028401Speterint
14193580Sjhbgetpgid(struct thread *td, struct getpgid_args *uap)
14228401Speter{
143114031Sjhb	struct proc *p;
14492985Sjhb	int error;
14541726Struckman
14691140Stanimura	if (uap->pid == 0) {
147114031Sjhb		p = td->td_proc;
14891140Stanimura		PROC_LOCK(p);
149114031Sjhb	} else {
150114031Sjhb		p = pfind(uap->pid);
151114031Sjhb		if (p == NULL)
152114031Sjhb			return (ESRCH);
153114031Sjhb		error = p_cansee(td, p);
154114031Sjhb		if (error) {
155114031Sjhb			PROC_UNLOCK(p);
156114031Sjhb			return (error);
157114031Sjhb		}
15875893Sjhb	}
159114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
160114031Sjhb	PROC_UNLOCK(p);
161114031Sjhb	return (0);
16228401Speter}
16328401Speter
16428401Speter/*
16528401Speter * Get an arbitary pid's session id.
16628401Speter */
16728401Speter#ifndef _SYS_SYSPROTO_H_
16828401Speterstruct getsid_args {
16928401Speter	pid_t	pid;
17028401Speter};
17128401Speter#endif
17228401Speterint
17393580Sjhbgetsid(struct thread *td, struct getsid_args *uap)
17428401Speter{
175114031Sjhb	struct proc *p;
17687218Srwatson	int error;
17741726Struckman
17891140Stanimura	if (uap->pid == 0) {
179114031Sjhb		p = td->td_proc;
18091140Stanimura		PROC_LOCK(p);
181114031Sjhb	} else {
182114031Sjhb		p = pfind(uap->pid);
183114031Sjhb		if (p == NULL)
184114031Sjhb			return (ESRCH);
185114031Sjhb		error = p_cansee(td, p);
186114031Sjhb		if (error) {
187114031Sjhb			PROC_UNLOCK(p);
188114031Sjhb			return (error);
189114031Sjhb		}
19075893Sjhb	}
191114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
192114031Sjhb	PROC_UNLOCK(p);
193114031Sjhb	return (0);
19428401Speter}
19528401Speter
19628401Speter#ifndef _SYS_SYSPROTO_H_
19711332Sswallacestruct getuid_args {
19811332Sswallace        int     dummy;
19911332Sswallace};
20012221Sbde#endif
2011541Srgrimes/* ARGSUSED */
2021549Srgrimesint
20393580Sjhbgetuid(struct thread *td, struct getuid_args *uap)
2041541Srgrimes{
2051541Srgrimes
20692987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
207130344Sphk#if defined(COMPAT_43)
20892987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2091541Srgrimes#endif
2101541Srgrimes	return (0);
2111541Srgrimes}
2121541Srgrimes
21312221Sbde#ifndef _SYS_SYSPROTO_H_
21411332Sswallacestruct geteuid_args {
21511332Sswallace        int     dummy;
21611332Sswallace};
21712221Sbde#endif
2181541Srgrimes/* ARGSUSED */
2191549Srgrimesint
22093580Sjhbgeteuid(struct thread *td, struct geteuid_args *uap)
2211541Srgrimes{
22292987Sjhb
22392987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2241541Srgrimes	return (0);
2251541Srgrimes}
2261541Srgrimes
22712221Sbde#ifndef _SYS_SYSPROTO_H_
22811332Sswallacestruct getgid_args {
22911332Sswallace        int     dummy;
23011332Sswallace};
23112221Sbde#endif
2321541Srgrimes/* ARGSUSED */
2331549Srgrimesint
23493580Sjhbgetgid(struct thread *td, struct getgid_args *uap)
2351541Srgrimes{
2361541Srgrimes
23792987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
238130344Sphk#if defined(COMPAT_43)
23992987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2401541Srgrimes#endif
2411541Srgrimes	return (0);
2421541Srgrimes}
2431541Srgrimes
2441541Srgrimes/*
2451541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2461541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2471541Srgrimes * correctly in a library function.
2481541Srgrimes */
24912221Sbde#ifndef _SYS_SYSPROTO_H_
25011332Sswallacestruct getegid_args {
25111332Sswallace        int     dummy;
25211332Sswallace};
25312221Sbde#endif
2541541Srgrimes/* ARGSUSED */
2551549Srgrimesint
25693580Sjhbgetegid(struct thread *td, struct getegid_args *uap)
2571541Srgrimes{
2581541Srgrimes
25992987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2601541Srgrimes	return (0);
2611541Srgrimes}
2621541Srgrimes
26312221Sbde#ifndef _SYS_SYSPROTO_H_
2641541Srgrimesstruct getgroups_args {
2651541Srgrimes	u_int	gidsetsize;
2661541Srgrimes	gid_t	*gidset;
2671541Srgrimes};
26812221Sbde#endif
2691549Srgrimesint
27093580Sjhbgetgroups(struct thread *td, register struct getgroups_args *uap)
2711541Srgrimes{
272160139Sjhb	gid_t groups[NGROUPS];
27377183Srwatson	u_int ngrp;
27487218Srwatson	int error;
2751541Srgrimes
276160139Sjhb	ngrp = MIN(uap->gidsetsize, NGROUPS);
277160139Sjhb	error = kern_getgroups(td, &ngrp, groups);
278160139Sjhb	if (error)
279160139Sjhb		return (error);
280160139Sjhb	if (uap->gidsetsize > 0)
281160139Sjhb		error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t));
282160139Sjhb	if (error == 0)
283160139Sjhb		td->td_retval[0] = ngrp;
284160139Sjhb	return (error);
285160139Sjhb}
286160139Sjhb
287160139Sjhbint
288160139Sjhbkern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups)
289160139Sjhb{
290160139Sjhb	struct ucred *cred;
291160139Sjhb
29292987Sjhb	cred = td->td_ucred;
293160139Sjhb	if (*ngrp == 0) {
294160139Sjhb		*ngrp = cred->cr_ngroups;
29592987Sjhb		return (0);
2961541Srgrimes	}
297160139Sjhb	if (*ngrp < cred->cr_ngroups)
29892987Sjhb		return (EINVAL);
299160139Sjhb	*ngrp = cred->cr_ngroups;
300160139Sjhb	bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t));
301160139Sjhb	return (0);
3021541Srgrimes}
3031541Srgrimes
30412221Sbde#ifndef _SYS_SYSPROTO_H_
30512207Sbdestruct setsid_args {
30611332Sswallace        int     dummy;
30711332Sswallace};
30812221Sbde#endif
3091541Srgrimes/* ARGSUSED */
3101549Srgrimesint
31193580Sjhbsetsid(register struct thread *td, struct setsid_args *uap)
3121541Srgrimes{
31391140Stanimura	struct pgrp *pgrp;
31482749Sdillon	int error;
31583366Sjulian	struct proc *p = td->td_proc;
31691140Stanimura	struct pgrp *newpgrp;
31791140Stanimura	struct session *newsess;
3181541Srgrimes
31991140Stanimura	error = 0;
32091140Stanimura	pgrp = NULL;
32191140Stanimura
322111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
323111119Simp	MALLOC(newsess, struct session *, sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
32491140Stanimura
32594859Sjhb	sx_xlock(&proctree_lock);
32691140Stanimura
32791140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
32891140Stanimura		if (pgrp != NULL)
32991140Stanimura			PGRP_UNLOCK(pgrp);
33082749Sdillon		error = EPERM;
33191140Stanimura	} else {
33291140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
33383366Sjulian		td->td_retval[0] = p->p_pid;
33494859Sjhb		newpgrp = NULL;
33594859Sjhb		newsess = NULL;
3361541Srgrimes	}
33791140Stanimura
33894859Sjhb	sx_xunlock(&proctree_lock);
33991140Stanimura
34095973Stanimura	if (newpgrp != NULL)
34195973Stanimura		FREE(newpgrp, M_PGRP);
34295973Stanimura	if (newsess != NULL)
34395973Stanimura		FREE(newsess, M_SESSION);
34491140Stanimura
34594859Sjhb	return (error);
3461541Srgrimes}
3471541Srgrimes
3481541Srgrimes/*
3491541Srgrimes * set process group (setpgid/old setpgrp)
3501541Srgrimes *
3511541Srgrimes * caller does setpgid(targpid, targpgid)
3521541Srgrimes *
3531541Srgrimes * pid must be caller or child of caller (ESRCH)
3541541Srgrimes * if a child
3551541Srgrimes *	pid must be in same session (EPERM)
3561541Srgrimes *	pid can't have done an exec (EACCES)
3571541Srgrimes * if pgid != pid
3581541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3591541Srgrimes * pid must not be session leader (EPERM)
3601541Srgrimes */
36112221Sbde#ifndef _SYS_SYSPROTO_H_
3621541Srgrimesstruct setpgid_args {
36387218Srwatson	int	pid;		/* target process id */
36487218Srwatson	int	pgid;		/* target pgrp id */
3651541Srgrimes};
36612221Sbde#endif
3671541Srgrimes/* ARGSUSED */
3681549Srgrimesint
36993580Sjhbsetpgid(struct thread *td, register struct setpgid_args *uap)
3701541Srgrimes{
37183366Sjulian	struct proc *curp = td->td_proc;
37287218Srwatson	register struct proc *targp;	/* target process */
37387218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
37475448Srwatson	int error;
37591140Stanimura	struct pgrp *newpgrp;
3761541Srgrimes
37720677Sbde	if (uap->pgid < 0)
37820677Sbde		return (EINVAL);
37991140Stanimura
38091140Stanimura	error = 0;
38191140Stanimura
382111119Simp	MALLOC(newpgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
38391140Stanimura
38494859Sjhb	sx_xlock(&proctree_lock);
3851541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
38691140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
38782749Sdillon			error = ESRCH;
38894859Sjhb			goto done;
38975893Sjhb		}
39091140Stanimura		if (!inferior(targp)) {
39191140Stanimura			PROC_UNLOCK(targp);
39291371Stanimura			error = ESRCH;
39394859Sjhb			goto done;
39491140Stanimura		}
395132568Srwatson		if ((error = p_cansee(td, targp))) {
39675893Sjhb			PROC_UNLOCK(targp);
39794859Sjhb			goto done;
39875893Sjhb		}
39975893Sjhb		if (targp->p_pgrp == NULL ||
40075893Sjhb		    targp->p_session != curp->p_session) {
40175893Sjhb			PROC_UNLOCK(targp);
40282749Sdillon			error = EPERM;
40394859Sjhb			goto done;
40475893Sjhb		}
40575893Sjhb		if (targp->p_flag & P_EXEC) {
40675893Sjhb			PROC_UNLOCK(targp);
40782749Sdillon			error = EACCES;
40894859Sjhb			goto done;
40975893Sjhb		}
41091140Stanimura		PROC_UNLOCK(targp);
41191140Stanimura	} else
4121541Srgrimes		targp = curp;
41375893Sjhb	if (SESS_LEADER(targp)) {
41482749Sdillon		error = EPERM;
41594859Sjhb		goto done;
41675893Sjhb	}
41787218Srwatson	if (uap->pgid == 0)
4181541Srgrimes		uap->pgid = targp->p_pid;
419117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
420117214Scognet		if (uap->pgid == targp->p_pid) {
421117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
422117214Scognet			    NULL);
423117214Scognet			if (error == 0)
424117214Scognet				newpgrp = NULL;
425117214Scognet		} else
426117214Scognet			error = EPERM;
42791140Stanimura	} else {
428117214Scognet		if (pgrp == targp->p_pgrp) {
429117214Scognet			PGRP_UNLOCK(pgrp);
43094859Sjhb			goto done;
43175893Sjhb		}
432117214Scognet		if (pgrp->pg_id != targp->p_pid &&
433117214Scognet		    pgrp->pg_session != curp->p_session) {
43491140Stanimura			PGRP_UNLOCK(pgrp);
435117214Scognet			error = EPERM;
43691140Stanimura			goto done;
43791140Stanimura		}
43891140Stanimura		PGRP_UNLOCK(pgrp);
43991140Stanimura		error = enterthispgrp(targp, pgrp);
44082749Sdillon	}
44191140Stanimuradone:
44294859Sjhb	sx_xunlock(&proctree_lock);
44394859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
44494859Sjhb	    ("setpgid failed and newpgrp is NULL"));
44595973Stanimura	if (newpgrp != NULL)
44691140Stanimura		FREE(newpgrp, M_PGRP);
44782749Sdillon	return (error);
4481541Srgrimes}
4491541Srgrimes
45024448Speter/*
45124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
45272093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
45324448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
45424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
45524448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
45624448Speter * does not set the saved id - this is dangerous for traditional BSD
45724448Speter * programs.  For this reason, we *really* do not want to set
45824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
45924448Speter */
46024448Speter#define POSIX_APPENDIX_B_4_2_2
46124448Speter
46212221Sbde#ifndef _SYS_SYSPROTO_H_
4631541Srgrimesstruct setuid_args {
4641541Srgrimes	uid_t	uid;
4651541Srgrimes};
46612221Sbde#endif
4671541Srgrimes/* ARGSUSED */
4681549Srgrimesint
46993580Sjhbsetuid(struct thread *td, struct setuid_args *uap)
4701541Srgrimes{
47183366Sjulian	struct proc *p = td->td_proc;
47277183Srwatson	struct ucred *newcred, *oldcred;
47377183Srwatson	uid_t uid;
47498417Salfred	struct uidinfo *uip;
47587218Srwatson	int error;
4761541Srgrimes
47777183Srwatson	uid = uap->uid;
478155370Swsalamon	AUDIT_ARG(uid, uid);
47994619Sjhb	newcred = crget();
48098417Salfred	uip = uifind(uid);
48194619Sjhb	PROC_LOCK(p);
48287219Srwatson	oldcred = p->p_ucred;
48387466Srwatson
484145147Srwatson#ifdef MAC
485145147Srwatson	error = mac_check_proc_setuid(p, oldcred, uid);
486145147Srwatson	if (error)
487145147Srwatson		goto fail;
488145147Srwatson#endif
489145147Srwatson
49024448Speter	/*
49124448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
49224448Speter	 *
49387218Srwatson	 * Note that setuid(geteuid()) is a special case of
49424448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
49572093Sasmodai	 * to use this clause to be compatible with traditional BSD
49624448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
49724448Speter	 * three id's (assuming you have privs).
49824448Speter	 *
49924448Speter	 * Notes on the logic.  We do things in three steps.
50024448Speter	 * 1: We determine if the euid is going to change, and do EPERM
50124448Speter	 *    right away.  We unconditionally change the euid later if this
50224448Speter	 *    test is satisfied, simplifying that part of the logic.
50387218Srwatson	 * 2: We determine if the real and/or saved uids are going to
50424448Speter	 *    change.  Determined by compile options.
50524448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
50624448Speter	 */
50777183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
50817994Sache#ifdef _POSIX_SAVED_IDS
50977183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
51017994Sache#endif
51124448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
51277183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
51324448Speter#endif
514170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0)
515145147Srwatson		goto fail;
51624448Speter
51798417Salfred	/*
51898417Salfred	 * Copy credentials so other references do not see our changes.
51998417Salfred	 */
52094619Sjhb	crcopy(newcred, oldcred);
52124448Speter#ifdef _POSIX_SAVED_IDS
5221541Srgrimes	/*
52324448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
52424448Speter	 * If so, we are changing the real uid and/or saved uid.
5251541Srgrimes	 */
52617994Sache	if (
52724448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
52877183Srwatson	    uid == oldcred->cr_uid ||
52917994Sache#endif
530164032Srwatson	    /* We are using privs. */
531170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0)
53217994Sache#endif
53324448Speter	{
53424448Speter		/*
53565495Struckman		 * Set the real uid and transfer proc count to new user.
53624448Speter		 */
53777183Srwatson		if (uid != oldcred->cr_ruid) {
53898417Salfred			change_ruid(newcred, uip);
53965495Struckman			setsugid(p);
54024448Speter		}
54124448Speter		/*
54224448Speter		 * Set saved uid
54324448Speter		 *
54424448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
54524448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
54624448Speter		 * is important that we should do this.
54724448Speter		 */
54877183Srwatson		if (uid != oldcred->cr_svuid) {
54977183Srwatson			change_svuid(newcred, uid);
55031891Ssef			setsugid(p);
55124448Speter		}
5528141Sache	}
55324448Speter
55424448Speter	/*
55524448Speter	 * In all permitted cases, we are changing the euid.
55624448Speter	 */
55777183Srwatson	if (uid != oldcred->cr_uid) {
55898417Salfred		change_euid(newcred, uip);
55931891Ssef		setsugid(p);
56024448Speter	}
56177183Srwatson	p->p_ucred = newcred;
56294619Sjhb	PROC_UNLOCK(p);
56398417Salfred	uifree(uip);
56477183Srwatson	crfree(oldcred);
56594619Sjhb	return (0);
566145147Srwatson
567145147Srwatsonfail:
568145147Srwatson	PROC_UNLOCK(p);
569145147Srwatson	uifree(uip);
570145147Srwatson	crfree(newcred);
571145147Srwatson	return (error);
5721541Srgrimes}
5731541Srgrimes
57412221Sbde#ifndef _SYS_SYSPROTO_H_
5751541Srgrimesstruct seteuid_args {
5761541Srgrimes	uid_t	euid;
5771541Srgrimes};
57812221Sbde#endif
5791541Srgrimes/* ARGSUSED */
5801549Srgrimesint
58193580Sjhbseteuid(struct thread *td, struct seteuid_args *uap)
5821541Srgrimes{
58383366Sjulian	struct proc *p = td->td_proc;
58477183Srwatson	struct ucred *newcred, *oldcred;
58577183Srwatson	uid_t euid;
58698417Salfred	struct uidinfo *euip;
58787218Srwatson	int error;
5881541Srgrimes
5891541Srgrimes	euid = uap->euid;
590155370Swsalamon	AUDIT_ARG(euid, euid);
59194619Sjhb	newcred = crget();
59298417Salfred	euip = uifind(euid);
59394619Sjhb	PROC_LOCK(p);
59477183Srwatson	oldcred = p->p_ucred;
595145147Srwatson
596145147Srwatson#ifdef MAC
597145147Srwatson	error = mac_check_proc_seteuid(p, oldcred, euid);
598145147Srwatson	if (error)
599145147Srwatson		goto fail;
600145147Srwatson#endif
601145147Srwatson
60277183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
60377183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
604170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0)
605145147Srwatson		goto fail;
606145147Srwatson
6071541Srgrimes	/*
6081541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
6091541Srgrimes	 * not see our changes.
6101541Srgrimes	 */
61194619Sjhb	crcopy(newcred, oldcred);
61277183Srwatson	if (oldcred->cr_uid != euid) {
61398417Salfred		change_euid(newcred, euip);
61431891Ssef		setsugid(p);
61524449Speter	}
61677183Srwatson	p->p_ucred = newcred;
61794619Sjhb	PROC_UNLOCK(p);
61898417Salfred	uifree(euip);
61977183Srwatson	crfree(oldcred);
62094619Sjhb	return (0);
621145147Srwatson
622145147Srwatsonfail:
623145147Srwatson	PROC_UNLOCK(p);
624145147Srwatson	uifree(euip);
625145147Srwatson	crfree(newcred);
626145147Srwatson	return (error);
6271541Srgrimes}
6281541Srgrimes
62912221Sbde#ifndef _SYS_SYSPROTO_H_
6301541Srgrimesstruct setgid_args {
6311541Srgrimes	gid_t	gid;
6321541Srgrimes};
63312221Sbde#endif
6341541Srgrimes/* ARGSUSED */
6351549Srgrimesint
63693580Sjhbsetgid(struct thread *td, struct setgid_args *uap)
6371541Srgrimes{
63883366Sjulian	struct proc *p = td->td_proc;
63977183Srwatson	struct ucred *newcred, *oldcred;
64077183Srwatson	gid_t gid;
64187218Srwatson	int error;
6421541Srgrimes
64377183Srwatson	gid = uap->gid;
644155370Swsalamon	AUDIT_ARG(gid, gid);
64594619Sjhb	newcred = crget();
64694619Sjhb	PROC_LOCK(p);
64777183Srwatson	oldcred = p->p_ucred;
64887466Srwatson
649145147Srwatson#ifdef MAC
650145147Srwatson	error = mac_check_proc_setgid(p, oldcred, gid);
651145147Srwatson	if (error)
652145147Srwatson		goto fail;
653145147Srwatson#endif
654145147Srwatson
65524448Speter	/*
65624448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
65724448Speter	 *
65824448Speter	 * Note that setgid(getegid()) is a special case of
65924448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
66072093Sasmodai	 * to use this clause to be compatible with traditional BSD
66124448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
66224448Speter	 * three id's (assuming you have privs).
66324448Speter	 *
66424448Speter	 * For notes on the logic here, see setuid() above.
66524448Speter	 */
66677183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
66717994Sache#ifdef _POSIX_SAVED_IDS
66877183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
66917994Sache#endif
67024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
67177183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
67224448Speter#endif
673170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0)
674145147Srwatson		goto fail;
67524448Speter
67694619Sjhb	crcopy(newcred, oldcred);
67717994Sache#ifdef _POSIX_SAVED_IDS
67824448Speter	/*
67924448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
68024448Speter	 * If so, we are changing the real uid and saved gid.
68124448Speter	 */
68224448Speter	if (
68324448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
68477183Srwatson	    gid == oldcred->cr_groups[0] ||
68517994Sache#endif
686164032Srwatson	    /* We are using privs. */
687170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0)
68824448Speter#endif
68924448Speter	{
69024448Speter		/*
69124448Speter		 * Set real gid
69224448Speter		 */
69377183Srwatson		if (oldcred->cr_rgid != gid) {
69477183Srwatson			change_rgid(newcred, gid);
69531891Ssef			setsugid(p);
69624448Speter		}
69724448Speter		/*
69824448Speter		 * Set saved gid
69924448Speter		 *
70024448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
70124448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
70224448Speter		 * is important that we should do this.
70324448Speter		 */
70477183Srwatson		if (oldcred->cr_svgid != gid) {
70577183Srwatson			change_svgid(newcred, gid);
70631891Ssef			setsugid(p);
70724448Speter		}
7088141Sache	}
70924448Speter	/*
71024448Speter	 * In all cases permitted cases, we are changing the egid.
71124448Speter	 * Copy credentials so other references do not see our changes.
71224448Speter	 */
71377183Srwatson	if (oldcred->cr_groups[0] != gid) {
71477183Srwatson		change_egid(newcred, gid);
71531891Ssef		setsugid(p);
71624448Speter	}
71777183Srwatson	p->p_ucred = newcred;
71894619Sjhb	PROC_UNLOCK(p);
71977183Srwatson	crfree(oldcred);
72094619Sjhb	return (0);
721145147Srwatson
722145147Srwatsonfail:
723145147Srwatson	PROC_UNLOCK(p);
724145147Srwatson	crfree(newcred);
725145147Srwatson	return (error);
7261541Srgrimes}
7271541Srgrimes
72812221Sbde#ifndef _SYS_SYSPROTO_H_
7291541Srgrimesstruct setegid_args {
7301541Srgrimes	gid_t	egid;
7311541Srgrimes};
73212221Sbde#endif
7331541Srgrimes/* ARGSUSED */
7341549Srgrimesint
73593580Sjhbsetegid(struct thread *td, struct setegid_args *uap)
7361541Srgrimes{
73783366Sjulian	struct proc *p = td->td_proc;
73877183Srwatson	struct ucred *newcred, *oldcred;
73977183Srwatson	gid_t egid;
74087218Srwatson	int error;
7411541Srgrimes
7421541Srgrimes	egid = uap->egid;
743155370Swsalamon	AUDIT_ARG(egid, egid);
74494619Sjhb	newcred = crget();
74594619Sjhb	PROC_LOCK(p);
74677183Srwatson	oldcred = p->p_ucred;
747145147Srwatson
748145147Srwatson#ifdef MAC
749145147Srwatson	error = mac_check_proc_setegid(p, oldcred, egid);
750145147Srwatson	if (error)
751145147Srwatson		goto fail;
752145147Srwatson#endif
753145147Srwatson
75477183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
75577183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
756170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0)
757145147Srwatson		goto fail;
758145147Srwatson
75994619Sjhb	crcopy(newcred, oldcred);
76077183Srwatson	if (oldcred->cr_groups[0] != egid) {
76177183Srwatson		change_egid(newcred, egid);
76231891Ssef		setsugid(p);
76324449Speter	}
76477183Srwatson	p->p_ucred = newcred;
76594619Sjhb	PROC_UNLOCK(p);
76677183Srwatson	crfree(oldcred);
76794619Sjhb	return (0);
768145147Srwatson
769145147Srwatsonfail:
770145147Srwatson	PROC_UNLOCK(p);
771145147Srwatson	crfree(newcred);
772145147Srwatson	return (error);
7731541Srgrimes}
7741541Srgrimes
77512221Sbde#ifndef _SYS_SYSPROTO_H_
7761541Srgrimesstruct setgroups_args {
7771541Srgrimes	u_int	gidsetsize;
7781541Srgrimes	gid_t	*gidset;
7791541Srgrimes};
78012221Sbde#endif
7811541Srgrimes/* ARGSUSED */
7821549Srgrimesint
78393580Sjhbsetgroups(struct thread *td, struct setgroups_args *uap)
7841541Srgrimes{
785160139Sjhb	gid_t groups[NGROUPS];
786160139Sjhb	int error;
787160139Sjhb
788160139Sjhb	if (uap->gidsetsize > NGROUPS)
789160139Sjhb		return (EINVAL);
790160139Sjhb	error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t));
791160139Sjhb	if (error)
792160139Sjhb		return (error);
793160139Sjhb	return (kern_setgroups(td, uap->gidsetsize, groups));
794160139Sjhb}
795160139Sjhb
796160139Sjhbint
797160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
798160139Sjhb{
79983366Sjulian	struct proc *p = td->td_proc;
800160139Sjhb	struct ucred *newcred, *oldcred;
8011541Srgrimes	int error;
8021541Srgrimes
80394619Sjhb	if (ngrp > NGROUPS)
80494619Sjhb		return (EINVAL);
805160139Sjhb	AUDIT_ARG(groupset, groups, ngrp);
80694619Sjhb	newcred = crget();
80794619Sjhb	PROC_LOCK(p);
80877183Srwatson	oldcred = p->p_ucred;
809145147Srwatson
810145147Srwatson#ifdef MAC
811160139Sjhb	error = mac_check_proc_setgroups(p, oldcred, ngrp, groups);
812145147Srwatson	if (error)
813145147Srwatson		goto fail;
814145147Srwatson#endif
815145147Srwatson
816170587Srwatson	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0);
817145147Srwatson	if (error)
818145147Srwatson		goto fail;
819145147Srwatson
82024447Speter	/*
82124447Speter	 * XXX A little bit lazy here.  We could test if anything has
82224447Speter	 * changed before crcopy() and setting P_SUGID.
82324447Speter	 */
82494619Sjhb	crcopy(newcred, oldcred);
82524447Speter	if (ngrp < 1) {
82624447Speter		/*
82724447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
82824447Speter		 * groups vector on non-BSD systems (which generally do not
82924447Speter		 * have the egid in the groups[0]).  We risk security holes
83024447Speter		 * when running non-BSD software if we do not do the same.
83124447Speter		 */
83277183Srwatson		newcred->cr_ngroups = 1;
83324447Speter	} else {
834160139Sjhb		bcopy(groups, newcred->cr_groups, ngrp * sizeof(gid_t));
83577183Srwatson		newcred->cr_ngroups = ngrp;
83624447Speter	}
83731891Ssef	setsugid(p);
83877183Srwatson	p->p_ucred = newcred;
83994619Sjhb	PROC_UNLOCK(p);
84077183Srwatson	crfree(oldcred);
84194619Sjhb	return (0);
842145147Srwatson
843145147Srwatsonfail:
844145147Srwatson	PROC_UNLOCK(p);
845145147Srwatson	crfree(newcred);
846145147Srwatson	return (error);
8471541Srgrimes}
8481541Srgrimes
84912221Sbde#ifndef _SYS_SYSPROTO_H_
8501541Srgrimesstruct setreuid_args {
8519238Sache	uid_t	ruid;
8529238Sache	uid_t	euid;
8531541Srgrimes};
85412221Sbde#endif
8551541Srgrimes/* ARGSUSED */
8561549Srgrimesint
85793580Sjhbsetreuid(register struct thread *td, struct setreuid_args *uap)
8581541Srgrimes{
85983366Sjulian	struct proc *p = td->td_proc;
86077183Srwatson	struct ucred *newcred, *oldcred;
86187218Srwatson	uid_t euid, ruid;
86298417Salfred	struct uidinfo *euip, *ruip;
86387218Srwatson	int error;
8641541Srgrimes
86587218Srwatson	euid = uap->euid;
8669238Sache	ruid = uap->ruid;
867155370Swsalamon	AUDIT_ARG(euid, euid);
868155370Swsalamon	AUDIT_ARG(ruid, ruid);
86994619Sjhb	newcred = crget();
87098417Salfred	euip = uifind(euid);
87198417Salfred	ruip = uifind(ruid);
87294619Sjhb	PROC_LOCK(p);
87377183Srwatson	oldcred = p->p_ucred;
874145147Srwatson
875145147Srwatson#ifdef MAC
876145147Srwatson	error = mac_check_proc_setreuid(p, oldcred, ruid, euid);
877145147Srwatson	if (error)
878145147Srwatson		goto fail;
879145147Srwatson#endif
880145147Srwatson
88177183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
88277183Srwatson	      ruid != oldcred->cr_svuid) ||
88377183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
88477183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
885170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0)
886145147Srwatson		goto fail;
887145147Srwatson
88894619Sjhb	crcopy(newcred, oldcred);
88977183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
89098417Salfred		change_euid(newcred, euip);
89131891Ssef		setsugid(p);
89224450Speter	}
89377183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
89498417Salfred		change_ruid(newcred, ruip);
89531891Ssef		setsugid(p);
8968135Sache	}
89777183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
89877183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
89977183Srwatson		change_svuid(newcred, newcred->cr_uid);
90031891Ssef		setsugid(p);
90124450Speter	}
90277183Srwatson	p->p_ucred = newcred;
90394619Sjhb	PROC_UNLOCK(p);
90498417Salfred	uifree(ruip);
90598417Salfred	uifree(euip);
90677183Srwatson	crfree(oldcred);
90794619Sjhb	return (0);
908145147Srwatson
909145147Srwatsonfail:
910145147Srwatson	PROC_UNLOCK(p);
911145147Srwatson	uifree(ruip);
912145147Srwatson	uifree(euip);
913145147Srwatson	crfree(newcred);
914145147Srwatson	return (error);
9151541Srgrimes}
9161541Srgrimes
91712221Sbde#ifndef _SYS_SYSPROTO_H_
9181541Srgrimesstruct setregid_args {
9199238Sache	gid_t	rgid;
9209238Sache	gid_t	egid;
9211541Srgrimes};
92212221Sbde#endif
9231541Srgrimes/* ARGSUSED */
9241549Srgrimesint
92593580Sjhbsetregid(register struct thread *td, struct setregid_args *uap)
9261541Srgrimes{
92783366Sjulian	struct proc *p = td->td_proc;
92877183Srwatson	struct ucred *newcred, *oldcred;
92987218Srwatson	gid_t egid, rgid;
93087218Srwatson	int error;
9311541Srgrimes
93287218Srwatson	egid = uap->egid;
9339238Sache	rgid = uap->rgid;
934155370Swsalamon	AUDIT_ARG(egid, egid);
935155370Swsalamon	AUDIT_ARG(rgid, rgid);
93694619Sjhb	newcred = crget();
93794619Sjhb	PROC_LOCK(p);
93877183Srwatson	oldcred = p->p_ucred;
939145147Srwatson
940145147Srwatson#ifdef MAC
941145147Srwatson	error = mac_check_proc_setregid(p, oldcred, rgid, egid);
942145147Srwatson	if (error)
943145147Srwatson		goto fail;
944145147Srwatson#endif
945145147Srwatson
94677183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
94777183Srwatson	    rgid != oldcred->cr_svgid) ||
94877183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
94977183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
950170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0)
951145147Srwatson		goto fail;
95294619Sjhb
95394619Sjhb	crcopy(newcred, oldcred);
95477183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
95577183Srwatson		change_egid(newcred, egid);
95631891Ssef		setsugid(p);
95724450Speter	}
95877183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
95977183Srwatson		change_rgid(newcred, rgid);
96031891Ssef		setsugid(p);
96124450Speter	}
96277183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
96377183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
96477183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
96531891Ssef		setsugid(p);
96624450Speter	}
96777812Sru	p->p_ucred = newcred;
96894619Sjhb	PROC_UNLOCK(p);
96977812Sru	crfree(oldcred);
97094619Sjhb	return (0);
971145147Srwatson
972145147Srwatsonfail:
973145147Srwatson	PROC_UNLOCK(p);
974145147Srwatson	crfree(newcred);
975145147Srwatson	return (error);
9761541Srgrimes}
9771541Srgrimes
97856115Speter/*
979167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved
980167232Srwatson * uid is explicit.
98156115Speter */
98224453Speter#ifndef _SYS_SYSPROTO_H_
98356115Speterstruct setresuid_args {
98456115Speter	uid_t	ruid;
98556115Speter	uid_t	euid;
98656115Speter	uid_t	suid;
98756115Speter};
98856115Speter#endif
98956115Speter/* ARGSUSED */
99056115Speterint
99193580Sjhbsetresuid(register struct thread *td, struct setresuid_args *uap)
99256115Speter{
99383366Sjulian	struct proc *p = td->td_proc;
99477183Srwatson	struct ucred *newcred, *oldcred;
99587218Srwatson	uid_t euid, ruid, suid;
99698417Salfred	struct uidinfo *euip, *ruip;
99756115Speter	int error;
99856115Speter
99987218Srwatson	euid = uap->euid;
100056115Speter	ruid = uap->ruid;
100156115Speter	suid = uap->suid;
1002155370Swsalamon	AUDIT_ARG(euid, euid);
1003155370Swsalamon	AUDIT_ARG(ruid, ruid);
1004155370Swsalamon	AUDIT_ARG(suid, suid);
100594619Sjhb	newcred = crget();
100698417Salfred	euip = uifind(euid);
100798417Salfred	ruip = uifind(ruid);
100894619Sjhb	PROC_LOCK(p);
100977183Srwatson	oldcred = p->p_ucred;
1010145147Srwatson
1011145147Srwatson#ifdef MAC
1012145147Srwatson	error = mac_check_proc_setresuid(p, oldcred, ruid, euid, suid);
1013145147Srwatson	if (error)
1014145147Srwatson		goto fail;
1015145147Srwatson#endif
1016145147Srwatson
101777183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
101877183Srwatson	     ruid != oldcred->cr_svuid &&
101977183Srwatson	      ruid != oldcred->cr_uid) ||
102077183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
102177183Srwatson	    euid != oldcred->cr_svuid &&
102277183Srwatson	      euid != oldcred->cr_uid) ||
102377183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
102477183Srwatson	    suid != oldcred->cr_svuid &&
102577183Srwatson	      suid != oldcred->cr_uid)) &&
1026170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0)
1027145147Srwatson		goto fail;
102894619Sjhb
102994619Sjhb	crcopy(newcred, oldcred);
103077183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
103198417Salfred		change_euid(newcred, euip);
103256115Speter		setsugid(p);
103356115Speter	}
103477183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
103598417Salfred		change_ruid(newcred, ruip);
103656115Speter		setsugid(p);
103756115Speter	}
103877183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
103977183Srwatson		change_svuid(newcred, suid);
104056115Speter		setsugid(p);
104156115Speter	}
104277183Srwatson	p->p_ucred = newcred;
104394619Sjhb	PROC_UNLOCK(p);
104498417Salfred	uifree(ruip);
104598417Salfred	uifree(euip);
104677183Srwatson	crfree(oldcred);
104794619Sjhb	return (0);
1048145147Srwatson
1049145147Srwatsonfail:
1050145147Srwatson	PROC_UNLOCK(p);
1051145147Srwatson	uifree(ruip);
1052145147Srwatson	uifree(euip);
1053145147Srwatson	crfree(newcred);
1054145147Srwatson	return (error);
1055145147Srwatson
105656115Speter}
105756115Speter
105856115Speter/*
1059167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1060167232Srwatson * gid is explicit.
106156115Speter */
106256115Speter#ifndef _SYS_SYSPROTO_H_
106356115Speterstruct setresgid_args {
106456115Speter	gid_t	rgid;
106556115Speter	gid_t	egid;
106656115Speter	gid_t	sgid;
106756115Speter};
106856115Speter#endif
106956115Speter/* ARGSUSED */
107056115Speterint
107193580Sjhbsetresgid(register struct thread *td, struct setresgid_args *uap)
107256115Speter{
107383366Sjulian	struct proc *p = td->td_proc;
107477183Srwatson	struct ucred *newcred, *oldcred;
107587218Srwatson	gid_t egid, rgid, sgid;
107656115Speter	int error;
107756115Speter
107887218Srwatson	egid = uap->egid;
107956115Speter	rgid = uap->rgid;
108056115Speter	sgid = uap->sgid;
1081155370Swsalamon	AUDIT_ARG(egid, egid);
1082155370Swsalamon	AUDIT_ARG(rgid, rgid);
1083155370Swsalamon	AUDIT_ARG(sgid, sgid);
108494619Sjhb	newcred = crget();
108594619Sjhb	PROC_LOCK(p);
108677183Srwatson	oldcred = p->p_ucred;
1087145147Srwatson
1088145147Srwatson#ifdef MAC
1089145147Srwatson	error = mac_check_proc_setresgid(p, oldcred, rgid, egid, sgid);
1090145147Srwatson	if (error)
1091145147Srwatson		goto fail;
1092145147Srwatson#endif
1093145147Srwatson
109477183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
109577183Srwatson	      rgid != oldcred->cr_svgid &&
109677183Srwatson	      rgid != oldcred->cr_groups[0]) ||
109777183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
109877183Srwatson	      egid != oldcred->cr_svgid &&
109977183Srwatson	      egid != oldcred->cr_groups[0]) ||
110077183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
110177183Srwatson	      sgid != oldcred->cr_svgid &&
110277183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1103170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0)
1104145147Srwatson		goto fail;
110594619Sjhb
110694619Sjhb	crcopy(newcred, oldcred);
110777183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
110877183Srwatson		change_egid(newcred, egid);
110956115Speter		setsugid(p);
111056115Speter	}
111177183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
111277183Srwatson		change_rgid(newcred, rgid);
111356115Speter		setsugid(p);
111456115Speter	}
111577183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
111677183Srwatson		change_svgid(newcred, sgid);
111756115Speter		setsugid(p);
111856115Speter	}
111977183Srwatson	p->p_ucred = newcred;
112094619Sjhb	PROC_UNLOCK(p);
112177183Srwatson	crfree(oldcred);
112294619Sjhb	return (0);
1123145147Srwatson
1124145147Srwatsonfail:
1125145147Srwatson	PROC_UNLOCK(p);
1126145147Srwatson	crfree(newcred);
1127145147Srwatson	return (error);
112856115Speter}
112956115Speter
113056115Speter#ifndef _SYS_SYSPROTO_H_
113156115Speterstruct getresuid_args {
113256115Speter	uid_t	*ruid;
113356115Speter	uid_t	*euid;
113456115Speter	uid_t	*suid;
113556115Speter};
113656115Speter#endif
113756115Speter/* ARGSUSED */
113856115Speterint
113993580Sjhbgetresuid(register struct thread *td, struct getresuid_args *uap)
114056115Speter{
114182749Sdillon	struct ucred *cred;
114256115Speter	int error1 = 0, error2 = 0, error3 = 0;
114356115Speter
114493264Sdillon	cred = td->td_ucred;
114556115Speter	if (uap->ruid)
114699009Salfred		error1 = copyout(&cred->cr_ruid,
114799009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
114856115Speter	if (uap->euid)
114999009Salfred		error2 = copyout(&cred->cr_uid,
115099009Salfred		    uap->euid, sizeof(cred->cr_uid));
115156115Speter	if (uap->suid)
115299009Salfred		error3 = copyout(&cred->cr_svuid,
115399009Salfred		    uap->suid, sizeof(cred->cr_svuid));
115487218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
115556115Speter}
115656115Speter
115756115Speter#ifndef _SYS_SYSPROTO_H_
115856115Speterstruct getresgid_args {
115956115Speter	gid_t	*rgid;
116056115Speter	gid_t	*egid;
116156115Speter	gid_t	*sgid;
116256115Speter};
116356115Speter#endif
116456115Speter/* ARGSUSED */
116556115Speterint
116693580Sjhbgetresgid(register struct thread *td, struct getresgid_args *uap)
116756115Speter{
116882749Sdillon	struct ucred *cred;
116956115Speter	int error1 = 0, error2 = 0, error3 = 0;
117056115Speter
117193264Sdillon	cred = td->td_ucred;
117256115Speter	if (uap->rgid)
117399009Salfred		error1 = copyout(&cred->cr_rgid,
117499009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
117556115Speter	if (uap->egid)
117699009Salfred		error2 = copyout(&cred->cr_groups[0],
117799009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
117856115Speter	if (uap->sgid)
117999009Salfred		error3 = copyout(&cred->cr_svgid,
118099009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
118187218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
118256115Speter}
118356115Speter
118456115Speter#ifndef _SYS_SYSPROTO_H_
118524453Speterstruct issetugid_args {
118624453Speter	int dummy;
118724453Speter};
118824453Speter#endif
118924453Speter/* ARGSUSED */
119024453Speterint
119193580Sjhbissetugid(register struct thread *td, struct issetugid_args *uap)
119224453Speter{
119383366Sjulian	struct proc *p = td->td_proc;
119483366Sjulian
119524453Speter	/*
119624453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
119724453Speter	 * we use P_SUGID because we consider changing the owners as
119824453Speter	 * "tainting" as well.
119924453Speter	 * This is significant for procs that start as root and "become"
120024453Speter	 * a user without an exec - programs cannot know *everything*
120124453Speter	 * that libc *might* have put in their data segment.
120224453Speter	 */
120391140Stanimura	PROC_LOCK(p);
120483366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
120591140Stanimura	PROC_UNLOCK(p);
120624453Speter	return (0);
120724453Speter}
120824453Speter
120975426Srwatsonint
121093580Sjhb__setugid(struct thread *td, struct __setugid_args *uap)
121175426Srwatson{
121282749Sdillon#ifdef REGRESSION
121394619Sjhb	struct proc *p;
121475426Srwatson
121594619Sjhb	p = td->td_proc;
121675426Srwatson	switch (uap->flag) {
121775426Srwatson	case 0:
121894619Sjhb		PROC_LOCK(p);
121994619Sjhb		p->p_flag &= ~P_SUGID;
122094619Sjhb		PROC_UNLOCK(p);
122194619Sjhb		return (0);
122275426Srwatson	case 1:
122394619Sjhb		PROC_LOCK(p);
122494619Sjhb		p->p_flag |= P_SUGID;
122594619Sjhb		PROC_UNLOCK(p);
122694619Sjhb		return (0);
122775426Srwatson	default:
122894619Sjhb		return (EINVAL);
122975426Srwatson	}
123075426Srwatson#else /* !REGRESSION */
123187218Srwatson
123275426Srwatson	return (ENOSYS);
123387218Srwatson#endif /* REGRESSION */
123475426Srwatson}
123575426Srwatson
12361541Srgrimes/*
12371541Srgrimes * Check if gid is a member of the group set.
12381541Srgrimes */
12391549Srgrimesint
124093580Sjhbgroupmember(gid_t gid, struct ucred *cred)
12411541Srgrimes{
12421541Srgrimes	register gid_t *gp;
12431541Srgrimes	gid_t *egp;
12441541Srgrimes
12451541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
12461541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
12471541Srgrimes		if (*gp == gid)
12481541Srgrimes			return (1);
12491541Srgrimes	return (0);
12501541Srgrimes}
12511541Srgrimes
125282424Srwatson/*
125387218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
125487218Srwatson * implements (securelevel > level).  securelevel_ge() implements
125587218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
125687218Srwatson * functions return EPERM on "success" and 0 on "failure".
125783639Srwatson *
1258164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to
1259164032Srwatson * kern_priv.c.
126083639Srwatson */
126183639Srwatsonint
126283639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
126383639Srwatson{
126487218Srwatson	int active_securelevel;
126583639Srwatson
126687218Srwatson	active_securelevel = securelevel;
126793732Sjhb	KASSERT(cr != NULL, ("securelevel_gt: null cr"));
1268140678Srwatson	if (cr->cr_prison != NULL)
126987218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
127087218Srwatson		    active_securelevel);
127187218Srwatson	return (active_securelevel > level ? EPERM : 0);
127283639Srwatson}
127383639Srwatson
127483639Srwatsonint
127583639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
127683639Srwatson{
127787218Srwatson	int active_securelevel;
127883639Srwatson
127987218Srwatson	active_securelevel = securelevel;
128093732Sjhb	KASSERT(cr != NULL, ("securelevel_ge: null cr"));
1281140678Srwatson	if (cr->cr_prison != NULL)
128287218Srwatson		active_securelevel = imax(cr->cr_prison->pr_securelevel,
128387218Srwatson		    active_securelevel);
128487218Srwatson	return (active_securelevel >= level ? EPERM : 0);
128583639Srwatson}
128683639Srwatson
128784736Srwatson/*
128887144Srwatson * 'see_other_uids' determines whether or not visibility of processes
128987218Srwatson * and sockets with credentials holding different real uids is possible
129087138Srwatson * using a variety of system MIBs.
129187218Srwatson * XXX: data declarations should be together near the beginning of the file.
129284736Srwatson */
129387144Srwatsonstatic int	see_other_uids = 1;
129489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
129587218Srwatson    &see_other_uids, 0,
129684736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
129784736Srwatson
129882466Srwatson/*-
129992923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
130092923Srwatson * 'see_other_uids' policy.
130192923Srwatson * Returns: 0 for permitted, ESRCH otherwise
130292923Srwatson * Locks: none
130392923Srwatson * References: *u1 and *u2 must not change during the call
130492923Srwatson *             u1 may equal u2, in which case only one reference is required
130592923Srwatson */
130692923Srwatsonstatic int
130792923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
130892923Srwatson{
130992923Srwatson
131092923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1311170587Srwatson		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0)
131292923Srwatson			return (ESRCH);
131392923Srwatson	}
131492923Srwatson	return (0);
131592923Srwatson}
131692923Srwatson
1317122869Srwatson/*
1318122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1319122869Srwatson * and sockets with credentials holding different real gids is possible
1320122869Srwatson * using a variety of system MIBs.
1321122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1322122869Srwatson */
1323122869Srwatsonstatic int	see_other_gids = 1;
1324122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1325122869Srwatson    &see_other_gids, 0,
1326122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1327122869Srwatson
1328122869Srwatson/*
1329122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1330122869Srwatson * 'see_other_gids' policy.
1331122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1332122869Srwatson * Locks: none
1333122869Srwatson * References: *u1 and *u2 must not change during the call
1334122869Srwatson *             u1 may equal u2, in which case only one reference is required
1335122869Srwatson */
1336122869Srwatsonstatic int
1337122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1338122869Srwatson{
1339122869Srwatson	int i, match;
1340122869Srwatson
1341122869Srwatson	if (!see_other_gids) {
1342122869Srwatson		match = 0;
1343122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1344122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1345122869Srwatson				match = 1;
1346122869Srwatson			if (match)
1347122869Srwatson				break;
1348122869Srwatson		}
1349122869Srwatson		if (!match) {
1350170587Srwatson			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0)
1351122869Srwatson				return (ESRCH);
1352122869Srwatson		}
1353122869Srwatson	}
1354122869Srwatson	return (0);
1355122869Srwatson}
1356122869Srwatson
135792923Srwatson/*-
135882466Srwatson * Determine if u1 "can see" the subject specified by u2.
135974956Srwatson * Returns: 0 for permitted, an errno value otherwise
136074956Srwatson * Locks: none
136187218Srwatson * References: *u1 and *u2 must not change during the call
136274956Srwatson *             u1 may equal u2, in which case only one reference is required
136374956Srwatson */
136474956Srwatsonint
136583742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
136665237Srwatson{
136772786Srwatson	int error;
136853518Sphk
136974956Srwatson	if ((error = prison_check(u1, u2)))
137072786Srwatson		return (error);
1371101003Srwatson#ifdef MAC
1372101003Srwatson	if ((error = mac_check_cred_visible(u1, u2)))
1373101003Srwatson		return (error);
1374101003Srwatson#endif
137592923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
137692923Srwatson		return (error);
1377122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1378122869Srwatson		return (error);
137965237Srwatson	return (0);
138065237Srwatson}
138165237Srwatson
138282466Srwatson/*-
138396886Sjhb * Determine if td "can see" the subject specified by p.
138482424Srwatson * Returns: 0 for permitted, an errno value otherwise
138596886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
138696886Sjhb *        should be curthread.
138796886Sjhb * References: td and p must be valid for the lifetime of the call
138882424Srwatson */
138979335Srwatsonint
139096886Sjhbp_cansee(struct thread *td, struct proc *p)
139174956Srwatson{
139274956Srwatson
139383742Srwatson	/* Wrap cr_cansee() for all functionality. */
139496886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
139596886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
139696886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
139774956Srwatson}
139874956Srwatson
1399120052Srwatson/*
1400120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1401120052Srwatson * signals by unprivileged processes to processes that have changed their
1402120052Srwatson * credentials since the last invocation of execve().  This can prevent
1403120052Srwatson * the leakage of cached information or retained privileges as a result
1404120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1405120052Srwatson * may interfere with some applications that expect to be able to
1406120052Srwatson * deliver these signals to peer processes after having given up
1407120052Srwatson * privilege.
1408120052Srwatson */
1409120052Srwatsonstatic int	conservative_signals = 1;
1410120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1411120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1412120052Srwatson    "sending certain signals to processes whose credentials have changed");
141382466Srwatson/*-
141488943Srwatson * Determine whether cred may deliver the specified signal to proc.
141588943Srwatson * Returns: 0 for permitted, an errno value otherwise.
141688943Srwatson * Locks: A lock must be held for proc.
141788943Srwatson * References: cred and proc must be valid for the lifetime of the call.
141875437Srwatson */
141975437Srwatsonint
1420141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum)
142153518Sphk{
142282466Srwatson	int error;
142384826Sjhb
142496886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
142575437Srwatson	/*
142688943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
142788943Srwatson	 * same jail as cred, if cred is in jail.
142875437Srwatson	 */
142988943Srwatson	error = prison_check(cred, proc->p_ucred);
143088943Srwatson	if (error)
143172786Srwatson		return (error);
1432101003Srwatson#ifdef MAC
1433101003Srwatson	if ((error = mac_check_proc_signal(cred, proc, signum)))
1434101003Srwatson		return (error);
1435101003Srwatson#endif
1436122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
143792923Srwatson		return (error);
1438122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1439122869Srwatson		return (error);
144065237Srwatson
144165237Srwatson	/*
144282424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
144382424Srwatson	 * bit on the target process.  If the bit is set, then additional
144482424Srwatson	 * restrictions are placed on the set of available signals.
144575437Srwatson	 */
1446141815Ssobomax	if (conservative_signals && (proc->p_flag & P_SUGID)) {
144775437Srwatson		switch (signum) {
144875437Srwatson		case 0:
144975437Srwatson		case SIGKILL:
145075437Srwatson		case SIGINT:
145175437Srwatson		case SIGTERM:
1452120052Srwatson		case SIGALRM:
145375437Srwatson		case SIGSTOP:
145475437Srwatson		case SIGTTIN:
145575437Srwatson		case SIGTTOU:
145675437Srwatson		case SIGTSTP:
145775437Srwatson		case SIGHUP:
145875437Srwatson		case SIGUSR1:
145975437Srwatson		case SIGUSR2:
146082466Srwatson			/*
146182466Srwatson			 * Generally, permit job and terminal control
146282466Srwatson			 * signals.
146382466Srwatson			 */
146475437Srwatson			break;
146575437Srwatson		default:
146688943Srwatson			/* Not permitted without privilege. */
1467170587Srwatson			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0);
146875437Srwatson			if (error)
146975437Srwatson				return (error);
147075437Srwatson		}
147165237Srwatson	}
147265237Srwatson
147375480Srwatson	/*
147482424Srwatson	 * Generally, the target credential's ruid or svuid must match the
147575480Srwatson	 * subject credential's ruid or euid.
147675480Srwatson	 */
147788943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
147888943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
147988943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
148088943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1481170587Srwatson		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0);
148275480Srwatson		if (error)
148375480Srwatson			return (error);
148475480Srwatson	}
148575480Srwatson
148687218Srwatson	return (0);
148753518Sphk}
148853518Sphk
148982466Srwatson/*-
149096886Sjhb * Determine whether td may deliver the specified signal to p.
149188943Srwatson * Returns: 0 for permitted, an errno value otherwise
149296886Sjhb * Locks: Sufficient locks to protect various components of td and p
149396886Sjhb *        must be held.  td must be curthread, and a lock must be
149496886Sjhb *        held for p.
149596886Sjhb * References: td and p must be valid for the lifetime of the call
149688943Srwatson */
149788943Srwatsonint
1498141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum)
149988943Srwatson{
150088943Srwatson
150196886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
150296886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
150396886Sjhb	if (td->td_proc == p)
150488943Srwatson		return (0);
150588943Srwatson
150688943Srwatson	/*
150788943Srwatson	 * UNIX signalling semantics require that processes in the same
150888943Srwatson	 * session always be able to deliver SIGCONT to one another,
150988943Srwatson	 * overriding the remaining protections.
151088943Srwatson	 */
151196886Sjhb	/* XXX: This will require an additional lock of some sort. */
151296886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
151388943Srwatson		return (0);
1514143108Ssobomax	/*
1515143800Ssobomax	 * Some compat layers use SIGTHR and higher signals for
1516143800Ssobomax	 * communication between different kernel threads of the same
1517143800Ssobomax	 * process, so that they expect that it's always possible to
1518143800Ssobomax	 * deliver them, even for suid applications where cr_cansignal() can
1519143108Ssobomax	 * deny such ability for security consideration.  It should be
1520143108Ssobomax	 * pretty safe to do since the only way to create two processes
1521143108Ssobomax	 * with the same p_leader is via rfork(2).
1522143108Ssobomax	 */
1523143805Ssobomax	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
1524143805Ssobomax	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
1525143108Ssobomax		return (0);
152688943Srwatson
1527141815Ssobomax	return (cr_cansignal(td->td_ucred, p, signum));
152888943Srwatson}
152988943Srwatson
153088943Srwatson/*-
153196886Sjhb * Determine whether td may reschedule p.
153282466Srwatson * Returns: 0 for permitted, an errno value otherwise
153396886Sjhb * Locks: Sufficient locks to protect various components of td and p
153496886Sjhb *        must be held.  td must be curthread, and a lock must
153596886Sjhb *        be held for p.
153696886Sjhb * References: td and p must be valid for the lifetime of the call
153782424Srwatson */
153879335Srwatsonint
153996886Sjhbp_cansched(struct thread *td, struct proc *p)
154065237Srwatson{
154172786Srwatson	int error;
154265237Srwatson
154396886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
154496886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
154596886Sjhb	if (td->td_proc == p)
154665237Srwatson		return (0);
154796886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
154872786Srwatson		return (error);
1549101003Srwatson#ifdef MAC
1550101003Srwatson	if ((error = mac_check_proc_sched(td->td_ucred, p)))
1551101003Srwatson		return (error);
1552101003Srwatson#endif
155396886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
155492923Srwatson		return (error);
1555122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1556122869Srwatson		return (error);
1557164032Srwatson	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1558164032Srwatson	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
1559170587Srwatson		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1560164032Srwatson		if (error)
1561164032Srwatson			return (error);
1562164032Srwatson	}
1563164032Srwatson	return (0);
156465237Srwatson}
156565237Srwatson
156682424Srwatson/*
156787280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
156887280Srwatson * unprivileged inter-process debugging services, including some procfs
156987280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
157087280Srwatson * debugging has been involved in a variety of security problems, and sites
157187280Srwatson * not requiring the service might choose to disable it when hardening
157287280Srwatson * systems.
157382424Srwatson *
157482424Srwatson * XXX: Should modifying and reading this variable require locking?
157587218Srwatson * XXX: data declarations should be together near the beginning of the file.
157682424Srwatson */
157787144Srwatsonstatic int	unprivileged_proc_debug = 1;
157889414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
157987218Srwatson    &unprivileged_proc_debug, 0,
158080735Srwatson    "Unprivileged processes may use process debugging facilities");
158180735Srwatson
158282466Srwatson/*-
158396886Sjhb * Determine whether td may debug p.
158482466Srwatson * Returns: 0 for permitted, an errno value otherwise
158596886Sjhb * Locks: Sufficient locks to protect various components of td and p
158696886Sjhb *        must be held.  td must be curthread, and a lock must
158796886Sjhb *        be held for p.
158896886Sjhb * References: td and p must be valid for the lifetime of the call
158982424Srwatson */
159079335Srwatsonint
159196886Sjhbp_candebug(struct thread *td, struct proc *p)
159265237Srwatson{
159387218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
159465237Srwatson
159596886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
159696886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
159787144Srwatson	if (!unprivileged_proc_debug) {
1598170587Srwatson		error = priv_check(td, PRIV_DEBUG_UNPRIV);
159984727Srwatson		if (error)
160084727Srwatson			return (error);
160184727Srwatson	}
160296886Sjhb	if (td->td_proc == p)
160384636Sdes		return (0);
160496886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
160572786Srwatson		return (error);
1606101003Srwatson#ifdef MAC
1607101003Srwatson	if ((error = mac_check_proc_debug(td->td_ucred, p)))
1608101003Srwatson		return (error);
1609101003Srwatson#endif
161096886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
161192923Srwatson		return (error);
1612122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1613122869Srwatson		return (error);
161465237Srwatson
161582466Srwatson	/*
161696886Sjhb	 * Is p's group set a subset of td's effective group set?  This
161796886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
161882466Srwatson	 */
161985895Srwatson	grpsubset = 1;
162096886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
162196886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
162285895Srwatson			grpsubset = 0;
162385895Srwatson			break;
162485895Srwatson		}
162585895Srwatson	}
162685895Srwatson	grpsubset = grpsubset &&
162796886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
162896886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
162985895Srwatson
163085895Srwatson	/*
163196886Sjhb	 * Are the uids present in p's credential equal to td's
163296886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
163385895Srwatson	 */
163496886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
163596886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
163696886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
163785895Srwatson
163885895Srwatson	/*
163985895Srwatson	 * Has the credential of the process changed since the last exec()?
164085895Srwatson	 */
164196886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
164285895Srwatson
164385895Srwatson	/*
164496886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
164585895Srwatson	 * or the credential has changed, require appropriate privilege
1646164032Srwatson	 * for td to debug p.
164785895Srwatson	 */
1648164032Srwatson	if (!grpsubset || !uidsubset) {
1649170587Srwatson		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
165084727Srwatson		if (error)
165165237Srwatson			return (error);
165282466Srwatson	}
165365237Srwatson
1654164032Srwatson	if (credentialchanged) {
1655170587Srwatson		error = priv_check(td, PRIV_DEBUG_SUGID);
1656164032Srwatson		if (error)
1657164032Srwatson			return (error);
1658164032Srwatson	}
1659164032Srwatson
166087218Srwatson	/* Can't trace init when securelevel > 0. */
166196886Sjhb	if (p == initproc) {
166296886Sjhb		error = securelevel_gt(td->td_ucred, 0);
166383639Srwatson		if (error)
166483639Srwatson			return (error);
166583639Srwatson	}
166665237Srwatson
166785880Srwatson	/*
166885880Srwatson	 * Can't trace a process that's currently exec'ing.
1669164032Srwatson	 *
167085880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
167185880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
167285880Srwatson	 * should be moved to the caller's of p_candebug().
167385880Srwatson	 */
167496886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
167585598Sdes		return (EAGAIN);
167687466Srwatson
167765237Srwatson	return (0);
167865237Srwatson}
167965237Srwatson
168092976Srwatson/*-
168192976Srwatson * Determine whether the subject represented by cred can "see" a socket.
168292976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
168392976Srwatson */
168492976Srwatsonint
168592976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
168692976Srwatson{
168792976Srwatson	int error;
168892976Srwatson
168992976Srwatson	error = prison_check(cred, so->so_cred);
169092976Srwatson	if (error)
169192976Srwatson		return (ENOENT);
1692101003Srwatson#ifdef MAC
1693130398Srwatson	SOCK_LOCK(so);
1694101003Srwatson	error = mac_check_socket_visible(cred, so);
1695130398Srwatson	SOCK_UNLOCK(so);
1696101003Srwatson	if (error)
1697101003Srwatson		return (error);
1698101003Srwatson#endif
169992976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
170092976Srwatson		return (ENOENT);
1701122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1702122869Srwatson		return (ENOENT);
170392976Srwatson
170492976Srwatson	return (0);
170592976Srwatson}
170692976Srwatson
1707145234Srwatson/*-
1708145234Srwatson * Determine whether td can wait for the exit of p.
1709145234Srwatson * Returns: 0 for permitted, an errno value otherwise
1710145234Srwatson * Locks: Sufficient locks to protect various components of td and p
1711145234Srwatson *        must be held.  td must be curthread, and a lock must
1712145234Srwatson *        be held for p.
1713145234Srwatson * References: td and p must be valid for the lifetime of the call
1714145234Srwatson
1715145234Srwatson */
1716145234Srwatsonint
1717145234Srwatsonp_canwait(struct thread *td, struct proc *p)
1718145234Srwatson{
1719145234Srwatson	int error;
1720145234Srwatson
1721145234Srwatson	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1722145234Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
1723145234Srwatson	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1724145234Srwatson		return (error);
1725145234Srwatson#ifdef MAC
1726145234Srwatson	if ((error = mac_check_proc_wait(td->td_ucred, p)))
1727145234Srwatson		return (error);
1728145234Srwatson#endif
1729145234Srwatson#if 0
1730145234Srwatson	/* XXXMAC: This could have odd effects on some shells. */
1731145234Srwatson	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
1732145234Srwatson		return (error);
1733145234Srwatson#endif
1734145234Srwatson
1735145234Srwatson	return (0);
1736145234Srwatson}
1737145234Srwatson
173853518Sphk/*
17391541Srgrimes * Allocate a zeroed cred structure.
17401541Srgrimes */
17411541Srgrimesstruct ucred *
174293580Sjhbcrget(void)
17431541Srgrimes{
17441541Srgrimes	register struct ucred *cr;
17451541Srgrimes
1746111119Simp	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1747150634Sjhb	refcount_init(&cr->cr_ref, 1);
1748170407Srwatson#ifdef AUDIT
1749170407Srwatson	audit_cred_init(cr);
1750170407Srwatson#endif
1751101001Srwatson#ifdef MAC
1752101001Srwatson	mac_init_cred(cr);
1753101001Srwatson#endif
17541541Srgrimes	return (cr);
17551541Srgrimes}
17561541Srgrimes
17571541Srgrimes/*
175882466Srwatson * Claim another reference to a ucred structure.
175969401Salfred */
176084827Sjhbstruct ucred *
176193580Sjhbcrhold(struct ucred *cr)
176269401Salfred{
176369401Salfred
1764150634Sjhb	refcount_acquire(&cr->cr_ref);
176584827Sjhb	return (cr);
176669401Salfred}
176769401Salfred
176869401Salfred/*
1769167211Srwatson * Free a cred structure.  Throws away space when ref count gets to 0.
17701541Srgrimes */
17711549Srgrimesvoid
177293580Sjhbcrfree(struct ucred *cr)
17731541Srgrimes{
177469239Salfred
177575632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1776150634Sjhb	KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred"));
1777150634Sjhb	if (refcount_release(&cr->cr_ref)) {
177865495Struckman		/*
177965495Struckman		 * Some callers of crget(), such as nfs_statfs(),
178065495Struckman		 * allocate a temporary credential, but don't
178165495Struckman		 * allocate a uidinfo structure.
178265495Struckman		 */
178365495Struckman		if (cr->cr_uidinfo != NULL)
178465495Struckman			uifree(cr->cr_uidinfo);
178577277Srwatson		if (cr->cr_ruidinfo != NULL)
178677277Srwatson			uifree(cr->cr_ruidinfo);
178772786Srwatson		/*
178872786Srwatson		 * Free a prison, if any.
178972786Srwatson		 */
179072786Srwatson		if (jailed(cr))
179172786Srwatson			prison_free(cr->cr_prison);
1792170407Srwatson#ifdef AUDIT
1793170407Srwatson		audit_cred_destroy(cr);
1794170407Srwatson#endif
1795101001Srwatson#ifdef MAC
1796101001Srwatson		mac_destroy_cred(cr);
1797101001Srwatson#endif
179899009Salfred		FREE(cr, M_CRED);
179990756Sdillon	}
18001541Srgrimes}
18011541Srgrimes
18021541Srgrimes/*
180384827Sjhb * Check to see if this ucred is shared.
18041541Srgrimes */
180584827Sjhbint
180693580Sjhbcrshared(struct ucred *cr)
18071541Srgrimes{
18081541Srgrimes
1809150634Sjhb	return (cr->cr_ref > 1);
18101541Srgrimes}
18111541Srgrimes
18121541Srgrimes/*
181384827Sjhb * Copy a ucred's contents from a template.  Does not block.
181484827Sjhb */
181584827Sjhbvoid
181693580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
181784827Sjhb{
181884827Sjhb
181984827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
182084827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
182187218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
182284827Sjhb		(caddr_t)&src->cr_startcopy));
182384827Sjhb	uihold(dest->cr_uidinfo);
182484827Sjhb	uihold(dest->cr_ruidinfo);
182584827Sjhb	if (jailed(dest))
182684827Sjhb		prison_hold(dest->cr_prison);
1827170407Srwatson#ifdef AUDIT
1828170407Srwatson	audit_cred_copy(src, dest);
1829170407Srwatson#endif
1830101001Srwatson#ifdef MAC
1831123173Srwatson	mac_copy_cred(src, dest);
1832101001Srwatson#endif
183384827Sjhb}
183484827Sjhb
183584827Sjhb/*
18361541Srgrimes * Dup cred struct to a new held one.
18371541Srgrimes */
18381541Srgrimesstruct ucred *
183993580Sjhbcrdup(struct ucred *cr)
18401541Srgrimes{
18411541Srgrimes	struct ucred *newcr;
18421541Srgrimes
184384827Sjhb	newcr = crget();
184484827Sjhb	crcopy(newcr, cr);
18451541Srgrimes	return (newcr);
18461541Srgrimes}
18471541Srgrimes
18481541Srgrimes/*
184991354Sdd * Fill in a struct xucred based on a struct ucred.
185091354Sdd */
185191354Sddvoid
185293580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
185391354Sdd{
185491354Sdd
185591354Sdd	bzero(xcr, sizeof(*xcr));
185691354Sdd	xcr->cr_version = XUCRED_VERSION;
185791354Sdd	xcr->cr_uid = cr->cr_uid;
185891354Sdd	xcr->cr_ngroups = cr->cr_ngroups;
185991354Sdd	bcopy(cr->cr_groups, xcr->cr_groups, sizeof(cr->cr_groups));
186091354Sdd}
186191354Sdd
186291354Sdd/*
1863167211Srwatson * small routine to swap a thread's current ucred for the correct one taken
1864167211Srwatson * from the process.
186590748Sjulian */
186690748Sjulianvoid
186790748Sjuliancred_update_thread(struct thread *td)
186890748Sjulian{
186990748Sjulian	struct proc *p;
187091405Sjhb	struct ucred *cred;
187190748Sjulian
187290748Sjulian	p = td->td_proc;
187391405Sjhb	cred = td->td_ucred;
187490748Sjulian	PROC_LOCK(p);
187590748Sjulian	td->td_ucred = crhold(p->p_ucred);
187690748Sjulian	PROC_UNLOCK(p);
187791405Sjhb	if (cred != NULL)
187891405Sjhb		crfree(cred);
187990748Sjulian}
188090748Sjulian
188190748Sjulian/*
18821541Srgrimes * Get login name, if available.
18831541Srgrimes */
188412221Sbde#ifndef _SYS_SYSPROTO_H_
18851541Srgrimesstruct getlogin_args {
18861541Srgrimes	char	*namebuf;
18871541Srgrimes	u_int	namelen;
18881541Srgrimes};
188912221Sbde#endif
18901541Srgrimes/* ARGSUSED */
18911549Srgrimesint
189293580Sjhbgetlogin(struct thread *td, struct getlogin_args *uap)
18931541Srgrimes{
189482749Sdillon	int error;
189591140Stanimura	char login[MAXLOGNAME];
189683366Sjulian	struct proc *p = td->td_proc;
18971541Srgrimes
189823358Sache	if (uap->namelen > MAXLOGNAME)
189923359Sache		uap->namelen = MAXLOGNAME;
190091140Stanimura	PROC_LOCK(p);
190191140Stanimura	SESS_LOCK(p->p_session);
190291140Stanimura	bcopy(p->p_session->s_login, login, uap->namelen);
190391140Stanimura	SESS_UNLOCK(p->p_session);
190491140Stanimura	PROC_UNLOCK(p);
190599009Salfred	error = copyout(login, uap->namebuf, uap->namelen);
190682749Sdillon	return(error);
19071541Srgrimes}
19081541Srgrimes
19091541Srgrimes/*
19101541Srgrimes * Set login name.
19111541Srgrimes */
191212221Sbde#ifndef _SYS_SYSPROTO_H_
19131541Srgrimesstruct setlogin_args {
19141541Srgrimes	char	*namebuf;
19151541Srgrimes};
191612221Sbde#endif
19171541Srgrimes/* ARGSUSED */
19181549Srgrimesint
191993580Sjhbsetlogin(struct thread *td, struct setlogin_args *uap)
19201541Srgrimes{
192183366Sjulian	struct proc *p = td->td_proc;
19221541Srgrimes	int error;
192323330Sache	char logintmp[MAXLOGNAME];
19241541Srgrimes
1925170587Srwatson	error = priv_check(td, PRIV_PROC_SETLOGIN);
192694619Sjhb	if (error)
192794619Sjhb		return (error);
192899009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
192987218Srwatson	if (error == ENAMETOOLONG)
19301541Srgrimes		error = EINVAL;
193191140Stanimura	else if (!error) {
193291140Stanimura		PROC_LOCK(p);
193391140Stanimura		SESS_LOCK(p->p_session);
193491140Stanimura		(void) memcpy(p->p_session->s_login, logintmp,
193523330Sache		    sizeof(logintmp));
193691140Stanimura		SESS_UNLOCK(p->p_session);
193791140Stanimura		PROC_UNLOCK(p);
193891140Stanimura	}
19391541Srgrimes	return (error);
19401541Srgrimes}
194131891Ssef
194231891Ssefvoid
194393580Sjhbsetsugid(struct proc *p)
194431891Ssef{
194598403Salfred
194698403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
194731891Ssef	p->p_flag |= P_SUGID;
194855707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
194931891Ssef		p->p_stops = 0;
195031891Ssef}
195165495Struckman
195282466Srwatson/*-
195382466Srwatson * Change a process's effective uid.
195477183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
195577183Srwatson * References: newcred must be an exclusive credential reference for the
195677183Srwatson *             duration of the call.
195765495Struckman */
195865495Struckmanvoid
195998417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
196065495Struckman{
196165495Struckman
196298417Salfred	newcred->cr_uid = euip->ui_uid;
196398417Salfred	uihold(euip);
196477183Srwatson	uifree(newcred->cr_uidinfo);
196598417Salfred	newcred->cr_uidinfo = euip;
196665495Struckman}
196765495Struckman
196882466Srwatson/*-
196982466Srwatson * Change a process's effective gid.
197077183Srwatson * Side effects: newcred->cr_gid will be modified.
197177183Srwatson * References: newcred must be an exclusive credential reference for the
197277183Srwatson *             duration of the call.
197365495Struckman */
197467629Sgallatinvoid
197593580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
197665495Struckman{
197765495Struckman
197877183Srwatson	newcred->cr_groups[0] = egid;
197965495Struckman}
198077183Srwatson
198182466Srwatson/*-
198282466Srwatson * Change a process's real uid.
198377183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
198477183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
198577183Srwatson *               counts will be updated.
198677183Srwatson * References: newcred must be an exclusive credential reference for the
198777183Srwatson *             duration of the call.
198877183Srwatson */
198977183Srwatsonvoid
199098417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
199177183Srwatson{
199277183Srwatson
199377183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
199498417Salfred	newcred->cr_ruid = ruip->ui_uid;
199598417Salfred	uihold(ruip);
199677183Srwatson	uifree(newcred->cr_ruidinfo);
199798417Salfred	newcred->cr_ruidinfo = ruip;
199877183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
199977183Srwatson}
200077183Srwatson
200182466Srwatson/*-
200282466Srwatson * Change a process's real gid.
200377183Srwatson * Side effects: newcred->cr_rgid will be updated.
200477183Srwatson * References: newcred must be an exclusive credential reference for the
200577183Srwatson *             duration of the call.
200677183Srwatson */
200777183Srwatsonvoid
200893580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
200977183Srwatson{
201077183Srwatson
201177183Srwatson	newcred->cr_rgid = rgid;
201277183Srwatson}
201377183Srwatson
201482466Srwatson/*-
201582466Srwatson * Change a process's saved uid.
201677183Srwatson * Side effects: newcred->cr_svuid will be updated.
201777183Srwatson * References: newcred must be an exclusive credential reference for the
201877183Srwatson *             duration of the call.
201977183Srwatson */
202077183Srwatsonvoid
202193580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
202277183Srwatson{
202377183Srwatson
202477183Srwatson	newcred->cr_svuid = svuid;
202577183Srwatson}
202677183Srwatson
202782466Srwatson/*-
202882466Srwatson * Change a process's saved gid.
202977183Srwatson * Side effects: newcred->cr_svgid will be updated.
203077183Srwatson * References: newcred must be an exclusive credential reference for the
203177183Srwatson *             duration of the call.
203277183Srwatson */
203377183Srwatsonvoid
203493580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
203577183Srwatson{
203677183Srwatson
203777183Srwatson	newcred->cr_svgid = svgid;
203877183Srwatson}
2039