kern_prot.c revision 277698
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: stable/10/sys/kern/kern_prot.c 277698 2015-01-25 13:15:12Z kib $");
46116182Sobrien
4731778Seivind#include "opt_compat.h"
48183982Sbz#include "opt_inet.h"
49183982Sbz#include "opt_inet6.h"
5031778Seivind
511541Srgrimes#include <sys/param.h>
5276166Smarkm#include <sys/systm.h>
531541Srgrimes#include <sys/acct.h>
54132548Srwatson#include <sys/kdb.h>
5541059Speter#include <sys/kernel.h>
5670317Sjake#include <sys/lock.h>
57219304Strasz#include <sys/loginclass.h>
5891140Stanimura#include <sys/malloc.h>
5976166Smarkm#include <sys/mutex.h>
60150634Sjhb#include <sys/refcount.h>
6191140Stanimura#include <sys/sx.h>
62164032Srwatson#include <sys/priv.h>
631541Srgrimes#include <sys/proc.h>
6476166Smarkm#include <sys/sysproto.h>
6587218Srwatson#include <sys/jail.h>
6631891Ssef#include <sys/pioctl.h>
67220212Strasz#include <sys/racct.h>
6865495Struckman#include <sys/resourcevar.h>
6992976Srwatson#include <sys/socket.h>
7092976Srwatson#include <sys/socketvar.h>
71160139Sjhb#include <sys/syscallsubr.h>
7261287Srwatson#include <sys/sysctl.h>
731541Srgrimes
74219028Snetchild#ifdef REGRESSION
75219028SnetchildFEATURE(regression,
76229818Shrs    "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)");
77219028Snetchild#endif
78219028Snetchild
79183982Sbz#if defined(INET) || defined(INET6)
80183982Sbz#include <netinet/in.h>
81183982Sbz#include <netinet/in_pcb.h>
82183982Sbz#endif
83183982Sbz
84155370Swsalamon#include <security/audit/audit.h>
85163606Srwatson#include <security/mac/mac_framework.h>
86155370Swsalamon
8730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials");
8830354Sphk
89162383SrwatsonSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy");
9087138Srwatson
91194498Sbrooksstatic void crextend(struct ucred *cr, int n);
92194498Sbrooksstatic void crsetgroups_locked(struct ucred *cr, int ngrp,
93194498Sbrooks    gid_t *groups);
94194498Sbrooks
9512221Sbde#ifndef _SYS_SYSPROTO_H_
9611332Sswallacestruct getpid_args {
971541Srgrimes	int	dummy;
981541Srgrimes};
9912221Sbde#endif
1001541Srgrimes/* ARGSUSED */
1011549Srgrimesint
102225617Skmacysys_getpid(struct thread *td, struct getpid_args *uap)
1031541Srgrimes{
10483366Sjulian	struct proc *p = td->td_proc;
1051541Srgrimes
10683366Sjulian	td->td_retval[0] = p->p_pid;
107130344Sphk#if defined(COMPAT_43)
10874728Sjhb	PROC_LOCK(p);
10983366Sjulian	td->td_retval[1] = p->p_pptr->p_pid;
11074728Sjhb	PROC_UNLOCK(p);
1111541Srgrimes#endif
1121541Srgrimes	return (0);
1131541Srgrimes}
1141541Srgrimes
11512221Sbde#ifndef _SYS_SYSPROTO_H_
11611332Sswallacestruct getppid_args {
11711332Sswallace        int     dummy;
11811332Sswallace};
11912221Sbde#endif
1201541Srgrimes/* ARGSUSED */
1211549Srgrimesint
122225617Skmacysys_getppid(struct thread *td, struct getppid_args *uap)
1231541Srgrimes{
12483366Sjulian	struct proc *p = td->td_proc;
1251541Srgrimes
12674728Sjhb	PROC_LOCK(p);
12783366Sjulian	td->td_retval[0] = p->p_pptr->p_pid;
12874728Sjhb	PROC_UNLOCK(p);
1291541Srgrimes	return (0);
1301541Srgrimes}
1311541Srgrimes
13287466Srwatson/*
13387218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter.
13458717Sdillon */
13512221Sbde#ifndef _SYS_SYSPROTO_H_
13611332Sswallacestruct getpgrp_args {
13711332Sswallace        int     dummy;
13811332Sswallace};
13912221Sbde#endif
1401549Srgrimesint
141225617Skmacysys_getpgrp(struct thread *td, struct getpgrp_args *uap)
1421541Srgrimes{
14383366Sjulian	struct proc *p = td->td_proc;
1441541Srgrimes
14591140Stanimura	PROC_LOCK(p);
14683366Sjulian	td->td_retval[0] = p->p_pgrp->pg_id;
14791140Stanimura	PROC_UNLOCK(p);
1481541Srgrimes	return (0);
1491541Srgrimes}
1501541Srgrimes
15128401Speter/* Get an arbitary pid's process group id */
15212221Sbde#ifndef _SYS_SYSPROTO_H_
15328401Speterstruct getpgid_args {
15428401Speter	pid_t	pid;
15528401Speter};
15628401Speter#endif
15728401Speterint
158225617Skmacysys_getpgid(struct thread *td, struct getpgid_args *uap)
15928401Speter{
160114031Sjhb	struct proc *p;
16192985Sjhb	int error;
16241726Struckman
16391140Stanimura	if (uap->pid == 0) {
164114031Sjhb		p = td->td_proc;
16591140Stanimura		PROC_LOCK(p);
166114031Sjhb	} else {
167114031Sjhb		p = pfind(uap->pid);
168114031Sjhb		if (p == NULL)
169114031Sjhb			return (ESRCH);
170114031Sjhb		error = p_cansee(td, p);
171114031Sjhb		if (error) {
172114031Sjhb			PROC_UNLOCK(p);
173114031Sjhb			return (error);
174114031Sjhb		}
17575893Sjhb	}
176114031Sjhb	td->td_retval[0] = p->p_pgrp->pg_id;
177114031Sjhb	PROC_UNLOCK(p);
178114031Sjhb	return (0);
17928401Speter}
18028401Speter
18128401Speter/*
18228401Speter * Get an arbitary pid's session id.
18328401Speter */
18428401Speter#ifndef _SYS_SYSPROTO_H_
18528401Speterstruct getsid_args {
18628401Speter	pid_t	pid;
18728401Speter};
18828401Speter#endif
18928401Speterint
190225617Skmacysys_getsid(struct thread *td, struct getsid_args *uap)
19128401Speter{
192114031Sjhb	struct proc *p;
19387218Srwatson	int error;
19441726Struckman
19591140Stanimura	if (uap->pid == 0) {
196114031Sjhb		p = td->td_proc;
19791140Stanimura		PROC_LOCK(p);
198114031Sjhb	} else {
199114031Sjhb		p = pfind(uap->pid);
200114031Sjhb		if (p == NULL)
201114031Sjhb			return (ESRCH);
202114031Sjhb		error = p_cansee(td, p);
203114031Sjhb		if (error) {
204114031Sjhb			PROC_UNLOCK(p);
205114031Sjhb			return (error);
206114031Sjhb		}
20775893Sjhb	}
208114031Sjhb	td->td_retval[0] = p->p_session->s_sid;
209114031Sjhb	PROC_UNLOCK(p);
210114031Sjhb	return (0);
21128401Speter}
21228401Speter
21328401Speter#ifndef _SYS_SYSPROTO_H_
21411332Sswallacestruct getuid_args {
21511332Sswallace        int     dummy;
21611332Sswallace};
21712221Sbde#endif
2181541Srgrimes/* ARGSUSED */
2191549Srgrimesint
220225617Skmacysys_getuid(struct thread *td, struct getuid_args *uap)
2211541Srgrimes{
2221541Srgrimes
22392987Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
224130344Sphk#if defined(COMPAT_43)
22592987Sjhb	td->td_retval[1] = td->td_ucred->cr_uid;
2261541Srgrimes#endif
2271541Srgrimes	return (0);
2281541Srgrimes}
2291541Srgrimes
23012221Sbde#ifndef _SYS_SYSPROTO_H_
23111332Sswallacestruct geteuid_args {
23211332Sswallace        int     dummy;
23311332Sswallace};
23412221Sbde#endif
2351541Srgrimes/* ARGSUSED */
2361549Srgrimesint
237225617Skmacysys_geteuid(struct thread *td, struct geteuid_args *uap)
2381541Srgrimes{
23992987Sjhb
24092987Sjhb	td->td_retval[0] = td->td_ucred->cr_uid;
2411541Srgrimes	return (0);
2421541Srgrimes}
2431541Srgrimes
24412221Sbde#ifndef _SYS_SYSPROTO_H_
24511332Sswallacestruct getgid_args {
24611332Sswallace        int     dummy;
24711332Sswallace};
24812221Sbde#endif
2491541Srgrimes/* ARGSUSED */
2501549Srgrimesint
251225617Skmacysys_getgid(struct thread *td, struct getgid_args *uap)
2521541Srgrimes{
2531541Srgrimes
25492987Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
255130344Sphk#if defined(COMPAT_43)
25692987Sjhb	td->td_retval[1] = td->td_ucred->cr_groups[0];
2571541Srgrimes#endif
2581541Srgrimes	return (0);
2591541Srgrimes}
2601541Srgrimes
2611541Srgrimes/*
2621541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
2631541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
2641541Srgrimes * correctly in a library function.
2651541Srgrimes */
26612221Sbde#ifndef _SYS_SYSPROTO_H_
26711332Sswallacestruct getegid_args {
26811332Sswallace        int     dummy;
26911332Sswallace};
27012221Sbde#endif
2711541Srgrimes/* ARGSUSED */
2721549Srgrimesint
273225617Skmacysys_getegid(struct thread *td, struct getegid_args *uap)
2741541Srgrimes{
2751541Srgrimes
27692987Sjhb	td->td_retval[0] = td->td_ucred->cr_groups[0];
2771541Srgrimes	return (0);
2781541Srgrimes}
2791541Srgrimes
28012221Sbde#ifndef _SYS_SYSPROTO_H_
2811541Srgrimesstruct getgroups_args {
2821541Srgrimes	u_int	gidsetsize;
2831541Srgrimes	gid_t	*gidset;
2841541Srgrimes};
28512221Sbde#endif
2861549Srgrimesint
287225617Skmacysys_getgroups(struct thread *td, register struct getgroups_args *uap)
2881541Srgrimes{
289194498Sbrooks	gid_t *groups;
29077183Srwatson	u_int ngrp;
29187218Srwatson	int error;
2921541Srgrimes
293202342Sbrooks	if (uap->gidsetsize < td->td_ucred->cr_ngroups) {
294202342Sbrooks		if (uap->gidsetsize == 0)
295202342Sbrooks			ngrp = 0;
296202342Sbrooks		else
297202342Sbrooks			return (EINVAL);
298202342Sbrooks	} else
299202342Sbrooks		ngrp = td->td_ucred->cr_ngroups;
300194498Sbrooks	groups = malloc(ngrp * sizeof(*groups), M_TEMP, M_WAITOK);
301160139Sjhb	error = kern_getgroups(td, &ngrp, groups);
302160139Sjhb	if (error)
303194498Sbrooks		goto out;
304160139Sjhb	if (uap->gidsetsize > 0)
305160139Sjhb		error = copyout(groups, uap->gidset, ngrp * sizeof(gid_t));
306160139Sjhb	if (error == 0)
307160139Sjhb		td->td_retval[0] = ngrp;
308194498Sbrooksout:
309194498Sbrooks	free(groups, M_TEMP);
310160139Sjhb	return (error);
311160139Sjhb}
312160139Sjhb
313160139Sjhbint
314160139Sjhbkern_getgroups(struct thread *td, u_int *ngrp, gid_t *groups)
315160139Sjhb{
316160139Sjhb	struct ucred *cred;
317160139Sjhb
31892987Sjhb	cred = td->td_ucred;
319160139Sjhb	if (*ngrp == 0) {
320160139Sjhb		*ngrp = cred->cr_ngroups;
32192987Sjhb		return (0);
3221541Srgrimes	}
323160139Sjhb	if (*ngrp < cred->cr_ngroups)
32492987Sjhb		return (EINVAL);
325160139Sjhb	*ngrp = cred->cr_ngroups;
326160139Sjhb	bcopy(cred->cr_groups, groups, *ngrp * sizeof(gid_t));
327160139Sjhb	return (0);
3281541Srgrimes}
3291541Srgrimes
33012221Sbde#ifndef _SYS_SYSPROTO_H_
33112207Sbdestruct setsid_args {
33211332Sswallace        int     dummy;
33311332Sswallace};
33412221Sbde#endif
3351541Srgrimes/* ARGSUSED */
3361549Srgrimesint
337225617Skmacysys_setsid(register struct thread *td, struct setsid_args *uap)
3381541Srgrimes{
33991140Stanimura	struct pgrp *pgrp;
34082749Sdillon	int error;
34183366Sjulian	struct proc *p = td->td_proc;
34291140Stanimura	struct pgrp *newpgrp;
34391140Stanimura	struct session *newsess;
3441541Srgrimes
34591140Stanimura	error = 0;
34691140Stanimura	pgrp = NULL;
34791140Stanimura
348184205Sdes	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
349184205Sdes	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
35091140Stanimura
35194859Sjhb	sx_xlock(&proctree_lock);
35291140Stanimura
35391140Stanimura	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
35491140Stanimura		if (pgrp != NULL)
35591140Stanimura			PGRP_UNLOCK(pgrp);
35682749Sdillon		error = EPERM;
35791140Stanimura	} else {
35891140Stanimura		(void)enterpgrp(p, p->p_pid, newpgrp, newsess);
35983366Sjulian		td->td_retval[0] = p->p_pid;
36094859Sjhb		newpgrp = NULL;
36194859Sjhb		newsess = NULL;
3621541Srgrimes	}
36391140Stanimura
36494859Sjhb	sx_xunlock(&proctree_lock);
36591140Stanimura
36695973Stanimura	if (newpgrp != NULL)
367184205Sdes		free(newpgrp, M_PGRP);
36895973Stanimura	if (newsess != NULL)
369184205Sdes		free(newsess, M_SESSION);
37091140Stanimura
37194859Sjhb	return (error);
3721541Srgrimes}
3731541Srgrimes
3741541Srgrimes/*
3751541Srgrimes * set process group (setpgid/old setpgrp)
3761541Srgrimes *
3771541Srgrimes * caller does setpgid(targpid, targpgid)
3781541Srgrimes *
3791541Srgrimes * pid must be caller or child of caller (ESRCH)
3801541Srgrimes * if a child
3811541Srgrimes *	pid must be in same session (EPERM)
3821541Srgrimes *	pid can't have done an exec (EACCES)
3831541Srgrimes * if pgid != pid
3841541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
3851541Srgrimes * pid must not be session leader (EPERM)
3861541Srgrimes */
38712221Sbde#ifndef _SYS_SYSPROTO_H_
3881541Srgrimesstruct setpgid_args {
38987218Srwatson	int	pid;		/* target process id */
39087218Srwatson	int	pgid;		/* target pgrp id */
3911541Srgrimes};
39212221Sbde#endif
3931541Srgrimes/* ARGSUSED */
3941549Srgrimesint
395225617Skmacysys_setpgid(struct thread *td, register struct setpgid_args *uap)
3961541Srgrimes{
39783366Sjulian	struct proc *curp = td->td_proc;
39887218Srwatson	register struct proc *targp;	/* target process */
39987218Srwatson	register struct pgrp *pgrp;	/* target pgrp */
40075448Srwatson	int error;
40191140Stanimura	struct pgrp *newpgrp;
4021541Srgrimes
40320677Sbde	if (uap->pgid < 0)
40420677Sbde		return (EINVAL);
40591140Stanimura
40691140Stanimura	error = 0;
40791140Stanimura
408184205Sdes	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
40991140Stanimura
41094859Sjhb	sx_xlock(&proctree_lock);
4111541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
41291140Stanimura		if ((targp = pfind(uap->pid)) == NULL) {
41382749Sdillon			error = ESRCH;
41494859Sjhb			goto done;
41575893Sjhb		}
41691140Stanimura		if (!inferior(targp)) {
41791140Stanimura			PROC_UNLOCK(targp);
41891371Stanimura			error = ESRCH;
41994859Sjhb			goto done;
42091140Stanimura		}
421132568Srwatson		if ((error = p_cansee(td, targp))) {
42275893Sjhb			PROC_UNLOCK(targp);
42394859Sjhb			goto done;
42475893Sjhb		}
42575893Sjhb		if (targp->p_pgrp == NULL ||
42675893Sjhb		    targp->p_session != curp->p_session) {
42775893Sjhb			PROC_UNLOCK(targp);
42882749Sdillon			error = EPERM;
42994859Sjhb			goto done;
43075893Sjhb		}
43175893Sjhb		if (targp->p_flag & P_EXEC) {
43275893Sjhb			PROC_UNLOCK(targp);
43382749Sdillon			error = EACCES;
43494859Sjhb			goto done;
43575893Sjhb		}
43691140Stanimura		PROC_UNLOCK(targp);
43791140Stanimura	} else
4381541Srgrimes		targp = curp;
43975893Sjhb	if (SESS_LEADER(targp)) {
44082749Sdillon		error = EPERM;
44194859Sjhb		goto done;
44275893Sjhb	}
44387218Srwatson	if (uap->pgid == 0)
4441541Srgrimes		uap->pgid = targp->p_pid;
445117214Scognet	if ((pgrp = pgfind(uap->pgid)) == NULL) {
446117214Scognet		if (uap->pgid == targp->p_pid) {
447117214Scognet			error = enterpgrp(targp, uap->pgid, newpgrp,
448117214Scognet			    NULL);
449117214Scognet			if (error == 0)
450117214Scognet				newpgrp = NULL;
451117214Scognet		} else
452117214Scognet			error = EPERM;
45391140Stanimura	} else {
454117214Scognet		if (pgrp == targp->p_pgrp) {
455117214Scognet			PGRP_UNLOCK(pgrp);
45694859Sjhb			goto done;
45775893Sjhb		}
458117214Scognet		if (pgrp->pg_id != targp->p_pid &&
459117214Scognet		    pgrp->pg_session != curp->p_session) {
46091140Stanimura			PGRP_UNLOCK(pgrp);
461117214Scognet			error = EPERM;
46291140Stanimura			goto done;
46391140Stanimura		}
46491140Stanimura		PGRP_UNLOCK(pgrp);
46591140Stanimura		error = enterthispgrp(targp, pgrp);
46682749Sdillon	}
46791140Stanimuradone:
46894859Sjhb	sx_xunlock(&proctree_lock);
46994859Sjhb	KASSERT((error == 0) || (newpgrp != NULL),
47094859Sjhb	    ("setpgid failed and newpgrp is NULL"));
47195973Stanimura	if (newpgrp != NULL)
472184205Sdes		free(newpgrp, M_PGRP);
47382749Sdillon	return (error);
4741541Srgrimes}
4751541Srgrimes
47624448Speter/*
47724448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
47872093Sasmodai * compatible.  It says that setting the uid/gid to euid/egid is a special
47924448Speter * case of "appropriate privilege".  Once the rules are expanded out, this
48024448Speter * basically means that setuid(nnn) sets all three id's, in all permitted
48124448Speter * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
48224448Speter * does not set the saved id - this is dangerous for traditional BSD
48324448Speter * programs.  For this reason, we *really* do not want to set
48424448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
48524448Speter */
48624448Speter#define POSIX_APPENDIX_B_4_2_2
48724448Speter
48812221Sbde#ifndef _SYS_SYSPROTO_H_
4891541Srgrimesstruct setuid_args {
4901541Srgrimes	uid_t	uid;
4911541Srgrimes};
49212221Sbde#endif
4931541Srgrimes/* ARGSUSED */
4941549Srgrimesint
495225617Skmacysys_setuid(struct thread *td, struct setuid_args *uap)
4961541Srgrimes{
49783366Sjulian	struct proc *p = td->td_proc;
49877183Srwatson	struct ucred *newcred, *oldcred;
49977183Srwatson	uid_t uid;
50098417Salfred	struct uidinfo *uip;
50187218Srwatson	int error;
5021541Srgrimes
50377183Srwatson	uid = uap->uid;
504195104Srwatson	AUDIT_ARG_UID(uid);
50594619Sjhb	newcred = crget();
50698417Salfred	uip = uifind(uid);
50794619Sjhb	PROC_LOCK(p);
508194498Sbrooks	/*
509194498Sbrooks	 * Copy credentials so other references do not see our changes.
510194498Sbrooks	 */
511194498Sbrooks	oldcred = crcopysafe(p, newcred);
51287466Srwatson
513145147Srwatson#ifdef MAC
514189529Srwatson	error = mac_cred_check_setuid(oldcred, uid);
515145147Srwatson	if (error)
516145147Srwatson		goto fail;
517145147Srwatson#endif
518145147Srwatson
51924448Speter	/*
52024448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
52124448Speter	 *
52287218Srwatson	 * Note that setuid(geteuid()) is a special case of
52324448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
52472093Sasmodai	 * to use this clause to be compatible with traditional BSD
52524448Speter	 * semantics.  Basically, it means that "setuid(xx)" sets all
52624448Speter	 * three id's (assuming you have privs).
52724448Speter	 *
52824448Speter	 * Notes on the logic.  We do things in three steps.
52924448Speter	 * 1: We determine if the euid is going to change, and do EPERM
53024448Speter	 *    right away.  We unconditionally change the euid later if this
53124448Speter	 *    test is satisfied, simplifying that part of the logic.
53287218Srwatson	 * 2: We determine if the real and/or saved uids are going to
53324448Speter	 *    change.  Determined by compile options.
53424448Speter	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
53524448Speter	 */
53677183Srwatson	if (uid != oldcred->cr_ruid &&		/* allow setuid(getuid()) */
53717994Sache#ifdef _POSIX_SAVED_IDS
53877183Srwatson	    uid != oldcred->cr_svuid &&		/* allow setuid(saved gid) */
53917994Sache#endif
54024448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
54177183Srwatson	    uid != oldcred->cr_uid &&		/* allow setuid(geteuid()) */
54224448Speter#endif
543170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETUID, 0)) != 0)
544145147Srwatson		goto fail;
54524448Speter
54624448Speter#ifdef _POSIX_SAVED_IDS
5471541Srgrimes	/*
54824448Speter	 * Do we have "appropriate privileges" (are we root or uid == euid)
54924448Speter	 * If so, we are changing the real uid and/or saved uid.
5501541Srgrimes	 */
55117994Sache	if (
55224448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
55377183Srwatson	    uid == oldcred->cr_uid ||
55417994Sache#endif
555164032Srwatson	    /* We are using privs. */
556170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETUID, 0) == 0)
55717994Sache#endif
55824448Speter	{
55924448Speter		/*
56065495Struckman		 * Set the real uid and transfer proc count to new user.
56124448Speter		 */
56277183Srwatson		if (uid != oldcred->cr_ruid) {
56398417Salfred			change_ruid(newcred, uip);
56465495Struckman			setsugid(p);
56524448Speter		}
56624448Speter		/*
56724448Speter		 * Set saved uid
56824448Speter		 *
56924448Speter		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
57024448Speter		 * the security of seteuid() depends on it.  B.4.2.2 says it
57124448Speter		 * is important that we should do this.
57224448Speter		 */
57377183Srwatson		if (uid != oldcred->cr_svuid) {
57477183Srwatson			change_svuid(newcred, uid);
57531891Ssef			setsugid(p);
57624448Speter		}
5778141Sache	}
57824448Speter
57924448Speter	/*
58024448Speter	 * In all permitted cases, we are changing the euid.
58124448Speter	 */
58277183Srwatson	if (uid != oldcred->cr_uid) {
58398417Salfred		change_euid(newcred, uip);
58431891Ssef		setsugid(p);
58524448Speter	}
58677183Srwatson	p->p_ucred = newcred;
58794619Sjhb	PROC_UNLOCK(p);
588220212Strasz#ifdef RACCT
589220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
590220212Strasz#endif
59198417Salfred	uifree(uip);
59277183Srwatson	crfree(oldcred);
59394619Sjhb	return (0);
594145147Srwatson
595145147Srwatsonfail:
596145147Srwatson	PROC_UNLOCK(p);
597145147Srwatson	uifree(uip);
598145147Srwatson	crfree(newcred);
599145147Srwatson	return (error);
6001541Srgrimes}
6011541Srgrimes
60212221Sbde#ifndef _SYS_SYSPROTO_H_
6031541Srgrimesstruct seteuid_args {
6041541Srgrimes	uid_t	euid;
6051541Srgrimes};
60612221Sbde#endif
6071541Srgrimes/* ARGSUSED */
6081549Srgrimesint
609225617Skmacysys_seteuid(struct thread *td, struct seteuid_args *uap)
6101541Srgrimes{
61183366Sjulian	struct proc *p = td->td_proc;
61277183Srwatson	struct ucred *newcred, *oldcred;
61377183Srwatson	uid_t euid;
61498417Salfred	struct uidinfo *euip;
61587218Srwatson	int error;
6161541Srgrimes
6171541Srgrimes	euid = uap->euid;
618195104Srwatson	AUDIT_ARG_EUID(euid);
61994619Sjhb	newcred = crget();
62098417Salfred	euip = uifind(euid);
62194619Sjhb	PROC_LOCK(p);
622194498Sbrooks	/*
623194498Sbrooks	 * Copy credentials so other references do not see our changes.
624194498Sbrooks	 */
625194498Sbrooks	oldcred = crcopysafe(p, newcred);
626145147Srwatson
627145147Srwatson#ifdef MAC
628189529Srwatson	error = mac_cred_check_seteuid(oldcred, euid);
629145147Srwatson	if (error)
630145147Srwatson		goto fail;
631145147Srwatson#endif
632145147Srwatson
63377183Srwatson	if (euid != oldcred->cr_ruid &&		/* allow seteuid(getuid()) */
63477183Srwatson	    euid != oldcred->cr_svuid &&	/* allow seteuid(saved uid) */
635170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEUID, 0)) != 0)
636145147Srwatson		goto fail;
637145147Srwatson
6381541Srgrimes	/*
639194498Sbrooks	 * Everything's okay, do it.
6401541Srgrimes	 */
64177183Srwatson	if (oldcred->cr_uid != euid) {
64298417Salfred		change_euid(newcred, euip);
64331891Ssef		setsugid(p);
64424449Speter	}
64577183Srwatson	p->p_ucred = newcred;
64694619Sjhb	PROC_UNLOCK(p);
64798417Salfred	uifree(euip);
64877183Srwatson	crfree(oldcred);
64994619Sjhb	return (0);
650145147Srwatson
651145147Srwatsonfail:
652145147Srwatson	PROC_UNLOCK(p);
653145147Srwatson	uifree(euip);
654145147Srwatson	crfree(newcred);
655145147Srwatson	return (error);
6561541Srgrimes}
6571541Srgrimes
65812221Sbde#ifndef _SYS_SYSPROTO_H_
6591541Srgrimesstruct setgid_args {
6601541Srgrimes	gid_t	gid;
6611541Srgrimes};
66212221Sbde#endif
6631541Srgrimes/* ARGSUSED */
6641549Srgrimesint
665225617Skmacysys_setgid(struct thread *td, struct setgid_args *uap)
6661541Srgrimes{
66783366Sjulian	struct proc *p = td->td_proc;
66877183Srwatson	struct ucred *newcred, *oldcred;
66977183Srwatson	gid_t gid;
67087218Srwatson	int error;
6711541Srgrimes
67277183Srwatson	gid = uap->gid;
673195104Srwatson	AUDIT_ARG_GID(gid);
67494619Sjhb	newcred = crget();
67594619Sjhb	PROC_LOCK(p);
676194498Sbrooks	oldcred = crcopysafe(p, newcred);
67787466Srwatson
678145147Srwatson#ifdef MAC
679189529Srwatson	error = mac_cred_check_setgid(oldcred, gid);
680145147Srwatson	if (error)
681145147Srwatson		goto fail;
682145147Srwatson#endif
683145147Srwatson
68424448Speter	/*
68524448Speter	 * See if we have "permission" by POSIX 1003.1 rules.
68624448Speter	 *
68724448Speter	 * Note that setgid(getegid()) is a special case of
68824448Speter	 * "appropriate privileges" in appendix B.4.2.2.  We need
68972093Sasmodai	 * to use this clause to be compatible with traditional BSD
69024448Speter	 * semantics.  Basically, it means that "setgid(xx)" sets all
69124448Speter	 * three id's (assuming you have privs).
69224448Speter	 *
69324448Speter	 * For notes on the logic here, see setuid() above.
69424448Speter	 */
69577183Srwatson	if (gid != oldcred->cr_rgid &&		/* allow setgid(getgid()) */
69617994Sache#ifdef _POSIX_SAVED_IDS
69777183Srwatson	    gid != oldcred->cr_svgid &&		/* allow setgid(saved gid) */
69817994Sache#endif
69924448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
70077183Srwatson	    gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
70124448Speter#endif
702170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETGID, 0)) != 0)
703145147Srwatson		goto fail;
70424448Speter
70517994Sache#ifdef _POSIX_SAVED_IDS
70624448Speter	/*
70724448Speter	 * Do we have "appropriate privileges" (are we root or gid == egid)
70824448Speter	 * If so, we are changing the real uid and saved gid.
70924448Speter	 */
71024448Speter	if (
71124448Speter#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
71277183Srwatson	    gid == oldcred->cr_groups[0] ||
71317994Sache#endif
714164032Srwatson	    /* We are using privs. */
715170587Srwatson	    priv_check_cred(oldcred, PRIV_CRED_SETGID, 0) == 0)
71624448Speter#endif
71724448Speter	{
71824448Speter		/*
71924448Speter		 * Set real gid
72024448Speter		 */
72177183Srwatson		if (oldcred->cr_rgid != gid) {
72277183Srwatson			change_rgid(newcred, gid);
72331891Ssef			setsugid(p);
72424448Speter		}
72524448Speter		/*
72624448Speter		 * Set saved gid
72724448Speter		 *
72824448Speter		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
72924448Speter		 * the security of setegid() depends on it.  B.4.2.2 says it
73024448Speter		 * is important that we should do this.
73124448Speter		 */
73277183Srwatson		if (oldcred->cr_svgid != gid) {
73377183Srwatson			change_svgid(newcred, gid);
73431891Ssef			setsugid(p);
73524448Speter		}
7368141Sache	}
73724448Speter	/*
73824448Speter	 * In all cases permitted cases, we are changing the egid.
73924448Speter	 * Copy credentials so other references do not see our changes.
74024448Speter	 */
74177183Srwatson	if (oldcred->cr_groups[0] != gid) {
74277183Srwatson		change_egid(newcred, gid);
74331891Ssef		setsugid(p);
74424448Speter	}
74577183Srwatson	p->p_ucred = newcred;
74694619Sjhb	PROC_UNLOCK(p);
74777183Srwatson	crfree(oldcred);
74894619Sjhb	return (0);
749145147Srwatson
750145147Srwatsonfail:
751145147Srwatson	PROC_UNLOCK(p);
752145147Srwatson	crfree(newcred);
753145147Srwatson	return (error);
7541541Srgrimes}
7551541Srgrimes
75612221Sbde#ifndef _SYS_SYSPROTO_H_
7571541Srgrimesstruct setegid_args {
7581541Srgrimes	gid_t	egid;
7591541Srgrimes};
76012221Sbde#endif
7611541Srgrimes/* ARGSUSED */
7621549Srgrimesint
763225617Skmacysys_setegid(struct thread *td, struct setegid_args *uap)
7641541Srgrimes{
76583366Sjulian	struct proc *p = td->td_proc;
76677183Srwatson	struct ucred *newcred, *oldcred;
76777183Srwatson	gid_t egid;
76887218Srwatson	int error;
7691541Srgrimes
7701541Srgrimes	egid = uap->egid;
771195104Srwatson	AUDIT_ARG_EGID(egid);
77294619Sjhb	newcred = crget();
77394619Sjhb	PROC_LOCK(p);
774194498Sbrooks	oldcred = crcopysafe(p, newcred);
775145147Srwatson
776145147Srwatson#ifdef MAC
777189529Srwatson	error = mac_cred_check_setegid(oldcred, egid);
778145147Srwatson	if (error)
779145147Srwatson		goto fail;
780145147Srwatson#endif
781145147Srwatson
78277183Srwatson	if (egid != oldcred->cr_rgid &&		/* allow setegid(getgid()) */
78377183Srwatson	    egid != oldcred->cr_svgid &&	/* allow setegid(saved gid) */
784170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETEGID, 0)) != 0)
785145147Srwatson		goto fail;
786145147Srwatson
78777183Srwatson	if (oldcred->cr_groups[0] != egid) {
78877183Srwatson		change_egid(newcred, egid);
78931891Ssef		setsugid(p);
79024449Speter	}
79177183Srwatson	p->p_ucred = newcred;
79294619Sjhb	PROC_UNLOCK(p);
79377183Srwatson	crfree(oldcred);
79494619Sjhb	return (0);
795145147Srwatson
796145147Srwatsonfail:
797145147Srwatson	PROC_UNLOCK(p);
798145147Srwatson	crfree(newcred);
799145147Srwatson	return (error);
8001541Srgrimes}
8011541Srgrimes
80212221Sbde#ifndef _SYS_SYSPROTO_H_
8031541Srgrimesstruct setgroups_args {
8041541Srgrimes	u_int	gidsetsize;
8051541Srgrimes	gid_t	*gidset;
8061541Srgrimes};
80712221Sbde#endif
8081541Srgrimes/* ARGSUSED */
8091549Srgrimesint
810225617Skmacysys_setgroups(struct thread *td, struct setgroups_args *uap)
8111541Srgrimes{
812194498Sbrooks	gid_t *groups = NULL;
813160139Sjhb	int error;
814160139Sjhb
815202143Sbrooks	if (uap->gidsetsize > ngroups_max + 1)
816160139Sjhb		return (EINVAL);
817194498Sbrooks	groups = malloc(uap->gidsetsize * sizeof(gid_t), M_TEMP, M_WAITOK);
818160139Sjhb	error = copyin(uap->gidset, groups, uap->gidsetsize * sizeof(gid_t));
819160139Sjhb	if (error)
820194498Sbrooks		goto out;
821194498Sbrooks	error = kern_setgroups(td, uap->gidsetsize, groups);
822194498Sbrooksout:
823194498Sbrooks	free(groups, M_TEMP);
824194498Sbrooks	return (error);
825160139Sjhb}
826160139Sjhb
827160139Sjhbint
828160139Sjhbkern_setgroups(struct thread *td, u_int ngrp, gid_t *groups)
829160139Sjhb{
83083366Sjulian	struct proc *p = td->td_proc;
831160139Sjhb	struct ucred *newcred, *oldcred;
8321541Srgrimes	int error;
8331541Srgrimes
834202143Sbrooks	if (ngrp > ngroups_max + 1)
83594619Sjhb		return (EINVAL);
836195104Srwatson	AUDIT_ARG_GROUPSET(groups, ngrp);
83794619Sjhb	newcred = crget();
838194498Sbrooks	crextend(newcred, ngrp);
83994619Sjhb	PROC_LOCK(p);
840194498Sbrooks	oldcred = crcopysafe(p, newcred);
841145147Srwatson
842145147Srwatson#ifdef MAC
843189529Srwatson	error = mac_cred_check_setgroups(oldcred, ngrp, groups);
844145147Srwatson	if (error)
845145147Srwatson		goto fail;
846145147Srwatson#endif
847145147Srwatson
848170587Srwatson	error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0);
849145147Srwatson	if (error)
850145147Srwatson		goto fail;
851145147Srwatson
85224447Speter	if (ngrp < 1) {
85324447Speter		/*
85424447Speter		 * setgroups(0, NULL) is a legitimate way of clearing the
85524447Speter		 * groups vector on non-BSD systems (which generally do not
85624447Speter		 * have the egid in the groups[0]).  We risk security holes
85724447Speter		 * when running non-BSD software if we do not do the same.
85824447Speter		 */
85977183Srwatson		newcred->cr_ngroups = 1;
86024447Speter	} else {
861194498Sbrooks		crsetgroups_locked(newcred, ngrp, groups);
86224447Speter	}
86331891Ssef	setsugid(p);
86477183Srwatson	p->p_ucred = newcred;
86594619Sjhb	PROC_UNLOCK(p);
86677183Srwatson	crfree(oldcred);
86794619Sjhb	return (0);
868145147Srwatson
869145147Srwatsonfail:
870145147Srwatson	PROC_UNLOCK(p);
871145147Srwatson	crfree(newcred);
872145147Srwatson	return (error);
8731541Srgrimes}
8741541Srgrimes
87512221Sbde#ifndef _SYS_SYSPROTO_H_
8761541Srgrimesstruct setreuid_args {
8779238Sache	uid_t	ruid;
8789238Sache	uid_t	euid;
8791541Srgrimes};
88012221Sbde#endif
8811541Srgrimes/* ARGSUSED */
8821549Srgrimesint
883225617Skmacysys_setreuid(register struct thread *td, struct setreuid_args *uap)
8841541Srgrimes{
88583366Sjulian	struct proc *p = td->td_proc;
88677183Srwatson	struct ucred *newcred, *oldcred;
88787218Srwatson	uid_t euid, ruid;
88898417Salfred	struct uidinfo *euip, *ruip;
88987218Srwatson	int error;
8901541Srgrimes
89187218Srwatson	euid = uap->euid;
8929238Sache	ruid = uap->ruid;
893195104Srwatson	AUDIT_ARG_EUID(euid);
894195104Srwatson	AUDIT_ARG_RUID(ruid);
89594619Sjhb	newcred = crget();
89698417Salfred	euip = uifind(euid);
89798417Salfred	ruip = uifind(ruid);
89894619Sjhb	PROC_LOCK(p);
899194498Sbrooks	oldcred = crcopysafe(p, newcred);
900145147Srwatson
901145147Srwatson#ifdef MAC
902189529Srwatson	error = mac_cred_check_setreuid(oldcred, ruid, euid);
903145147Srwatson	if (error)
904145147Srwatson		goto fail;
905145147Srwatson#endif
906145147Srwatson
90777183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
90877183Srwatson	      ruid != oldcred->cr_svuid) ||
90977183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_uid &&
91077183Srwatson	      euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) &&
911170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREUID, 0)) != 0)
912145147Srwatson		goto fail;
913145147Srwatson
91477183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
91598417Salfred		change_euid(newcred, euip);
91631891Ssef		setsugid(p);
91724450Speter	}
91877183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
91998417Salfred		change_ruid(newcred, ruip);
92031891Ssef		setsugid(p);
9218135Sache	}
92277183Srwatson	if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) &&
92377183Srwatson	    newcred->cr_svuid != newcred->cr_uid) {
92477183Srwatson		change_svuid(newcred, newcred->cr_uid);
92531891Ssef		setsugid(p);
92624450Speter	}
92777183Srwatson	p->p_ucred = newcred;
92894619Sjhb	PROC_UNLOCK(p);
929220212Strasz#ifdef RACCT
930220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
931220212Strasz#endif
93298417Salfred	uifree(ruip);
93398417Salfred	uifree(euip);
93477183Srwatson	crfree(oldcred);
93594619Sjhb	return (0);
936145147Srwatson
937145147Srwatsonfail:
938145147Srwatson	PROC_UNLOCK(p);
939145147Srwatson	uifree(ruip);
940145147Srwatson	uifree(euip);
941145147Srwatson	crfree(newcred);
942145147Srwatson	return (error);
9431541Srgrimes}
9441541Srgrimes
94512221Sbde#ifndef _SYS_SYSPROTO_H_
9461541Srgrimesstruct setregid_args {
9479238Sache	gid_t	rgid;
9489238Sache	gid_t	egid;
9491541Srgrimes};
95012221Sbde#endif
9511541Srgrimes/* ARGSUSED */
9521549Srgrimesint
953225617Skmacysys_setregid(register struct thread *td, struct setregid_args *uap)
9541541Srgrimes{
95583366Sjulian	struct proc *p = td->td_proc;
95677183Srwatson	struct ucred *newcred, *oldcred;
95787218Srwatson	gid_t egid, rgid;
95887218Srwatson	int error;
9591541Srgrimes
96087218Srwatson	egid = uap->egid;
9619238Sache	rgid = uap->rgid;
962195104Srwatson	AUDIT_ARG_EGID(egid);
963195104Srwatson	AUDIT_ARG_RGID(rgid);
96494619Sjhb	newcred = crget();
96594619Sjhb	PROC_LOCK(p);
966194498Sbrooks	oldcred = crcopysafe(p, newcred);
967145147Srwatson
968145147Srwatson#ifdef MAC
969189529Srwatson	error = mac_cred_check_setregid(oldcred, rgid, egid);
970145147Srwatson	if (error)
971145147Srwatson		goto fail;
972145147Srwatson#endif
973145147Srwatson
97477183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
97577183Srwatson	    rgid != oldcred->cr_svgid) ||
97677183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
97777183Srwatson	     egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
978170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETREGID, 0)) != 0)
979145147Srwatson		goto fail;
98094619Sjhb
98177183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
98277183Srwatson		change_egid(newcred, egid);
98331891Ssef		setsugid(p);
98424450Speter	}
98577183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
98677183Srwatson		change_rgid(newcred, rgid);
98731891Ssef		setsugid(p);
98824450Speter	}
98977183Srwatson	if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
99077183Srwatson	    newcred->cr_svgid != newcred->cr_groups[0]) {
99177183Srwatson		change_svgid(newcred, newcred->cr_groups[0]);
99231891Ssef		setsugid(p);
99324450Speter	}
99477812Sru	p->p_ucred = newcred;
99594619Sjhb	PROC_UNLOCK(p);
99677812Sru	crfree(oldcred);
99794619Sjhb	return (0);
998145147Srwatson
999145147Srwatsonfail:
1000145147Srwatson	PROC_UNLOCK(p);
1001145147Srwatson	crfree(newcred);
1002145147Srwatson	return (error);
10031541Srgrimes}
10041541Srgrimes
100556115Speter/*
1006167232Srwatson * setresuid(ruid, euid, suid) is like setreuid except control over the saved
1007167232Srwatson * uid is explicit.
100856115Speter */
100924453Speter#ifndef _SYS_SYSPROTO_H_
101056115Speterstruct setresuid_args {
101156115Speter	uid_t	ruid;
101256115Speter	uid_t	euid;
101356115Speter	uid_t	suid;
101456115Speter};
101556115Speter#endif
101656115Speter/* ARGSUSED */
101756115Speterint
1018225617Skmacysys_setresuid(register struct thread *td, struct setresuid_args *uap)
101956115Speter{
102083366Sjulian	struct proc *p = td->td_proc;
102177183Srwatson	struct ucred *newcred, *oldcred;
102287218Srwatson	uid_t euid, ruid, suid;
102398417Salfred	struct uidinfo *euip, *ruip;
102456115Speter	int error;
102556115Speter
102687218Srwatson	euid = uap->euid;
102756115Speter	ruid = uap->ruid;
102856115Speter	suid = uap->suid;
1029195104Srwatson	AUDIT_ARG_EUID(euid);
1030195104Srwatson	AUDIT_ARG_RUID(ruid);
1031195104Srwatson	AUDIT_ARG_SUID(suid);
103294619Sjhb	newcred = crget();
103398417Salfred	euip = uifind(euid);
103498417Salfred	ruip = uifind(ruid);
103594619Sjhb	PROC_LOCK(p);
1036194498Sbrooks	oldcred = crcopysafe(p, newcred);
1037145147Srwatson
1038145147Srwatson#ifdef MAC
1039189529Srwatson	error = mac_cred_check_setresuid(oldcred, ruid, euid, suid);
1040145147Srwatson	if (error)
1041145147Srwatson		goto fail;
1042145147Srwatson#endif
1043145147Srwatson
104477183Srwatson	if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid &&
104577183Srwatson	     ruid != oldcred->cr_svuid &&
104677183Srwatson	      ruid != oldcred->cr_uid) ||
104777183Srwatson	     (euid != (uid_t)-1 && euid != oldcred->cr_ruid &&
104877183Srwatson	    euid != oldcred->cr_svuid &&
104977183Srwatson	      euid != oldcred->cr_uid) ||
105077183Srwatson	     (suid != (uid_t)-1 && suid != oldcred->cr_ruid &&
105177183Srwatson	    suid != oldcred->cr_svuid &&
105277183Srwatson	      suid != oldcred->cr_uid)) &&
1053170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESUID, 0)) != 0)
1054145147Srwatson		goto fail;
105594619Sjhb
105677183Srwatson	if (euid != (uid_t)-1 && oldcred->cr_uid != euid) {
105798417Salfred		change_euid(newcred, euip);
105856115Speter		setsugid(p);
105956115Speter	}
106077183Srwatson	if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) {
106198417Salfred		change_ruid(newcred, ruip);
106256115Speter		setsugid(p);
106356115Speter	}
106477183Srwatson	if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) {
106577183Srwatson		change_svuid(newcred, suid);
106656115Speter		setsugid(p);
106756115Speter	}
106877183Srwatson	p->p_ucred = newcred;
106994619Sjhb	PROC_UNLOCK(p);
1070220212Strasz#ifdef RACCT
1071220212Strasz	racct_proc_ucred_changed(p, oldcred, newcred);
1072220212Strasz#endif
107398417Salfred	uifree(ruip);
107498417Salfred	uifree(euip);
107577183Srwatson	crfree(oldcred);
107694619Sjhb	return (0);
1077145147Srwatson
1078145147Srwatsonfail:
1079145147Srwatson	PROC_UNLOCK(p);
1080145147Srwatson	uifree(ruip);
1081145147Srwatson	uifree(euip);
1082145147Srwatson	crfree(newcred);
1083145147Srwatson	return (error);
1084145147Srwatson
108556115Speter}
108656115Speter
108756115Speter/*
1088167232Srwatson * setresgid(rgid, egid, sgid) is like setregid except control over the saved
1089167232Srwatson * gid is explicit.
109056115Speter */
109156115Speter#ifndef _SYS_SYSPROTO_H_
109256115Speterstruct setresgid_args {
109356115Speter	gid_t	rgid;
109456115Speter	gid_t	egid;
109556115Speter	gid_t	sgid;
109656115Speter};
109756115Speter#endif
109856115Speter/* ARGSUSED */
109956115Speterint
1100225617Skmacysys_setresgid(register struct thread *td, struct setresgid_args *uap)
110156115Speter{
110283366Sjulian	struct proc *p = td->td_proc;
110377183Srwatson	struct ucred *newcred, *oldcred;
110487218Srwatson	gid_t egid, rgid, sgid;
110556115Speter	int error;
110656115Speter
110787218Srwatson	egid = uap->egid;
110856115Speter	rgid = uap->rgid;
110956115Speter	sgid = uap->sgid;
1110195104Srwatson	AUDIT_ARG_EGID(egid);
1111195104Srwatson	AUDIT_ARG_RGID(rgid);
1112195104Srwatson	AUDIT_ARG_SGID(sgid);
111394619Sjhb	newcred = crget();
111494619Sjhb	PROC_LOCK(p);
1115194498Sbrooks	oldcred = crcopysafe(p, newcred);
1116145147Srwatson
1117145147Srwatson#ifdef MAC
1118189529Srwatson	error = mac_cred_check_setresgid(oldcred, rgid, egid, sgid);
1119145147Srwatson	if (error)
1120145147Srwatson		goto fail;
1121145147Srwatson#endif
1122145147Srwatson
112377183Srwatson	if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
112477183Srwatson	      rgid != oldcred->cr_svgid &&
112577183Srwatson	      rgid != oldcred->cr_groups[0]) ||
112677183Srwatson	     (egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
112777183Srwatson	      egid != oldcred->cr_svgid &&
112877183Srwatson	      egid != oldcred->cr_groups[0]) ||
112977183Srwatson	     (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
113077183Srwatson	      sgid != oldcred->cr_svgid &&
113177183Srwatson	      sgid != oldcred->cr_groups[0])) &&
1132170587Srwatson	    (error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID, 0)) != 0)
1133145147Srwatson		goto fail;
113494619Sjhb
113577183Srwatson	if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
113677183Srwatson		change_egid(newcred, egid);
113756115Speter		setsugid(p);
113856115Speter	}
113977183Srwatson	if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) {
114077183Srwatson		change_rgid(newcred, rgid);
114156115Speter		setsugid(p);
114256115Speter	}
114377183Srwatson	if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) {
114477183Srwatson		change_svgid(newcred, sgid);
114556115Speter		setsugid(p);
114656115Speter	}
114777183Srwatson	p->p_ucred = newcred;
114894619Sjhb	PROC_UNLOCK(p);
114977183Srwatson	crfree(oldcred);
115094619Sjhb	return (0);
1151145147Srwatson
1152145147Srwatsonfail:
1153145147Srwatson	PROC_UNLOCK(p);
1154145147Srwatson	crfree(newcred);
1155145147Srwatson	return (error);
115656115Speter}
115756115Speter
115856115Speter#ifndef _SYS_SYSPROTO_H_
115956115Speterstruct getresuid_args {
116056115Speter	uid_t	*ruid;
116156115Speter	uid_t	*euid;
116256115Speter	uid_t	*suid;
116356115Speter};
116456115Speter#endif
116556115Speter/* ARGSUSED */
116656115Speterint
1167225617Skmacysys_getresuid(register struct thread *td, struct getresuid_args *uap)
116856115Speter{
116982749Sdillon	struct ucred *cred;
117056115Speter	int error1 = 0, error2 = 0, error3 = 0;
117156115Speter
117293264Sdillon	cred = td->td_ucred;
117356115Speter	if (uap->ruid)
117499009Salfred		error1 = copyout(&cred->cr_ruid,
117599009Salfred		    uap->ruid, sizeof(cred->cr_ruid));
117656115Speter	if (uap->euid)
117799009Salfred		error2 = copyout(&cred->cr_uid,
117899009Salfred		    uap->euid, sizeof(cred->cr_uid));
117956115Speter	if (uap->suid)
118099009Salfred		error3 = copyout(&cred->cr_svuid,
118199009Salfred		    uap->suid, sizeof(cred->cr_svuid));
118287218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
118356115Speter}
118456115Speter
118556115Speter#ifndef _SYS_SYSPROTO_H_
118656115Speterstruct getresgid_args {
118756115Speter	gid_t	*rgid;
118856115Speter	gid_t	*egid;
118956115Speter	gid_t	*sgid;
119056115Speter};
119156115Speter#endif
119256115Speter/* ARGSUSED */
119356115Speterint
1194225617Skmacysys_getresgid(register struct thread *td, struct getresgid_args *uap)
119556115Speter{
119682749Sdillon	struct ucred *cred;
119756115Speter	int error1 = 0, error2 = 0, error3 = 0;
119856115Speter
119993264Sdillon	cred = td->td_ucred;
120056115Speter	if (uap->rgid)
120199009Salfred		error1 = copyout(&cred->cr_rgid,
120299009Salfred		    uap->rgid, sizeof(cred->cr_rgid));
120356115Speter	if (uap->egid)
120499009Salfred		error2 = copyout(&cred->cr_groups[0],
120599009Salfred		    uap->egid, sizeof(cred->cr_groups[0]));
120656115Speter	if (uap->sgid)
120799009Salfred		error3 = copyout(&cred->cr_svgid,
120899009Salfred		    uap->sgid, sizeof(cred->cr_svgid));
120987218Srwatson	return (error1 ? error1 : error2 ? error2 : error3);
121056115Speter}
121156115Speter
121256115Speter#ifndef _SYS_SYSPROTO_H_
121324453Speterstruct issetugid_args {
121424453Speter	int dummy;
121524453Speter};
121624453Speter#endif
121724453Speter/* ARGSUSED */
121824453Speterint
1219225617Skmacysys_issetugid(register struct thread *td, struct issetugid_args *uap)
122024453Speter{
122183366Sjulian	struct proc *p = td->td_proc;
122283366Sjulian
122324453Speter	/*
122424453Speter	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
122524453Speter	 * we use P_SUGID because we consider changing the owners as
122624453Speter	 * "tainting" as well.
122724453Speter	 * This is significant for procs that start as root and "become"
122824453Speter	 * a user without an exec - programs cannot know *everything*
122924453Speter	 * that libc *might* have put in their data segment.
123024453Speter	 */
123191140Stanimura	PROC_LOCK(p);
123283366Sjulian	td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0;
123391140Stanimura	PROC_UNLOCK(p);
123424453Speter	return (0);
123524453Speter}
123624453Speter
123775426Srwatsonint
1238225617Skmacysys___setugid(struct thread *td, struct __setugid_args *uap)
123975426Srwatson{
124082749Sdillon#ifdef REGRESSION
124194619Sjhb	struct proc *p;
124275426Srwatson
124394619Sjhb	p = td->td_proc;
124475426Srwatson	switch (uap->flag) {
124575426Srwatson	case 0:
124694619Sjhb		PROC_LOCK(p);
124794619Sjhb		p->p_flag &= ~P_SUGID;
124894619Sjhb		PROC_UNLOCK(p);
124994619Sjhb		return (0);
125075426Srwatson	case 1:
125194619Sjhb		PROC_LOCK(p);
125294619Sjhb		p->p_flag |= P_SUGID;
125394619Sjhb		PROC_UNLOCK(p);
125494619Sjhb		return (0);
125575426Srwatson	default:
125694619Sjhb		return (EINVAL);
125775426Srwatson	}
125875426Srwatson#else /* !REGRESSION */
125987218Srwatson
126075426Srwatson	return (ENOSYS);
126187218Srwatson#endif /* REGRESSION */
126275426Srwatson}
126375426Srwatson
12641541Srgrimes/*
12651541Srgrimes * Check if gid is a member of the group set.
12661541Srgrimes */
12671549Srgrimesint
126893580Sjhbgroupmember(gid_t gid, struct ucred *cred)
12691541Srgrimes{
1270194556Sbrooks	int l;
1271194556Sbrooks	int h;
1272194556Sbrooks	int m;
12731541Srgrimes
1274194556Sbrooks	if (cred->cr_groups[0] == gid)
1275194556Sbrooks		return(1);
1276194556Sbrooks
1277194556Sbrooks	/*
1278194556Sbrooks	 * If gid was not our primary group, perform a binary search
1279194556Sbrooks	 * of the supplemental groups.  This is possible because we
1280194556Sbrooks	 * sort the groups in crsetgroups().
1281194556Sbrooks	 */
1282194556Sbrooks	l = 1;
1283194556Sbrooks	h = cred->cr_ngroups;
1284194556Sbrooks	while (l < h) {
1285194556Sbrooks		m = l + ((h - l) / 2);
1286194556Sbrooks		if (cred->cr_groups[m] < gid)
1287194556Sbrooks			l = m + 1;
1288194556Sbrooks		else
1289194556Sbrooks			h = m;
1290194556Sbrooks	}
1291194556Sbrooks	if ((l < cred->cr_ngroups) && (cred->cr_groups[l] == gid))
1292194556Sbrooks		return (1);
1293194556Sbrooks
12941541Srgrimes	return (0);
12951541Srgrimes}
12961541Srgrimes
129782424Srwatson/*
129887218Srwatson * Test the active securelevel against a given level.  securelevel_gt()
129987218Srwatson * implements (securelevel > level).  securelevel_ge() implements
130087218Srwatson * (securelevel >= level).  Note that the logic is inverted -- these
130187218Srwatson * functions return EPERM on "success" and 0 on "failure".
130283639Srwatson *
1303192895Sjamie * Due to care taken when setting the securelevel, we know that no jail will
1304192895Sjamie * be less secure that its parent (or the physical system), so it is sufficient
1305192895Sjamie * to test the current jail only.
1306192895Sjamie *
1307164032Srwatson * XXXRW: Possibly since this has to do with privilege, it should move to
1308164032Srwatson * kern_priv.c.
130983639Srwatson */
131083639Srwatsonint
131183639Srwatsonsecurelevel_gt(struct ucred *cr, int level)
131283639Srwatson{
131383639Srwatson
1314192895Sjamie	return (cr->cr_prison->pr_securelevel > level ? EPERM : 0);
131583639Srwatson}
131683639Srwatson
131783639Srwatsonint
131883639Srwatsonsecurelevel_ge(struct ucred *cr, int level)
131983639Srwatson{
132083639Srwatson
1321192895Sjamie	return (cr->cr_prison->pr_securelevel >= level ? EPERM : 0);
132283639Srwatson}
132383639Srwatson
132484736Srwatson/*
132587144Srwatson * 'see_other_uids' determines whether or not visibility of processes
132687218Srwatson * and sockets with credentials holding different real uids is possible
132787138Srwatson * using a variety of system MIBs.
132887218Srwatson * XXX: data declarations should be together near the beginning of the file.
132984736Srwatson */
133087144Srwatsonstatic int	see_other_uids = 1;
133189414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW,
133287218Srwatson    &see_other_uids, 0,
133384736Srwatson    "Unprivileged processes may see subjects/objects with different real uid");
133484736Srwatson
1335210226Strasz/*-
133692923Srwatson * Determine if u1 "can see" the subject specified by u2, according to the
133792923Srwatson * 'see_other_uids' policy.
133892923Srwatson * Returns: 0 for permitted, ESRCH otherwise
133992923Srwatson * Locks: none
134092923Srwatson * References: *u1 and *u2 must not change during the call
134192923Srwatson *             u1 may equal u2, in which case only one reference is required
134292923Srwatson */
134392923Srwatsonstatic int
134492923Srwatsoncr_seeotheruids(struct ucred *u1, struct ucred *u2)
134592923Srwatson{
134692923Srwatson
134792923Srwatson	if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) {
1348170587Srwatson		if (priv_check_cred(u1, PRIV_SEEOTHERUIDS, 0) != 0)
134992923Srwatson			return (ESRCH);
135092923Srwatson	}
135192923Srwatson	return (0);
135292923Srwatson}
135392923Srwatson
1354122869Srwatson/*
1355122869Srwatson * 'see_other_gids' determines whether or not visibility of processes
1356122869Srwatson * and sockets with credentials holding different real gids is possible
1357122869Srwatson * using a variety of system MIBs.
1358122869Srwatson * XXX: data declarations should be together near the beginning of the file.
1359122869Srwatson */
1360122869Srwatsonstatic int	see_other_gids = 1;
1361122869SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, see_other_gids, CTLFLAG_RW,
1362122869Srwatson    &see_other_gids, 0,
1363122869Srwatson    "Unprivileged processes may see subjects/objects with different real gid");
1364122869Srwatson
1365122869Srwatson/*
1366122869Srwatson * Determine if u1 can "see" the subject specified by u2, according to the
1367122869Srwatson * 'see_other_gids' policy.
1368122869Srwatson * Returns: 0 for permitted, ESRCH otherwise
1369122869Srwatson * Locks: none
1370122869Srwatson * References: *u1 and *u2 must not change during the call
1371122869Srwatson *             u1 may equal u2, in which case only one reference is required
1372122869Srwatson */
1373122869Srwatsonstatic int
1374122869Srwatsoncr_seeothergids(struct ucred *u1, struct ucred *u2)
1375122869Srwatson{
1376122869Srwatson	int i, match;
1377122869Srwatson
1378122869Srwatson	if (!see_other_gids) {
1379122869Srwatson		match = 0;
1380122869Srwatson		for (i = 0; i < u1->cr_ngroups; i++) {
1381122869Srwatson			if (groupmember(u1->cr_groups[i], u2))
1382122869Srwatson				match = 1;
1383122869Srwatson			if (match)
1384122869Srwatson				break;
1385122869Srwatson		}
1386122869Srwatson		if (!match) {
1387170587Srwatson			if (priv_check_cred(u1, PRIV_SEEOTHERGIDS, 0) != 0)
1388122869Srwatson				return (ESRCH);
1389122869Srwatson		}
1390122869Srwatson	}
1391122869Srwatson	return (0);
1392122869Srwatson}
1393122869Srwatson
1394210226Strasz/*-
139582466Srwatson * Determine if u1 "can see" the subject specified by u2.
139674956Srwatson * Returns: 0 for permitted, an errno value otherwise
139774956Srwatson * Locks: none
139887218Srwatson * References: *u1 and *u2 must not change during the call
139974956Srwatson *             u1 may equal u2, in which case only one reference is required
140074956Srwatson */
140174956Srwatsonint
140283742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2)
140365237Srwatson{
140472786Srwatson	int error;
140553518Sphk
140674956Srwatson	if ((error = prison_check(u1, u2)))
140772786Srwatson		return (error);
1408101003Srwatson#ifdef MAC
1409172930Srwatson	if ((error = mac_cred_check_visible(u1, u2)))
1410101003Srwatson		return (error);
1411101003Srwatson#endif
141292923Srwatson	if ((error = cr_seeotheruids(u1, u2)))
141392923Srwatson		return (error);
1414122869Srwatson	if ((error = cr_seeothergids(u1, u2)))
1415122869Srwatson		return (error);
141665237Srwatson	return (0);
141765237Srwatson}
141865237Srwatson
1419210226Strasz/*-
142096886Sjhb * Determine if td "can see" the subject specified by p.
142182424Srwatson * Returns: 0 for permitted, an errno value otherwise
142296886Sjhb * Locks: Sufficient locks to protect p->p_ucred must be held.  td really
142396886Sjhb *        should be curthread.
142496886Sjhb * References: td and p must be valid for the lifetime of the call
142582424Srwatson */
142679335Srwatsonint
142796886Sjhbp_cansee(struct thread *td, struct proc *p)
142874956Srwatson{
142974956Srwatson
143083742Srwatson	/* Wrap cr_cansee() for all functionality. */
143196886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
143296886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
143396886Sjhb	return (cr_cansee(td->td_ucred, p->p_ucred));
143474956Srwatson}
143574956Srwatson
1436120052Srwatson/*
1437120052Srwatson * 'conservative_signals' prevents the delivery of a broad class of
1438120052Srwatson * signals by unprivileged processes to processes that have changed their
1439120052Srwatson * credentials since the last invocation of execve().  This can prevent
1440120052Srwatson * the leakage of cached information or retained privileges as a result
1441120052Srwatson * of a common class of signal-related vulnerabilities.  However, this
1442120052Srwatson * may interfere with some applications that expect to be able to
1443120052Srwatson * deliver these signals to peer processes after having given up
1444120052Srwatson * privilege.
1445120052Srwatson */
1446120052Srwatsonstatic int	conservative_signals = 1;
1447120052SrwatsonSYSCTL_INT(_security_bsd, OID_AUTO, conservative_signals, CTLFLAG_RW,
1448120052Srwatson    &conservative_signals, 0, "Unprivileged processes prevented from "
1449120052Srwatson    "sending certain signals to processes whose credentials have changed");
1450210226Strasz/*-
145188943Srwatson * Determine whether cred may deliver the specified signal to proc.
145288943Srwatson * Returns: 0 for permitted, an errno value otherwise.
145388943Srwatson * Locks: A lock must be held for proc.
145488943Srwatson * References: cred and proc must be valid for the lifetime of the call.
145575437Srwatson */
145675437Srwatsonint
1457141815Ssobomaxcr_cansignal(struct ucred *cred, struct proc *proc, int signum)
145853518Sphk{
145982466Srwatson	int error;
146084826Sjhb
146196886Sjhb	PROC_LOCK_ASSERT(proc, MA_OWNED);
146275437Srwatson	/*
146388943Srwatson	 * Jail semantics limit the scope of signalling to proc in the
146488943Srwatson	 * same jail as cred, if cred is in jail.
146575437Srwatson	 */
146688943Srwatson	error = prison_check(cred, proc->p_ucred);
146788943Srwatson	if (error)
146872786Srwatson		return (error);
1469101003Srwatson#ifdef MAC
1470172930Srwatson	if ((error = mac_proc_check_signal(cred, proc, signum)))
1471101003Srwatson		return (error);
1472101003Srwatson#endif
1473122869Srwatson	if ((error = cr_seeotheruids(cred, proc->p_ucred)))
147492923Srwatson		return (error);
1475122869Srwatson	if ((error = cr_seeothergids(cred, proc->p_ucred)))
1476122869Srwatson		return (error);
147765237Srwatson
147865237Srwatson	/*
147982424Srwatson	 * UNIX signal semantics depend on the status of the P_SUGID
148082424Srwatson	 * bit on the target process.  If the bit is set, then additional
148182424Srwatson	 * restrictions are placed on the set of available signals.
148275437Srwatson	 */
1483141815Ssobomax	if (conservative_signals && (proc->p_flag & P_SUGID)) {
148475437Srwatson		switch (signum) {
148575437Srwatson		case 0:
148675437Srwatson		case SIGKILL:
148775437Srwatson		case SIGINT:
148875437Srwatson		case SIGTERM:
1489120052Srwatson		case SIGALRM:
149075437Srwatson		case SIGSTOP:
149175437Srwatson		case SIGTTIN:
149275437Srwatson		case SIGTTOU:
149375437Srwatson		case SIGTSTP:
149475437Srwatson		case SIGHUP:
149575437Srwatson		case SIGUSR1:
149675437Srwatson		case SIGUSR2:
149782466Srwatson			/*
149882466Srwatson			 * Generally, permit job and terminal control
149982466Srwatson			 * signals.
150082466Srwatson			 */
150175437Srwatson			break;
150275437Srwatson		default:
150388943Srwatson			/* Not permitted without privilege. */
1504170587Srwatson			error = priv_check_cred(cred, PRIV_SIGNAL_SUGID, 0);
150575437Srwatson			if (error)
150675437Srwatson				return (error);
150775437Srwatson		}
150865237Srwatson	}
150965237Srwatson
151075480Srwatson	/*
151182424Srwatson	 * Generally, the target credential's ruid or svuid must match the
151275480Srwatson	 * subject credential's ruid or euid.
151375480Srwatson	 */
151488943Srwatson	if (cred->cr_ruid != proc->p_ucred->cr_ruid &&
151588943Srwatson	    cred->cr_ruid != proc->p_ucred->cr_svuid &&
151688943Srwatson	    cred->cr_uid != proc->p_ucred->cr_ruid &&
151788943Srwatson	    cred->cr_uid != proc->p_ucred->cr_svuid) {
1518170587Srwatson		error = priv_check_cred(cred, PRIV_SIGNAL_DIFFCRED, 0);
151975480Srwatson		if (error)
152075480Srwatson			return (error);
152175480Srwatson	}
152275480Srwatson
152387218Srwatson	return (0);
152453518Sphk}
152553518Sphk
1526210226Strasz/*-
152796886Sjhb * Determine whether td may deliver the specified signal to p.
152888943Srwatson * Returns: 0 for permitted, an errno value otherwise
152996886Sjhb * Locks: Sufficient locks to protect various components of td and p
153096886Sjhb *        must be held.  td must be curthread, and a lock must be
153196886Sjhb *        held for p.
153296886Sjhb * References: td and p must be valid for the lifetime of the call
153388943Srwatson */
153488943Srwatsonint
1535141815Ssobomaxp_cansignal(struct thread *td, struct proc *p, int signum)
153688943Srwatson{
153788943Srwatson
153896886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
153996886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
154096886Sjhb	if (td->td_proc == p)
154188943Srwatson		return (0);
154288943Srwatson
154388943Srwatson	/*
154488943Srwatson	 * UNIX signalling semantics require that processes in the same
154588943Srwatson	 * session always be able to deliver SIGCONT to one another,
154688943Srwatson	 * overriding the remaining protections.
154788943Srwatson	 */
154896886Sjhb	/* XXX: This will require an additional lock of some sort. */
154996886Sjhb	if (signum == SIGCONT && td->td_proc->p_session == p->p_session)
155088943Srwatson		return (0);
1551143108Ssobomax	/*
1552143800Ssobomax	 * Some compat layers use SIGTHR and higher signals for
1553143800Ssobomax	 * communication between different kernel threads of the same
1554143800Ssobomax	 * process, so that they expect that it's always possible to
1555143800Ssobomax	 * deliver them, even for suid applications where cr_cansignal() can
1556143108Ssobomax	 * deny such ability for security consideration.  It should be
1557143108Ssobomax	 * pretty safe to do since the only way to create two processes
1558143108Ssobomax	 * with the same p_leader is via rfork(2).
1559143108Ssobomax	 */
1560143805Ssobomax	if (td->td_proc->p_leader != NULL && signum >= SIGTHR &&
1561143805Ssobomax	    signum < SIGTHR + 4 && td->td_proc->p_leader == p->p_leader)
1562143108Ssobomax		return (0);
156388943Srwatson
1564141815Ssobomax	return (cr_cansignal(td->td_ucred, p, signum));
156588943Srwatson}
156688943Srwatson
1567210226Strasz/*-
156896886Sjhb * Determine whether td may reschedule p.
156982466Srwatson * Returns: 0 for permitted, an errno value otherwise
157096886Sjhb * Locks: Sufficient locks to protect various components of td and p
157196886Sjhb *        must be held.  td must be curthread, and a lock must
157296886Sjhb *        be held for p.
157396886Sjhb * References: td and p must be valid for the lifetime of the call
157482424Srwatson */
157579335Srwatsonint
157696886Sjhbp_cansched(struct thread *td, struct proc *p)
157765237Srwatson{
157872786Srwatson	int error;
157965237Srwatson
158096886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
158196886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
158296886Sjhb	if (td->td_proc == p)
158365237Srwatson		return (0);
158496886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
158572786Srwatson		return (error);
1586101003Srwatson#ifdef MAC
1587172930Srwatson	if ((error = mac_proc_check_sched(td->td_ucred, p)))
1588101003Srwatson		return (error);
1589101003Srwatson#endif
159096886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
159192923Srwatson		return (error);
1592122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1593122869Srwatson		return (error);
1594164032Srwatson	if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid &&
1595164032Srwatson	    td->td_ucred->cr_uid != p->p_ucred->cr_ruid) {
1596170587Srwatson		error = priv_check(td, PRIV_SCHED_DIFFCRED);
1597164032Srwatson		if (error)
1598164032Srwatson			return (error);
1599164032Srwatson	}
1600164032Srwatson	return (0);
160165237Srwatson}
160265237Srwatson
160382424Srwatson/*
160487280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of
160587280Srwatson * unprivileged inter-process debugging services, including some procfs
160687280Srwatson * functionality, ptrace(), and ktrace().  In the past, inter-process
160787280Srwatson * debugging has been involved in a variety of security problems, and sites
160887280Srwatson * not requiring the service might choose to disable it when hardening
160987280Srwatson * systems.
161082424Srwatson *
161182424Srwatson * XXX: Should modifying and reading this variable require locking?
161287218Srwatson * XXX: data declarations should be together near the beginning of the file.
161382424Srwatson */
161487144Srwatsonstatic int	unprivileged_proc_debug = 1;
161589414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
161687218Srwatson    &unprivileged_proc_debug, 0,
161780735Srwatson    "Unprivileged processes may use process debugging facilities");
161880735Srwatson
1619210226Strasz/*-
162096886Sjhb * Determine whether td may debug p.
162182466Srwatson * Returns: 0 for permitted, an errno value otherwise
162296886Sjhb * Locks: Sufficient locks to protect various components of td and p
162396886Sjhb *        must be held.  td must be curthread, and a lock must
162496886Sjhb *        be held for p.
162596886Sjhb * References: td and p must be valid for the lifetime of the call
162682424Srwatson */
162779335Srwatsonint
162896886Sjhbp_candebug(struct thread *td, struct proc *p)
162965237Srwatson{
163087218Srwatson	int credentialchanged, error, grpsubset, i, uidsubset;
163165237Srwatson
163296886Sjhb	KASSERT(td == curthread, ("%s: td not curthread", __func__));
163396886Sjhb	PROC_LOCK_ASSERT(p, MA_OWNED);
163487144Srwatson	if (!unprivileged_proc_debug) {
1635170587Srwatson		error = priv_check(td, PRIV_DEBUG_UNPRIV);
163684727Srwatson		if (error)
163784727Srwatson			return (error);
163884727Srwatson	}
163996886Sjhb	if (td->td_proc == p)
164084636Sdes		return (0);
164196886Sjhb	if ((error = prison_check(td->td_ucred, p->p_ucred)))
164272786Srwatson		return (error);
1643101003Srwatson#ifdef MAC
1644172930Srwatson	if ((error = mac_proc_check_debug(td->td_ucred, p)))
1645101003Srwatson		return (error);
1646101003Srwatson#endif
164796886Sjhb	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
164892923Srwatson		return (error);
1649122869Srwatson	if ((error = cr_seeothergids(td->td_ucred, p->p_ucred)))
1650122869Srwatson		return (error);
165165237Srwatson
165282466Srwatson	/*
165396886Sjhb	 * Is p's group set a subset of td's effective group set?  This
165496886Sjhb	 * includes p's egid, group access list, rgid, and svgid.
165582466Srwatson	 */
165685895Srwatson	grpsubset = 1;
165796886Sjhb	for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
165896886Sjhb		if (!groupmember(p->p_ucred->cr_groups[i], td->td_ucred)) {
165985895Srwatson			grpsubset = 0;
166085895Srwatson			break;
166185895Srwatson		}
166285895Srwatson	}
166385895Srwatson	grpsubset = grpsubset &&
166496886Sjhb	    groupmember(p->p_ucred->cr_rgid, td->td_ucred) &&
166596886Sjhb	    groupmember(p->p_ucred->cr_svgid, td->td_ucred);
166685895Srwatson
166785895Srwatson	/*
166896886Sjhb	 * Are the uids present in p's credential equal to td's
166996886Sjhb	 * effective uid?  This includes p's euid, svuid, and ruid.
167085895Srwatson	 */
167196886Sjhb	uidsubset = (td->td_ucred->cr_uid == p->p_ucred->cr_uid &&
167296886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_svuid &&
167396886Sjhb	    td->td_ucred->cr_uid == p->p_ucred->cr_ruid);
167485895Srwatson
167585895Srwatson	/*
167685895Srwatson	 * Has the credential of the process changed since the last exec()?
167785895Srwatson	 */
167896886Sjhb	credentialchanged = (p->p_flag & P_SUGID);
167985895Srwatson
168085895Srwatson	/*
168196886Sjhb	 * If p's gids aren't a subset, or the uids aren't a subset,
168285895Srwatson	 * or the credential has changed, require appropriate privilege
1683164032Srwatson	 * for td to debug p.
168485895Srwatson	 */
1685164032Srwatson	if (!grpsubset || !uidsubset) {
1686170587Srwatson		error = priv_check(td, PRIV_DEBUG_DIFFCRED);
168784727Srwatson		if (error)
168865237Srwatson			return (error);
168982466Srwatson	}
169065237Srwatson
1691164032Srwatson	if (credentialchanged) {
1692170587Srwatson		error = priv_check(td, PRIV_DEBUG_SUGID);
1693164032Srwatson		if (error)
1694164032Srwatson			return (error);
1695164032Srwatson	}
1696164032Srwatson
169787218Srwatson	/* Can't trace init when securelevel > 0. */
169896886Sjhb	if (p == initproc) {
169996886Sjhb		error = securelevel_gt(td->td_ucred, 0);
170083639Srwatson		if (error)
170183639Srwatson			return (error);
170283639Srwatson	}
170365237Srwatson
170485880Srwatson	/*
170585880Srwatson	 * Can't trace a process that's currently exec'ing.
1706164032Srwatson	 *
170785880Srwatson	 * XXX: Note, this is not a security policy decision, it's a
170885880Srwatson	 * basic correctness/functionality decision.  Therefore, this check
170985880Srwatson	 * should be moved to the caller's of p_candebug().
171085880Srwatson	 */
171196886Sjhb	if ((p->p_flag & P_INEXEC) != 0)
1712185983Skib		return (EBUSY);
171387466Srwatson
1714277698Skib	/* Denied explicitely */
1715277698Skib	if ((p->p_flag2 & P2_NOTRACE) != 0) {
1716277698Skib		error = priv_check(td, PRIV_DEBUG_DENIED);
1717277698Skib		if (error != 0)
1718277698Skib			return (error);
1719277698Skib	}
1720277698Skib
172165237Srwatson	return (0);
172265237Srwatson}
172365237Srwatson
1724210226Strasz/*-
172592976Srwatson * Determine whether the subject represented by cred can "see" a socket.
172692976Srwatson * Returns: 0 for permitted, ENOENT otherwise.
172792976Srwatson */
172892976Srwatsonint
172992976Srwatsoncr_canseesocket(struct ucred *cred, struct socket *so)
173092976Srwatson{
173192976Srwatson	int error;
173292976Srwatson
173392976Srwatson	error = prison_check(cred, so->so_cred);
173492976Srwatson	if (error)
173592976Srwatson		return (ENOENT);
1736101003Srwatson#ifdef MAC
1737172930Srwatson	error = mac_socket_check_visible(cred, so);
1738101003Srwatson	if (error)
1739101003Srwatson		return (error);
1740101003Srwatson#endif
174192976Srwatson	if (cr_seeotheruids(cred, so->so_cred))
174292976Srwatson		return (ENOENT);
1743122869Srwatson	if (cr_seeothergids(cred, so->so_cred))
1744122869Srwatson		return (ENOENT);
174592976Srwatson
174692976Srwatson	return (0);
174792976Srwatson}
174892976Srwatson
1749183982Sbz#if defined(INET) || defined(INET6)
1750210226Strasz/*-
1751183982Sbz * Determine whether the subject represented by cred can "see" a socket.
1752183982Sbz * Returns: 0 for permitted, ENOENT otherwise.
1753183982Sbz */
1754183982Sbzint
1755183982Sbzcr_canseeinpcb(struct ucred *cred, struct inpcb *inp)
1756183982Sbz{
1757183982Sbz	int error;
1758183982Sbz
1759183982Sbz	error = prison_check(cred, inp->inp_cred);
1760183982Sbz	if (error)
1761183982Sbz		return (ENOENT);
1762183982Sbz#ifdef MAC
1763183982Sbz	INP_LOCK_ASSERT(inp);
1764183982Sbz	error = mac_inpcb_check_visible(cred, inp);
1765183982Sbz	if (error)
1766183982Sbz		return (error);
1767183982Sbz#endif
1768183982Sbz	if (cr_seeotheruids(cred, inp->inp_cred))
1769183982Sbz		return (ENOENT);
1770183982Sbz	if (cr_seeothergids(cred, inp->inp_cred))
1771183982Sbz		return (ENOENT);
1772183982Sbz
1773183982Sbz	return (0);
1774183982Sbz}
1775183982Sbz#endif
1776183982Sbz
1777210226Strasz/*-
1778145234Srwatson * Determine whether td can wait for the exit of p.
1779145234Srwatson * Returns: 0 for permitted, an errno value otherwise
1780145234Srwatson * Locks: Sufficient locks to protect various components of td and p
1781145234Srwatson *        must be held.  td must be curthread, and a lock must
1782145234Srwatson *        be held for p.
1783145234Srwatson * References: td and p must be valid for the lifetime of the call
1784145234Srwatson
1785145234Srwatson */
1786145234Srwatsonint
1787145234Srwatsonp_canwait(struct thread *td, struct proc *p)
1788145234Srwatson{
1789145234Srwatson	int error;
1790145234Srwatson
1791145234Srwatson	KASSERT(td == curthread, ("%s: td not curthread", __func__));
1792145234Srwatson	PROC_LOCK_ASSERT(p, MA_OWNED);
1793195741Sjamie	if ((error = prison_check(td->td_ucred, p->p_ucred)))
1794145234Srwatson		return (error);
1795145234Srwatson#ifdef MAC
1796172930Srwatson	if ((error = mac_proc_check_wait(td->td_ucred, p)))
1797145234Srwatson		return (error);
1798145234Srwatson#endif
1799145234Srwatson#if 0
1800145234Srwatson	/* XXXMAC: This could have odd effects on some shells. */
1801145234Srwatson	if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred)))
1802145234Srwatson		return (error);
1803145234Srwatson#endif
1804145234Srwatson
1805145234Srwatson	return (0);
1806145234Srwatson}
1807145234Srwatson
180853518Sphk/*
18091541Srgrimes * Allocate a zeroed cred structure.
18101541Srgrimes */
18111541Srgrimesstruct ucred *
181293580Sjhbcrget(void)
18131541Srgrimes{
18141541Srgrimes	register struct ucred *cr;
18151541Srgrimes
1816184205Sdes	cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO);
1817150634Sjhb	refcount_init(&cr->cr_ref, 1);
1818170407Srwatson#ifdef AUDIT
1819170407Srwatson	audit_cred_init(cr);
1820170407Srwatson#endif
1821101001Srwatson#ifdef MAC
1822172930Srwatson	mac_cred_init(cr);
1823101001Srwatson#endif
1824194498Sbrooks	crextend(cr, XU_NGROUPS);
18251541Srgrimes	return (cr);
18261541Srgrimes}
18271541Srgrimes
18281541Srgrimes/*
182982466Srwatson * Claim another reference to a ucred structure.
183069401Salfred */
183184827Sjhbstruct ucred *
183293580Sjhbcrhold(struct ucred *cr)
183369401Salfred{
183469401Salfred
1835150634Sjhb	refcount_acquire(&cr->cr_ref);
183684827Sjhb	return (cr);
183769401Salfred}
183869401Salfred
183969401Salfred/*
1840167211Srwatson * Free a cred structure.  Throws away space when ref count gets to 0.
18411541Srgrimes */
18421549Srgrimesvoid
184393580Sjhbcrfree(struct ucred *cr)
18441541Srgrimes{
184569239Salfred
184675632Salfred	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
1847150634Sjhb	KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred"));
1848150634Sjhb	if (refcount_release(&cr->cr_ref)) {
184965495Struckman		/*
185065495Struckman		 * Some callers of crget(), such as nfs_statfs(),
185165495Struckman		 * allocate a temporary credential, but don't
185265495Struckman		 * allocate a uidinfo structure.
185365495Struckman		 */
185465495Struckman		if (cr->cr_uidinfo != NULL)
185565495Struckman			uifree(cr->cr_uidinfo);
185677277Srwatson		if (cr->cr_ruidinfo != NULL)
185777277Srwatson			uifree(cr->cr_ruidinfo);
185872786Srwatson		/*
185972786Srwatson		 * Free a prison, if any.
186072786Srwatson		 */
1861192895Sjamie		if (cr->cr_prison != NULL)
186272786Srwatson			prison_free(cr->cr_prison);
1863219304Strasz		if (cr->cr_loginclass != NULL)
1864219304Strasz			loginclass_free(cr->cr_loginclass);
1865170407Srwatson#ifdef AUDIT
1866170407Srwatson		audit_cred_destroy(cr);
1867170407Srwatson#endif
1868101001Srwatson#ifdef MAC
1869172930Srwatson		mac_cred_destroy(cr);
1870101001Srwatson#endif
1871194498Sbrooks		free(cr->cr_groups, M_CRED);
1872184205Sdes		free(cr, M_CRED);
187390756Sdillon	}
18741541Srgrimes}
18751541Srgrimes
18761541Srgrimes/*
187784827Sjhb * Check to see if this ucred is shared.
18781541Srgrimes */
187984827Sjhbint
188093580Sjhbcrshared(struct ucred *cr)
18811541Srgrimes{
18821541Srgrimes
1883150634Sjhb	return (cr->cr_ref > 1);
18841541Srgrimes}
18851541Srgrimes
18861541Srgrimes/*
188784827Sjhb * Copy a ucred's contents from a template.  Does not block.
188884827Sjhb */
188984827Sjhbvoid
189093580Sjhbcrcopy(struct ucred *dest, struct ucred *src)
189184827Sjhb{
189284827Sjhb
189384827Sjhb	KASSERT(crshared(dest) == 0, ("crcopy of shared ucred"));
189484827Sjhb	bcopy(&src->cr_startcopy, &dest->cr_startcopy,
189587218Srwatson	    (unsigned)((caddr_t)&src->cr_endcopy -
189684827Sjhb		(caddr_t)&src->cr_startcopy));
1897194498Sbrooks	crsetgroups(dest, src->cr_ngroups, src->cr_groups);
189884827Sjhb	uihold(dest->cr_uidinfo);
189984827Sjhb	uihold(dest->cr_ruidinfo);
1900192895Sjamie	prison_hold(dest->cr_prison);
1901219304Strasz	loginclass_hold(dest->cr_loginclass);
1902170407Srwatson#ifdef AUDIT
1903170407Srwatson	audit_cred_copy(src, dest);
1904170407Srwatson#endif
1905101001Srwatson#ifdef MAC
1906172930Srwatson	mac_cred_copy(src, dest);
1907101001Srwatson#endif
190884827Sjhb}
190984827Sjhb
191084827Sjhb/*
19111541Srgrimes * Dup cred struct to a new held one.
19121541Srgrimes */
19131541Srgrimesstruct ucred *
191493580Sjhbcrdup(struct ucred *cr)
19151541Srgrimes{
19161541Srgrimes	struct ucred *newcr;
19171541Srgrimes
191884827Sjhb	newcr = crget();
191984827Sjhb	crcopy(newcr, cr);
19201541Srgrimes	return (newcr);
19211541Srgrimes}
19221541Srgrimes
19231541Srgrimes/*
192491354Sdd * Fill in a struct xucred based on a struct ucred.
192591354Sdd */
192691354Sddvoid
192793580Sjhbcru2x(struct ucred *cr, struct xucred *xcr)
192891354Sdd{
1929194498Sbrooks	int ngroups;
193091354Sdd
193191354Sdd	bzero(xcr, sizeof(*xcr));
193291354Sdd	xcr->cr_version = XUCRED_VERSION;
193391354Sdd	xcr->cr_uid = cr->cr_uid;
1934194498Sbrooks
1935194498Sbrooks	ngroups = MIN(cr->cr_ngroups, XU_NGROUPS);
1936194498Sbrooks	xcr->cr_ngroups = ngroups;
1937194498Sbrooks	bcopy(cr->cr_groups, xcr->cr_groups,
1938194498Sbrooks	    ngroups * sizeof(*cr->cr_groups));
193991354Sdd}
194091354Sdd
194191354Sdd/*
1942167211Srwatson * small routine to swap a thread's current ucred for the correct one taken
1943167211Srwatson * from the process.
194490748Sjulian */
194590748Sjulianvoid
194690748Sjuliancred_update_thread(struct thread *td)
194790748Sjulian{
194890748Sjulian	struct proc *p;
194991405Sjhb	struct ucred *cred;
195090748Sjulian
195190748Sjulian	p = td->td_proc;
195291405Sjhb	cred = td->td_ucred;
195390748Sjulian	PROC_LOCK(p);
195490748Sjulian	td->td_ucred = crhold(p->p_ucred);
195590748Sjulian	PROC_UNLOCK(p);
195691405Sjhb	if (cred != NULL)
195791405Sjhb		crfree(cred);
195890748Sjulian}
195990748Sjulian
1960194498Sbrooksstruct ucred *
1961194498Sbrookscrcopysafe(struct proc *p, struct ucred *cr)
1962194498Sbrooks{
1963194498Sbrooks	struct ucred *oldcred;
1964194498Sbrooks	int groups;
1965194498Sbrooks
1966194498Sbrooks	PROC_LOCK_ASSERT(p, MA_OWNED);
1967194498Sbrooks
1968194498Sbrooks	oldcred = p->p_ucred;
1969194498Sbrooks	while (cr->cr_agroups < oldcred->cr_agroups) {
1970194498Sbrooks		groups = oldcred->cr_agroups;
1971194498Sbrooks		PROC_UNLOCK(p);
1972194498Sbrooks		crextend(cr, groups);
1973194498Sbrooks		PROC_LOCK(p);
1974194498Sbrooks		oldcred = p->p_ucred;
1975194498Sbrooks	}
1976194498Sbrooks	crcopy(cr, oldcred);
1977194498Sbrooks
1978194498Sbrooks	return (oldcred);
1979194498Sbrooks}
1980194498Sbrooks
198190748Sjulian/*
1982194498Sbrooks * Extend the passed in credential to hold n items.
1983194498Sbrooks */
1984194498Sbrooksstatic void
1985194498Sbrookscrextend(struct ucred *cr, int n)
1986194498Sbrooks{
1987194498Sbrooks	int cnt;
1988194498Sbrooks
1989194498Sbrooks	/* Truncate? */
1990194498Sbrooks	if (n <= cr->cr_agroups)
1991194498Sbrooks		return;
1992194498Sbrooks
1993194498Sbrooks	/*
1994194498Sbrooks	 * We extend by 2 each time since we're using a power of two
1995194498Sbrooks	 * allocator until we need enough groups to fill a page.
1996194498Sbrooks	 * Once we're allocating multiple pages, only allocate as many
1997194498Sbrooks	 * as we actually need.  The case of processes needing a
1998194498Sbrooks	 * non-power of two number of pages seems more likely than
1999194498Sbrooks	 * a real world process that adds thousands of groups one at a
2000194498Sbrooks	 * time.
2001194498Sbrooks	 */
2002194498Sbrooks	if ( n < PAGE_SIZE / sizeof(gid_t) ) {
2003194498Sbrooks		if (cr->cr_agroups == 0)
2004194498Sbrooks			cnt = MINALLOCSIZE / sizeof(gid_t);
2005194498Sbrooks		else
2006194498Sbrooks			cnt = cr->cr_agroups * 2;
2007194498Sbrooks
2008194498Sbrooks		while (cnt < n)
2009194498Sbrooks			cnt *= 2;
2010194498Sbrooks	} else
2011194498Sbrooks		cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t));
2012194498Sbrooks
2013194498Sbrooks	/* Free the old array. */
2014194498Sbrooks	if (cr->cr_groups)
2015194498Sbrooks		free(cr->cr_groups, M_CRED);
2016194498Sbrooks
2017194498Sbrooks	cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO);
2018194498Sbrooks	cr->cr_agroups = cnt;
2019194498Sbrooks}
2020194498Sbrooks
2021194498Sbrooks/*
2022194556Sbrooks * Copy groups in to a credential, preserving any necessary invariants.
2023194556Sbrooks * Currently this includes the sorting of all supplemental gids.
2024194556Sbrooks * crextend() must have been called before hand to ensure sufficient
2025194556Sbrooks * space is available.
2026194498Sbrooks */
2027194498Sbrooksstatic void
2028194498Sbrookscrsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups)
2029194498Sbrooks{
2030194556Sbrooks	int i;
2031194556Sbrooks	int j;
2032194556Sbrooks	gid_t g;
2033194498Sbrooks
2034194498Sbrooks	KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small"));
2035194498Sbrooks
2036194498Sbrooks	bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t));
2037194498Sbrooks	cr->cr_ngroups = ngrp;
2038194556Sbrooks
2039194556Sbrooks	/*
2040194556Sbrooks	 * Sort all groups except cr_groups[0] to allow groupmember to
2041194556Sbrooks	 * perform a binary search.
2042194556Sbrooks	 *
2043194556Sbrooks	 * XXX: If large numbers of groups become common this should
2044194556Sbrooks	 * be replaced with shell sort like linux uses or possibly
2045194556Sbrooks	 * heap sort.
2046194556Sbrooks	 */
2047194556Sbrooks	for (i = 2; i < ngrp; i++) {
2048194556Sbrooks		g = cr->cr_groups[i];
2049194556Sbrooks		for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--)
2050194556Sbrooks			cr->cr_groups[j + 1] = cr->cr_groups[j];
2051194556Sbrooks		cr->cr_groups[j + 1] = g;
2052194556Sbrooks	}
2053194498Sbrooks}
2054194498Sbrooks
2055194498Sbrooks/*
2056194498Sbrooks * Copy groups in to a credential after expanding it if required.
2057202143Sbrooks * Truncate the list to (ngroups_max + 1) if it is too large.
2058194498Sbrooks */
2059194498Sbrooksvoid
2060194498Sbrookscrsetgroups(struct ucred *cr, int ngrp, gid_t *groups)
2061194498Sbrooks{
2062194498Sbrooks
2063202143Sbrooks	if (ngrp > ngroups_max + 1)
2064202143Sbrooks		ngrp = ngroups_max + 1;
2065194498Sbrooks
2066194498Sbrooks	crextend(cr, ngrp);
2067194498Sbrooks	crsetgroups_locked(cr, ngrp, groups);
2068194498Sbrooks}
2069194498Sbrooks
2070194498Sbrooks/*
20711541Srgrimes * Get login name, if available.
20721541Srgrimes */
207312221Sbde#ifndef _SYS_SYSPROTO_H_
20741541Srgrimesstruct getlogin_args {
20751541Srgrimes	char	*namebuf;
20761541Srgrimes	u_int	namelen;
20771541Srgrimes};
207812221Sbde#endif
20791541Srgrimes/* ARGSUSED */
20801549Srgrimesint
2081225617Skmacysys_getlogin(struct thread *td, struct getlogin_args *uap)
20821541Srgrimes{
208391140Stanimura	char login[MAXLOGNAME];
208483366Sjulian	struct proc *p = td->td_proc;
2085274107Sdes	size_t len;
20861541Srgrimes
208723358Sache	if (uap->namelen > MAXLOGNAME)
208823359Sache		uap->namelen = MAXLOGNAME;
208991140Stanimura	PROC_LOCK(p);
209091140Stanimura	SESS_LOCK(p->p_session);
2091274107Sdes	len = strlcpy(login, p->p_session->s_login, uap->namelen) + 1;
209291140Stanimura	SESS_UNLOCK(p->p_session);
209391140Stanimura	PROC_UNLOCK(p);
2094274107Sdes	if (len > uap->namelen)
2095243021Sbapt		return (ERANGE);
2096274107Sdes	return (copyout(login, uap->namebuf, len));
20971541Srgrimes}
20981541Srgrimes
20991541Srgrimes/*
21001541Srgrimes * Set login name.
21011541Srgrimes */
210212221Sbde#ifndef _SYS_SYSPROTO_H_
21031541Srgrimesstruct setlogin_args {
21041541Srgrimes	char	*namebuf;
21051541Srgrimes};
210612221Sbde#endif
21071541Srgrimes/* ARGSUSED */
21081549Srgrimesint
2109225617Skmacysys_setlogin(struct thread *td, struct setlogin_args *uap)
21101541Srgrimes{
211183366Sjulian	struct proc *p = td->td_proc;
21121541Srgrimes	int error;
211323330Sache	char logintmp[MAXLOGNAME];
21141541Srgrimes
2115274107Sdes	CTASSERT(sizeof(p->p_session->s_login) >= sizeof(logintmp));
2116274107Sdes
2117170587Srwatson	error = priv_check(td, PRIV_PROC_SETLOGIN);
211894619Sjhb	if (error)
211994619Sjhb		return (error);
212099009Salfred	error = copyinstr(uap->namebuf, logintmp, sizeof(logintmp), NULL);
2121274107Sdes	if (error != 0) {
2122274107Sdes		if (error == ENAMETOOLONG)
2123274107Sdes			error = EINVAL;
2124274107Sdes		return (error);
212591140Stanimura	}
2126274107Sdes	PROC_LOCK(p);
2127274107Sdes	SESS_LOCK(p->p_session);
2128274107Sdes	strcpy(p->p_session->s_login, logintmp);
2129274107Sdes	SESS_UNLOCK(p->p_session);
2130274107Sdes	PROC_UNLOCK(p);
2131274107Sdes	return (0);
21321541Srgrimes}
213331891Ssef
213431891Ssefvoid
213593580Sjhbsetsugid(struct proc *p)
213631891Ssef{
213798403Salfred
213898403Salfred	PROC_LOCK_ASSERT(p, MA_OWNED);
213931891Ssef	p->p_flag |= P_SUGID;
214055707Ssef	if (!(p->p_pfsflags & PF_ISUGID))
214131891Ssef		p->p_stops = 0;
214231891Ssef}
214365495Struckman
2144210226Strasz/*-
214582466Srwatson * Change a process's effective uid.
214677183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified.
214777183Srwatson * References: newcred must be an exclusive credential reference for the
214877183Srwatson *             duration of the call.
214965495Struckman */
215065495Struckmanvoid
215198417Salfredchange_euid(struct ucred *newcred, struct uidinfo *euip)
215265495Struckman{
215365495Struckman
215498417Salfred	newcred->cr_uid = euip->ui_uid;
215598417Salfred	uihold(euip);
215677183Srwatson	uifree(newcred->cr_uidinfo);
215798417Salfred	newcred->cr_uidinfo = euip;
215865495Struckman}
215965495Struckman
2160210226Strasz/*-
216182466Srwatson * Change a process's effective gid.
216277183Srwatson * Side effects: newcred->cr_gid will be modified.
216377183Srwatson * References: newcred must be an exclusive credential reference for the
216477183Srwatson *             duration of the call.
216565495Struckman */
216667629Sgallatinvoid
216793580Sjhbchange_egid(struct ucred *newcred, gid_t egid)
216865495Struckman{
216965495Struckman
217077183Srwatson	newcred->cr_groups[0] = egid;
217165495Struckman}
217277183Srwatson
2173210226Strasz/*-
217482466Srwatson * Change a process's real uid.
217577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo
217677183Srwatson *               will be updated, and the old and new cr_ruidinfo proc
217777183Srwatson *               counts will be updated.
217877183Srwatson * References: newcred must be an exclusive credential reference for the
217977183Srwatson *             duration of the call.
218077183Srwatson */
218177183Srwatsonvoid
218298417Salfredchange_ruid(struct ucred *newcred, struct uidinfo *ruip)
218377183Srwatson{
218477183Srwatson
218577183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, -1, 0);
218698417Salfred	newcred->cr_ruid = ruip->ui_uid;
218798417Salfred	uihold(ruip);
218877183Srwatson	uifree(newcred->cr_ruidinfo);
218998417Salfred	newcred->cr_ruidinfo = ruip;
219077183Srwatson	(void)chgproccnt(newcred->cr_ruidinfo, 1, 0);
219177183Srwatson}
219277183Srwatson
2193210226Strasz/*-
219482466Srwatson * Change a process's real gid.
219577183Srwatson * Side effects: newcred->cr_rgid will be updated.
219677183Srwatson * References: newcred must be an exclusive credential reference for the
219777183Srwatson *             duration of the call.
219877183Srwatson */
219977183Srwatsonvoid
220093580Sjhbchange_rgid(struct ucred *newcred, gid_t rgid)
220177183Srwatson{
220277183Srwatson
220377183Srwatson	newcred->cr_rgid = rgid;
220477183Srwatson}
220577183Srwatson
2206210226Strasz/*-
220782466Srwatson * Change a process's saved uid.
220877183Srwatson * Side effects: newcred->cr_svuid will be updated.
220977183Srwatson * References: newcred must be an exclusive credential reference for the
221077183Srwatson *             duration of the call.
221177183Srwatson */
221277183Srwatsonvoid
221393580Sjhbchange_svuid(struct ucred *newcred, uid_t svuid)
221477183Srwatson{
221577183Srwatson
221677183Srwatson	newcred->cr_svuid = svuid;
221777183Srwatson}
221877183Srwatson
2219210226Strasz/*-
222082466Srwatson * Change a process's saved gid.
222177183Srwatson * Side effects: newcred->cr_svgid will be updated.
222277183Srwatson * References: newcred must be an exclusive credential reference for the
222377183Srwatson *             duration of the call.
222477183Srwatson */
222577183Srwatsonvoid
222693580Sjhbchange_svgid(struct ucred *newcred, gid_t svgid)
222777183Srwatson{
222877183Srwatson
222977183Srwatson	newcred->cr_svgid = svgid;
223077183Srwatson}
2231