kern_prot.c revision 89414
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 51541Srgrimes * All or some portions of this file are derived from material licensed 61541Srgrimes * to the University of California by American Telephone and Telegraph 71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81541Srgrimes * the permission of UNIX System Laboratories, Inc. 987218Srwatson * Copyright (c) 2000-2001 Robert N. M. Watson. All rights reserved. 101541Srgrimes * 111541Srgrimes * Redistribution and use in source and binary forms, with or without 121541Srgrimes * modification, are permitted provided that the following conditions 131541Srgrimes * are met: 141541Srgrimes * 1. Redistributions of source code must retain the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer. 161541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171541Srgrimes * notice, this list of conditions and the following disclaimer in the 181541Srgrimes * documentation and/or other materials provided with the distribution. 191541Srgrimes * 3. All advertising materials mentioning features or use of this software 201541Srgrimes * must display the following acknowledgement: 211541Srgrimes * This product includes software developed by the University of 221541Srgrimes * California, Berkeley and its contributors. 231541Srgrimes * 4. Neither the name of the University nor the names of its contributors 241541Srgrimes * may be used to endorse or promote products derived from this software 251541Srgrimes * without specific prior written permission. 261541Srgrimes * 271541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371541Srgrimes * SUCH DAMAGE. 381541Srgrimes * 391541Srgrimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 4050477Speter * $FreeBSD: head/sys/kern/kern_prot.c 89414 2002-01-16 06:55:30Z arr $ 411541Srgrimes */ 421541Srgrimes 431541Srgrimes/* 441541Srgrimes * System calls related to processes and protection 451541Srgrimes */ 461541Srgrimes 4731778Seivind#include "opt_compat.h" 4831778Seivind 491541Srgrimes#include <sys/param.h> 5076166Smarkm#include <sys/systm.h> 511541Srgrimes#include <sys/acct.h> 5241059Speter#include <sys/kernel.h> 5370317Sjake#include <sys/lock.h> 5476166Smarkm#include <sys/mutex.h> 551541Srgrimes#include <sys/proc.h> 5686304Sjhb#include <sys/sx.h> 5776166Smarkm#include <sys/sysproto.h> 5887218Srwatson#include <sys/jail.h> 591541Srgrimes#include <sys/malloc.h> 6031891Ssef#include <sys/pioctl.h> 6165495Struckman#include <sys/resourcevar.h> 6261287Srwatson#include <sys/sysctl.h> 631541Srgrimes 6430354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6530354Sphk 6689414SarrSYSCTL_DECL(_security); 6789414SarrSYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, 6887138Srwatson "BSD security policy"); 6987138Srwatson 7012221Sbde#ifndef _SYS_SYSPROTO_H_ 7111332Sswallacestruct getpid_args { 721541Srgrimes int dummy; 731541Srgrimes}; 7412221Sbde#endif 7558717Sdillon/* 7682749Sdillon * MPSAFE 7782749Sdillon */ 781541Srgrimes/* ARGSUSED */ 791549Srgrimesint 8083366Sjuliangetpid(td, uap) 8183366Sjulian struct thread *td; 8211332Sswallace struct getpid_args *uap; 831541Srgrimes{ 8483366Sjulian struct proc *p = td->td_proc; 8585564Sdillon int s; 861541Srgrimes 8785564Sdillon s = mtx_lock_giant(kern_giant_proc); 8883366Sjulian td->td_retval[0] = p->p_pid; 891541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9074728Sjhb PROC_LOCK(p); 9183366Sjulian td->td_retval[1] = p->p_pptr->p_pid; 9274728Sjhb PROC_UNLOCK(p); 931541Srgrimes#endif 9485564Sdillon mtx_unlock_giant(s); 951541Srgrimes return (0); 961541Srgrimes} 971541Srgrimes 9812221Sbde#ifndef _SYS_SYSPROTO_H_ 9911332Sswallacestruct getppid_args { 10011332Sswallace int dummy; 10111332Sswallace}; 10212221Sbde#endif 10382749Sdillon/* 10482749Sdillon * MPSAFE 10582749Sdillon */ 1061541Srgrimes/* ARGSUSED */ 1071549Srgrimesint 10883366Sjuliangetppid(td, uap) 10983366Sjulian struct thread *td; 11011332Sswallace struct getppid_args *uap; 1111541Srgrimes{ 11283366Sjulian struct proc *p = td->td_proc; 11385564Sdillon int s; 1141541Srgrimes 11585564Sdillon s = mtx_lock_giant(kern_giant_proc); 11674728Sjhb PROC_LOCK(p); 11783366Sjulian td->td_retval[0] = p->p_pptr->p_pid; 11874728Sjhb PROC_UNLOCK(p); 11985564Sdillon mtx_unlock_giant(s); 1201541Srgrimes return (0); 1211541Srgrimes} 1221541Srgrimes 12387466Srwatson/* 12487218Srwatson * Get process group ID; note that POSIX getpgrp takes no parameter. 12558717Sdillon */ 12612221Sbde#ifndef _SYS_SYSPROTO_H_ 12711332Sswallacestruct getpgrp_args { 12811332Sswallace int dummy; 12911332Sswallace}; 13012221Sbde#endif 13182749Sdillon/* 13282749Sdillon * MPSAFE 13382749Sdillon */ 1341549Srgrimesint 13583366Sjuliangetpgrp(td, uap) 13683366Sjulian struct thread *td; 13711332Sswallace struct getpgrp_args *uap; 1381541Srgrimes{ 13983366Sjulian struct proc *p = td->td_proc; 1401541Srgrimes 14182749Sdillon mtx_lock(&Giant); 14283366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 14382749Sdillon mtx_unlock(&Giant); 1441541Srgrimes return (0); 1451541Srgrimes} 1461541Srgrimes 14728401Speter/* Get an arbitary pid's process group id */ 14812221Sbde#ifndef _SYS_SYSPROTO_H_ 14928401Speterstruct getpgid_args { 15028401Speter pid_t pid; 15128401Speter}; 15228401Speter#endif 15382749Sdillon/* 15482749Sdillon * MPSAFE 15582749Sdillon */ 15628401Speterint 15783366Sjuliangetpgid(td, uap) 15883366Sjulian struct thread *td; 15928401Speter struct getpgid_args *uap; 16028401Speter{ 16183366Sjulian struct proc *p = td->td_proc; 16241726Struckman struct proc *pt; 16387218Srwatson int error, s; 16441726Struckman 16585564Sdillon s = mtx_lock_giant(kern_giant_proc); 16687218Srwatson error = 0; 16728401Speter if (uap->pid == 0) 16883366Sjulian td->td_retval[0] = p->p_pgrp->pg_id; 16984825Sjhb else if ((pt = pfind(uap->pid)) == NULL) 17084825Sjhb error = ESRCH; 17175893Sjhb else { 17284825Sjhb error = p_cansee(p, pt); 17384825Sjhb if (error == 0) 17484825Sjhb td->td_retval[0] = pt->p_pgrp->pg_id; 17575893Sjhb PROC_UNLOCK(pt); 17675893Sjhb } 17785564Sdillon mtx_unlock_giant(s); 17882749Sdillon return (error); 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 18982749Sdillon/* 19082749Sdillon * MPSAFE 19182749Sdillon */ 19228401Speterint 19383366Sjuliangetsid(td, uap) 19483366Sjulian struct thread *td; 19528401Speter struct getsid_args *uap; 19628401Speter{ 19783366Sjulian struct proc *p = td->td_proc; 19841726Struckman struct proc *pt; 19987218Srwatson int error; 20041726Struckman 20182749Sdillon mtx_lock(&Giant); 20287218Srwatson error = 0; 20384825Sjhb if (uap->pid == 0) 20483366Sjulian td->td_retval[0] = p->p_session->s_sid; 20584825Sjhb else if ((pt = pfind(uap->pid)) == NULL) 20684825Sjhb error = ESRCH; 20784825Sjhb else { 20884825Sjhb error = p_cansee(p, pt); 20984825Sjhb if (error == 0) 21084825Sjhb td->td_retval[0] = pt->p_session->s_sid; 21175893Sjhb PROC_UNLOCK(pt); 21275893Sjhb } 21382749Sdillon mtx_unlock(&Giant); 21482749Sdillon return (error); 21528401Speter} 21628401Speter 21728401Speter#ifndef _SYS_SYSPROTO_H_ 21811332Sswallacestruct getuid_args { 21911332Sswallace int dummy; 22011332Sswallace}; 22112221Sbde#endif 22282749Sdillon/* 22382749Sdillon * MPSAFE 22482749Sdillon */ 2251541Srgrimes/* ARGSUSED */ 2261549Srgrimesint 22783366Sjuliangetuid(td, uap) 22883366Sjulian struct thread *td; 22911332Sswallace struct getuid_args *uap; 2301541Srgrimes{ 23183366Sjulian struct proc *p = td->td_proc; 2321541Srgrimes 23382749Sdillon mtx_lock(&Giant); 23483366Sjulian td->td_retval[0] = p->p_ucred->cr_ruid; 2351541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 23683366Sjulian td->td_retval[1] = p->p_ucred->cr_uid; 2371541Srgrimes#endif 23882749Sdillon mtx_unlock(&Giant); 2391541Srgrimes return (0); 2401541Srgrimes} 2411541Srgrimes 24212221Sbde#ifndef _SYS_SYSPROTO_H_ 24311332Sswallacestruct geteuid_args { 24411332Sswallace int dummy; 24511332Sswallace}; 24612221Sbde#endif 24787218Srwatson/* 24887218Srwatson * MPSAFE 24987218Srwatson */ 2501541Srgrimes/* ARGSUSED */ 2511549Srgrimesint 25283366Sjuliangeteuid(td, uap) 25383366Sjulian struct thread *td; 25411332Sswallace struct geteuid_args *uap; 2551541Srgrimes{ 25682749Sdillon mtx_lock(&Giant); 25783366Sjulian td->td_retval[0] = td->td_proc->p_ucred->cr_uid; 25882749Sdillon mtx_unlock(&Giant); 2591541Srgrimes return (0); 2601541Srgrimes} 2611541Srgrimes 26212221Sbde#ifndef _SYS_SYSPROTO_H_ 26311332Sswallacestruct getgid_args { 26411332Sswallace int dummy; 26511332Sswallace}; 26612221Sbde#endif 26782749Sdillon/* 26882749Sdillon * MPSAFE 26982749Sdillon */ 2701541Srgrimes/* ARGSUSED */ 2711549Srgrimesint 27283366Sjuliangetgid(td, uap) 27383366Sjulian struct thread *td; 27411332Sswallace struct getgid_args *uap; 2751541Srgrimes{ 27683366Sjulian struct proc *p = td->td_proc; 2771541Srgrimes 27882749Sdillon mtx_lock(&Giant); 27983366Sjulian td->td_retval[0] = p->p_ucred->cr_rgid; 2801541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 28183366Sjulian td->td_retval[1] = p->p_ucred->cr_groups[0]; 2821541Srgrimes#endif 28382749Sdillon mtx_unlock(&Giant); 2841541Srgrimes return (0); 2851541Srgrimes} 2861541Srgrimes 2871541Srgrimes/* 2881541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2891541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2901541Srgrimes * correctly in a library function. 2911541Srgrimes */ 29212221Sbde#ifndef _SYS_SYSPROTO_H_ 29311332Sswallacestruct getegid_args { 29411332Sswallace int dummy; 29511332Sswallace}; 29612221Sbde#endif 29782749Sdillon/* 29882749Sdillon * MPSAFE 29982749Sdillon */ 3001541Srgrimes/* ARGSUSED */ 3011549Srgrimesint 30283366Sjuliangetegid(td, uap) 30383366Sjulian struct thread *td; 30411332Sswallace struct getegid_args *uap; 3051541Srgrimes{ 30683366Sjulian struct proc *p = td->td_proc; 3071541Srgrimes 30882749Sdillon mtx_lock(&Giant); 30983366Sjulian td->td_retval[0] = p->p_ucred->cr_groups[0]; 31082749Sdillon mtx_unlock(&Giant); 3111541Srgrimes return (0); 3121541Srgrimes} 3131541Srgrimes 31412221Sbde#ifndef _SYS_SYSPROTO_H_ 3151541Srgrimesstruct getgroups_args { 3161541Srgrimes u_int gidsetsize; 3171541Srgrimes gid_t *gidset; 3181541Srgrimes}; 31912221Sbde#endif 32082749Sdillon/* 32182749Sdillon * MPSAFE 32282749Sdillon */ 3231549Srgrimesint 32483366Sjuliangetgroups(td, uap) 32583366Sjulian struct thread *td; 32687218Srwatson register struct getgroups_args *uap; 3271541Srgrimes{ 32882749Sdillon struct ucred *cred; 32983366Sjulian struct proc *p = td->td_proc; 33077183Srwatson u_int ngrp; 33187218Srwatson int error; 3321541Srgrimes 33382749Sdillon mtx_lock(&Giant); 33487218Srwatson error = 0; 33582749Sdillon cred = p->p_ucred; 3361541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 33783366Sjulian td->td_retval[0] = cred->cr_ngroups; 33882749Sdillon goto done2; 3391541Srgrimes } 34082749Sdillon if (ngrp < cred->cr_ngroups) { 34182749Sdillon error = EINVAL; 34282749Sdillon goto done2; 34382749Sdillon } 34477183Srwatson ngrp = cred->cr_ngroups; 34577183Srwatson if ((error = copyout((caddr_t)cred->cr_groups, 34687218Srwatson (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 34782749Sdillon goto done2; 34883366Sjulian td->td_retval[0] = ngrp; 34982749Sdillondone2: 35082749Sdillon mtx_unlock(&Giant); 35182749Sdillon return (error); 3521541Srgrimes} 3531541Srgrimes 35412221Sbde#ifndef _SYS_SYSPROTO_H_ 35512207Sbdestruct setsid_args { 35611332Sswallace int dummy; 35711332Sswallace}; 35812221Sbde#endif 35982749Sdillon/* 36082749Sdillon * MPSAFE 36182749Sdillon */ 3621541Srgrimes/* ARGSUSED */ 3631549Srgrimesint 36483366Sjuliansetsid(td, uap) 36583366Sjulian register struct thread *td; 36612207Sbde struct setsid_args *uap; 3671541Srgrimes{ 36882749Sdillon int error; 36983366Sjulian struct proc *p = td->td_proc; 3701541Srgrimes 37182749Sdillon mtx_lock(&Giant); 37287218Srwatson if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) 37382749Sdillon error = EPERM; 37487218Srwatson else { 3751541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 37683366Sjulian td->td_retval[0] = p->p_pid; 37782749Sdillon error = 0; 3781541Srgrimes } 37982749Sdillon mtx_unlock(&Giant); 38082749Sdillon return (error); 3811541Srgrimes} 3821541Srgrimes 3831541Srgrimes/* 3841541Srgrimes * set process group (setpgid/old setpgrp) 3851541Srgrimes * 3861541Srgrimes * caller does setpgid(targpid, targpgid) 3871541Srgrimes * 3881541Srgrimes * pid must be caller or child of caller (ESRCH) 3891541Srgrimes * if a child 3901541Srgrimes * pid must be in same session (EPERM) 3911541Srgrimes * pid can't have done an exec (EACCES) 3921541Srgrimes * if pgid != pid 3931541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3941541Srgrimes * pid must not be session leader (EPERM) 3951541Srgrimes */ 39612221Sbde#ifndef _SYS_SYSPROTO_H_ 3971541Srgrimesstruct setpgid_args { 39887218Srwatson int pid; /* target process id */ 39987218Srwatson int pgid; /* target pgrp id */ 4001541Srgrimes}; 40112221Sbde#endif 40282749Sdillon/* 40382749Sdillon * MPSAFE 40482749Sdillon */ 4051541Srgrimes/* ARGSUSED */ 4061549Srgrimesint 40783366Sjuliansetpgid(td, uap) 40883366Sjulian struct thread *td; 4091541Srgrimes register struct setpgid_args *uap; 4101541Srgrimes{ 41183366Sjulian struct proc *curp = td->td_proc; 41287218Srwatson register struct proc *targp; /* target process */ 41387218Srwatson register struct pgrp *pgrp; /* target pgrp */ 41475448Srwatson int error; 4151541Srgrimes 41620677Sbde if (uap->pgid < 0) 41720677Sbde return (EINVAL); 41882749Sdillon mtx_lock(&Giant); 41986304Sjhb sx_slock(&proctree_lock); 4201541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 42175893Sjhb if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 42275893Sjhb if (targp) 42375893Sjhb PROC_UNLOCK(targp); 42482749Sdillon error = ESRCH; 42582749Sdillon goto done2; 42675893Sjhb } 42779335Srwatson if ((error = p_cansee(curproc, targp))) { 42875893Sjhb PROC_UNLOCK(targp); 42982749Sdillon goto done2; 43075893Sjhb } 43175893Sjhb if (targp->p_pgrp == NULL || 43275893Sjhb targp->p_session != curp->p_session) { 43375893Sjhb PROC_UNLOCK(targp); 43482749Sdillon error = EPERM; 43582749Sdillon goto done2; 43675893Sjhb } 43775893Sjhb if (targp->p_flag & P_EXEC) { 43875893Sjhb PROC_UNLOCK(targp); 43982749Sdillon error = EACCES; 44082749Sdillon goto done2; 44175893Sjhb } 44275893Sjhb } else { 4431541Srgrimes targp = curp; 44475893Sjhb PROC_LOCK(curp); /* XXX: not needed */ 44575893Sjhb } 44675893Sjhb if (SESS_LEADER(targp)) { 44775893Sjhb PROC_UNLOCK(targp); 44882749Sdillon error = EPERM; 44982749Sdillon goto done2; 45075893Sjhb } 45187218Srwatson if (uap->pgid == 0) 4521541Srgrimes uap->pgid = targp->p_pid; 45387218Srwatson else if (uap->pgid != targp->p_pid) { 4541541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 45587218Srwatson pgrp->pg_session != curp->p_session) { 45675893Sjhb PROC_UNLOCK(targp); 45782749Sdillon error = EPERM; 45882749Sdillon goto done2; 45975893Sjhb } 46082749Sdillon } 46175893Sjhb /* XXX: We should probably hold the lock across enterpgrp. */ 46275893Sjhb PROC_UNLOCK(targp); 46382749Sdillon error = enterpgrp(targp, uap->pgid, 0); 46482749Sdillondone2: 46586304Sjhb sx_sunlock(&proctree_lock); 46682749Sdillon mtx_unlock(&Giant); 46782749Sdillon return (error); 4681541Srgrimes} 4691541Srgrimes 47024448Speter/* 47124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 47272093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 47324448Speter * case of "appropriate privilege". Once the rules are expanded out, this 47424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 47524448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 47624448Speter * does not set the saved id - this is dangerous for traditional BSD 47724448Speter * programs. For this reason, we *really* do not want to set 47824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 47924448Speter */ 48024448Speter#define POSIX_APPENDIX_B_4_2_2 48124448Speter 48212221Sbde#ifndef _SYS_SYSPROTO_H_ 4831541Srgrimesstruct setuid_args { 4841541Srgrimes uid_t uid; 4851541Srgrimes}; 48612221Sbde#endif 48782749Sdillon/* 48882749Sdillon * MPSAFE 48982749Sdillon */ 4901541Srgrimes/* ARGSUSED */ 4911549Srgrimesint 49283366Sjuliansetuid(td, uap) 49383366Sjulian struct thread *td; 4941541Srgrimes struct setuid_args *uap; 4951541Srgrimes{ 49683366Sjulian struct proc *p = td->td_proc; 49777183Srwatson struct ucred *newcred, *oldcred; 49877183Srwatson uid_t uid; 49987218Srwatson int error; 5001541Srgrimes 50177183Srwatson uid = uap->uid; 50282749Sdillon mtx_lock(&Giant); 50387218Srwatson error = 0; 50487219Srwatson oldcred = p->p_ucred; 50587466Srwatson 50624448Speter /* 50724448Speter * See if we have "permission" by POSIX 1003.1 rules. 50824448Speter * 50987218Srwatson * Note that setuid(geteuid()) is a special case of 51024448Speter * "appropriate privileges" in appendix B.4.2.2. We need 51172093Sasmodai * to use this clause to be compatible with traditional BSD 51224448Speter * semantics. Basically, it means that "setuid(xx)" sets all 51324448Speter * three id's (assuming you have privs). 51424448Speter * 51524448Speter * Notes on the logic. We do things in three steps. 51624448Speter * 1: We determine if the euid is going to change, and do EPERM 51724448Speter * right away. We unconditionally change the euid later if this 51824448Speter * test is satisfied, simplifying that part of the logic. 51987218Srwatson * 2: We determine if the real and/or saved uids are going to 52024448Speter * change. Determined by compile options. 52124448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 52224448Speter */ 52377183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 52417994Sache#ifdef _POSIX_SAVED_IDS 52577183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 52617994Sache#endif 52724448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 52877183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 52924448Speter#endif 53087218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 53182749Sdillon goto done2; 53224448Speter 53377183Srwatson newcred = crdup(oldcred); 53424448Speter#ifdef _POSIX_SAVED_IDS 5351541Srgrimes /* 53624448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 53724448Speter * If so, we are changing the real uid and/or saved uid. 5381541Srgrimes */ 53917994Sache if ( 54024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 54177183Srwatson uid == oldcred->cr_uid || 54217994Sache#endif 54377183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 54417994Sache#endif 54524448Speter { 54624448Speter /* 54765495Struckman * Set the real uid and transfer proc count to new user. 54824448Speter */ 54977183Srwatson if (uid != oldcred->cr_ruid) { 55077183Srwatson change_ruid(newcred, uid); 55165495Struckman setsugid(p); 55224448Speter } 55324448Speter /* 55424448Speter * Set saved uid 55524448Speter * 55624448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 55724448Speter * the security of seteuid() depends on it. B.4.2.2 says it 55824448Speter * is important that we should do this. 55924448Speter */ 56077183Srwatson if (uid != oldcred->cr_svuid) { 56177183Srwatson change_svuid(newcred, uid); 56231891Ssef setsugid(p); 56324448Speter } 5648141Sache } 56524448Speter 56624448Speter /* 56724448Speter * In all permitted cases, we are changing the euid. 56824448Speter * Copy credentials so other references do not see our changes. 56924448Speter */ 57077183Srwatson if (uid != oldcred->cr_uid) { 57177183Srwatson change_euid(newcred, uid); 57231891Ssef setsugid(p); 57324448Speter } 57477183Srwatson p->p_ucred = newcred; 57577183Srwatson crfree(oldcred); 57682749Sdillondone2: 57782749Sdillon mtx_unlock(&Giant); 57882749Sdillon return (error); 5791541Srgrimes} 5801541Srgrimes 58112221Sbde#ifndef _SYS_SYSPROTO_H_ 5821541Srgrimesstruct seteuid_args { 5831541Srgrimes uid_t euid; 5841541Srgrimes}; 58512221Sbde#endif 58682749Sdillon/* 58782749Sdillon * MPSAFE 58882749Sdillon */ 5891541Srgrimes/* ARGSUSED */ 5901549Srgrimesint 59183366Sjulianseteuid(td, uap) 59283366Sjulian struct thread *td; 5931541Srgrimes struct seteuid_args *uap; 5941541Srgrimes{ 59583366Sjulian struct proc *p = td->td_proc; 59677183Srwatson struct ucred *newcred, *oldcred; 59777183Srwatson uid_t euid; 59887218Srwatson int error; 5991541Srgrimes 6001541Srgrimes euid = uap->euid; 60182749Sdillon mtx_lock(&Giant); 60287218Srwatson error = 0; 60377183Srwatson oldcred = p->p_ucred; 60477183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 60577183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 60687218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 60782749Sdillon goto done2; 6081541Srgrimes /* 6091541Srgrimes * Everything's okay, do it. Copy credentials so other references do 6101541Srgrimes * not see our changes. 6111541Srgrimes */ 61277183Srwatson newcred = crdup(oldcred); 61377183Srwatson if (oldcred->cr_uid != euid) { 61477183Srwatson change_euid(newcred, euid); 61531891Ssef setsugid(p); 61624449Speter } 61777183Srwatson p->p_ucred = newcred; 61877183Srwatson crfree(oldcred); 61982749Sdillondone2: 62082749Sdillon mtx_unlock(&Giant); 62182749Sdillon return (error); 6221541Srgrimes} 6231541Srgrimes 62412221Sbde#ifndef _SYS_SYSPROTO_H_ 6251541Srgrimesstruct setgid_args { 6261541Srgrimes gid_t gid; 6271541Srgrimes}; 62812221Sbde#endif 62982749Sdillon/* 63082749Sdillon * MPSAFE 63182749Sdillon */ 6321541Srgrimes/* ARGSUSED */ 6331549Srgrimesint 63483366Sjuliansetgid(td, uap) 63583366Sjulian struct thread *td; 6361541Srgrimes 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; 64482749Sdillon mtx_lock(&Giant); 64587218Srwatson error = 0; 64677183Srwatson oldcred = p->p_ucred; 64787466Srwatson 64824448Speter /* 64924448Speter * See if we have "permission" by POSIX 1003.1 rules. 65024448Speter * 65124448Speter * Note that setgid(getegid()) is a special case of 65224448Speter * "appropriate privileges" in appendix B.4.2.2. We need 65372093Sasmodai * to use this clause to be compatible with traditional BSD 65424448Speter * semantics. Basically, it means that "setgid(xx)" sets all 65524448Speter * three id's (assuming you have privs). 65624448Speter * 65724448Speter * For notes on the logic here, see setuid() above. 65824448Speter */ 65977183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 66017994Sache#ifdef _POSIX_SAVED_IDS 66177183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 66217994Sache#endif 66324448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 66477183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 66524448Speter#endif 66687218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 66782749Sdillon goto done2; 66824448Speter 66977183Srwatson newcred = crdup(oldcred); 67017994Sache#ifdef _POSIX_SAVED_IDS 67124448Speter /* 67224448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 67324448Speter * If so, we are changing the real uid and saved gid. 67424448Speter */ 67524448Speter if ( 67624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 67777183Srwatson gid == oldcred->cr_groups[0] || 67817994Sache#endif 67977183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 68024448Speter#endif 68124448Speter { 68224448Speter /* 68324448Speter * Set real gid 68424448Speter */ 68577183Srwatson if (oldcred->cr_rgid != gid) { 68677183Srwatson change_rgid(newcred, gid); 68731891Ssef setsugid(p); 68824448Speter } 68924448Speter /* 69024448Speter * Set saved gid 69124448Speter * 69224448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 69324448Speter * the security of setegid() depends on it. B.4.2.2 says it 69424448Speter * is important that we should do this. 69524448Speter */ 69677183Srwatson if (oldcred->cr_svgid != gid) { 69777183Srwatson change_svgid(newcred, gid); 69831891Ssef setsugid(p); 69924448Speter } 7008141Sache } 70124448Speter /* 70224448Speter * In all cases permitted cases, we are changing the egid. 70324448Speter * Copy credentials so other references do not see our changes. 70424448Speter */ 70577183Srwatson if (oldcred->cr_groups[0] != gid) { 70677183Srwatson change_egid(newcred, gid); 70731891Ssef setsugid(p); 70824448Speter } 70977183Srwatson p->p_ucred = newcred; 71077183Srwatson crfree(oldcred); 71182749Sdillondone2: 71282749Sdillon mtx_unlock(&Giant); 71382749Sdillon return (error); 7141541Srgrimes} 7151541Srgrimes 71612221Sbde#ifndef _SYS_SYSPROTO_H_ 7171541Srgrimesstruct setegid_args { 7181541Srgrimes gid_t egid; 7191541Srgrimes}; 72012221Sbde#endif 72182749Sdillon/* 72282749Sdillon * MPSAFE 72382749Sdillon */ 7241541Srgrimes/* ARGSUSED */ 7251549Srgrimesint 72683366Sjuliansetegid(td, uap) 72783366Sjulian struct thread *td; 7281541Srgrimes struct setegid_args *uap; 7291541Srgrimes{ 73083366Sjulian struct proc *p = td->td_proc; 73177183Srwatson struct ucred *newcred, *oldcred; 73277183Srwatson gid_t egid; 73387218Srwatson int error; 7341541Srgrimes 7351541Srgrimes egid = uap->egid; 73682749Sdillon mtx_lock(&Giant); 73787218Srwatson error = 0; 73877183Srwatson oldcred = p->p_ucred; 73977183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 74077183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 74187218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 74282749Sdillon goto done2; 74377183Srwatson newcred = crdup(oldcred); 74477183Srwatson if (oldcred->cr_groups[0] != egid) { 74577183Srwatson change_egid(newcred, egid); 74631891Ssef setsugid(p); 74724449Speter } 74877183Srwatson p->p_ucred = newcred; 74977183Srwatson crfree(oldcred); 75082749Sdillondone2: 75182749Sdillon mtx_unlock(&Giant); 75282749Sdillon return (error); 7531541Srgrimes} 7541541Srgrimes 75512221Sbde#ifndef _SYS_SYSPROTO_H_ 7561541Srgrimesstruct setgroups_args { 7571541Srgrimes u_int gidsetsize; 7581541Srgrimes gid_t *gidset; 7591541Srgrimes}; 76012221Sbde#endif 76182749Sdillon/* 76282749Sdillon * MPSAFE 76382749Sdillon */ 7641541Srgrimes/* ARGSUSED */ 7651549Srgrimesint 76683366Sjuliansetgroups(td, uap) 76783366Sjulian struct thread *td; 7681541Srgrimes struct setgroups_args *uap; 7691541Srgrimes{ 77083366Sjulian struct proc *p = td->td_proc; 77177183Srwatson struct ucred *newcred, *oldcred; 77277183Srwatson u_int ngrp; 7731541Srgrimes int error; 7741541Srgrimes 77587220Srwatson ngrp = uap->gidsetsize; 77682749Sdillon mtx_lock(&Giant); 77777183Srwatson oldcred = p->p_ucred; 77887218Srwatson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 77982749Sdillon goto done2; 78082749Sdillon if (ngrp > NGROUPS) { 78182749Sdillon error = EINVAL; 78282749Sdillon goto done2; 78382749Sdillon } 78424447Speter /* 78524447Speter * XXX A little bit lazy here. We could test if anything has 78624447Speter * changed before crcopy() and setting P_SUGID. 78724447Speter */ 78877183Srwatson newcred = crdup(oldcred); 78924447Speter if (ngrp < 1) { 79024447Speter /* 79124447Speter * setgroups(0, NULL) is a legitimate way of clearing the 79224447Speter * groups vector on non-BSD systems (which generally do not 79324447Speter * have the egid in the groups[0]). We risk security holes 79424447Speter * when running non-BSD software if we do not do the same. 79524447Speter */ 79677183Srwatson newcred->cr_ngroups = 1; 79724447Speter } else { 79824447Speter if ((error = copyin((caddr_t)uap->gidset, 79977183Srwatson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 80077183Srwatson crfree(newcred); 80182749Sdillon goto done2; 80277183Srwatson } 80377183Srwatson newcred->cr_ngroups = ngrp; 80424447Speter } 80531891Ssef setsugid(p); 80677183Srwatson p->p_ucred = newcred; 80777183Srwatson crfree(oldcred); 80882749Sdillondone2: 80982749Sdillon mtx_unlock(&Giant); 81082749Sdillon return (error); 8111541Srgrimes} 8121541Srgrimes 81312221Sbde#ifndef _SYS_SYSPROTO_H_ 8141541Srgrimesstruct setreuid_args { 8159238Sache uid_t ruid; 8169238Sache uid_t euid; 8171541Srgrimes}; 81812221Sbde#endif 81982749Sdillon/* 82082749Sdillon * MPSAFE 82182749Sdillon */ 8221541Srgrimes/* ARGSUSED */ 8231549Srgrimesint 82483366Sjuliansetreuid(td, uap) 82583366Sjulian register struct thread *td; 8261541Srgrimes struct setreuid_args *uap; 8271541Srgrimes{ 82883366Sjulian struct proc *p = td->td_proc; 82977183Srwatson struct ucred *newcred, *oldcred; 83087218Srwatson uid_t euid, ruid; 83187218Srwatson int error; 8321541Srgrimes 83387218Srwatson euid = uap->euid; 8349238Sache ruid = uap->ruid; 83582749Sdillon mtx_lock(&Giant); 83687218Srwatson error = 0; 83777183Srwatson oldcred = p->p_ucred; 83877183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 83977183Srwatson ruid != oldcred->cr_svuid) || 84077183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 84177183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 84287218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 84382749Sdillon goto done2; 84477183Srwatson newcred = crdup(oldcred); 84577183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 84677183Srwatson change_euid(newcred, euid); 84731891Ssef setsugid(p); 84824450Speter } 84977183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 85077183Srwatson change_ruid(newcred, ruid); 85131891Ssef setsugid(p); 8528135Sache } 85377183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 85477183Srwatson newcred->cr_svuid != newcred->cr_uid) { 85577183Srwatson change_svuid(newcred, newcred->cr_uid); 85631891Ssef setsugid(p); 85724450Speter } 85877183Srwatson p->p_ucred = newcred; 85977183Srwatson crfree(oldcred); 86082749Sdillondone2: 86182749Sdillon mtx_unlock(&Giant); 86282749Sdillon return (error); 8631541Srgrimes} 8641541Srgrimes 86512221Sbde#ifndef _SYS_SYSPROTO_H_ 8661541Srgrimesstruct setregid_args { 8679238Sache gid_t rgid; 8689238Sache gid_t egid; 8691541Srgrimes}; 87012221Sbde#endif 87182749Sdillon/* 87282749Sdillon * MPSAFE 87382749Sdillon */ 8741541Srgrimes/* ARGSUSED */ 8751549Srgrimesint 87683366Sjuliansetregid(td, uap) 87783366Sjulian register struct thread *td; 8781541Srgrimes struct setregid_args *uap; 8791541Srgrimes{ 88083366Sjulian struct proc *p = td->td_proc; 88177183Srwatson struct ucred *newcred, *oldcred; 88287218Srwatson gid_t egid, rgid; 88387218Srwatson int error; 8841541Srgrimes 88587218Srwatson egid = uap->egid; 8869238Sache rgid = uap->rgid; 88782749Sdillon mtx_lock(&Giant); 88887218Srwatson error = 0; 88977183Srwatson oldcred = p->p_ucred; 89077183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 89177183Srwatson rgid != oldcred->cr_svgid) || 89277183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 89377183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 89487218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 89582749Sdillon goto done2; 89677183Srwatson newcred = crdup(oldcred); 89777183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 89877183Srwatson change_egid(newcred, egid); 89931891Ssef setsugid(p); 90024450Speter } 90177183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 90277183Srwatson change_rgid(newcred, rgid); 90331891Ssef setsugid(p); 90424450Speter } 90577183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 90677183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 90777183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 90831891Ssef setsugid(p); 90924450Speter } 91077812Sru p->p_ucred = newcred; 91177812Sru crfree(oldcred); 91282749Sdillondone2: 91382749Sdillon mtx_unlock(&Giant); 91482749Sdillon return (error); 9151541Srgrimes} 9161541Srgrimes 91756115Speter/* 91856115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 91956115Speter * saved uid is explicit. 92056115Speter */ 92156115Speter 92224453Speter#ifndef _SYS_SYSPROTO_H_ 92356115Speterstruct setresuid_args { 92456115Speter uid_t ruid; 92556115Speter uid_t euid; 92656115Speter uid_t suid; 92756115Speter}; 92856115Speter#endif 92982749Sdillon/* 93082749Sdillon * MPSAFE 93182749Sdillon */ 93256115Speter/* ARGSUSED */ 93356115Speterint 93483366Sjuliansetresuid(td, uap) 93583366Sjulian register struct thread *td; 93656115Speter struct setresuid_args *uap; 93756115Speter{ 93883366Sjulian struct proc *p = td->td_proc; 93977183Srwatson struct ucred *newcred, *oldcred; 94087218Srwatson uid_t euid, ruid, suid; 94156115Speter int error; 94256115Speter 94387218Srwatson euid = uap->euid; 94456115Speter ruid = uap->ruid; 94556115Speter suid = uap->suid; 94682749Sdillon mtx_lock(&Giant); 94777183Srwatson oldcred = p->p_ucred; 94877183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 94977183Srwatson ruid != oldcred->cr_svuid && 95077183Srwatson ruid != oldcred->cr_uid) || 95177183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 95277183Srwatson euid != oldcred->cr_svuid && 95377183Srwatson euid != oldcred->cr_uid) || 95477183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 95577183Srwatson suid != oldcred->cr_svuid && 95677183Srwatson suid != oldcred->cr_uid)) && 95787218Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 95882749Sdillon goto done2; 95977183Srwatson newcred = crdup(oldcred); 96077183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 96177183Srwatson change_euid(newcred, euid); 96256115Speter setsugid(p); 96356115Speter } 96477183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 96577183Srwatson change_ruid(newcred, ruid); 96656115Speter setsugid(p); 96756115Speter } 96877183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 96977183Srwatson change_svuid(newcred, suid); 97056115Speter setsugid(p); 97156115Speter } 97277183Srwatson p->p_ucred = newcred; 97377183Srwatson crfree(oldcred); 97482749Sdillon error = 0; 97582749Sdillondone2: 97682749Sdillon mtx_unlock(&Giant); 97782749Sdillon return (error); 97856115Speter} 97956115Speter 98056115Speter/* 98156115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 98256115Speter * saved gid is explicit. 98356115Speter */ 98456115Speter 98556115Speter#ifndef _SYS_SYSPROTO_H_ 98656115Speterstruct setresgid_args { 98756115Speter gid_t rgid; 98856115Speter gid_t egid; 98956115Speter gid_t sgid; 99056115Speter}; 99156115Speter#endif 99287466Srwatson/* 99382749Sdillon * MPSAFE 99482749Sdillon */ 99556115Speter/* ARGSUSED */ 99656115Speterint 99783366Sjuliansetresgid(td, uap) 99883366Sjulian register struct thread *td; 99956115Speter struct setresgid_args *uap; 100056115Speter{ 100183366Sjulian struct proc *p = td->td_proc; 100277183Srwatson struct ucred *newcred, *oldcred; 100387218Srwatson gid_t egid, rgid, sgid; 100456115Speter int error; 100556115Speter 100687218Srwatson egid = uap->egid; 100756115Speter rgid = uap->rgid; 100856115Speter sgid = uap->sgid; 100982749Sdillon mtx_lock(&Giant); 101077183Srwatson oldcred = p->p_ucred; 101177183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 101277183Srwatson rgid != oldcred->cr_svgid && 101377183Srwatson rgid != oldcred->cr_groups[0]) || 101477183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 101577183Srwatson egid != oldcred->cr_svgid && 101677183Srwatson egid != oldcred->cr_groups[0]) || 101777183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 101877183Srwatson sgid != oldcred->cr_svgid && 101977183Srwatson sgid != oldcred->cr_groups[0])) && 102087466Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 102182749Sdillon goto done2; 102277183Srwatson newcred = crdup(oldcred); 102377183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 102477183Srwatson change_egid(newcred, egid); 102556115Speter setsugid(p); 102656115Speter } 102777183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 102877183Srwatson change_rgid(newcred, rgid); 102956115Speter setsugid(p); 103056115Speter } 103177183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 103277183Srwatson change_svgid(newcred, sgid); 103356115Speter setsugid(p); 103456115Speter } 103577183Srwatson p->p_ucred = newcred; 103677183Srwatson crfree(oldcred); 103782749Sdillon error = 0; 103882749Sdillondone2: 103982749Sdillon mtx_unlock(&Giant); 104082749Sdillon return (error); 104156115Speter} 104256115Speter 104356115Speter#ifndef _SYS_SYSPROTO_H_ 104456115Speterstruct getresuid_args { 104556115Speter uid_t *ruid; 104656115Speter uid_t *euid; 104756115Speter uid_t *suid; 104856115Speter}; 104956115Speter#endif 105082749Sdillon/* 105182749Sdillon * MPSAFE 105282749Sdillon */ 105356115Speter/* ARGSUSED */ 105456115Speterint 105583366Sjuliangetresuid(td, uap) 105683366Sjulian register struct thread *td; 105756115Speter struct getresuid_args *uap; 105856115Speter{ 105982749Sdillon struct ucred *cred; 106083366Sjulian struct proc *p = td->td_proc; 106156115Speter int error1 = 0, error2 = 0, error3 = 0; 106256115Speter 106382749Sdillon mtx_lock(&Giant); 106482749Sdillon cred = p->p_ucred; 106556115Speter if (uap->ruid) 106677183Srwatson error1 = copyout((caddr_t)&cred->cr_ruid, 106777183Srwatson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 106856115Speter if (uap->euid) 106977183Srwatson error2 = copyout((caddr_t)&cred->cr_uid, 107077183Srwatson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 107156115Speter if (uap->suid) 107277183Srwatson error3 = copyout((caddr_t)&cred->cr_svuid, 107377183Srwatson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 107482749Sdillon mtx_unlock(&Giant); 107587218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 107656115Speter} 107756115Speter 107856115Speter#ifndef _SYS_SYSPROTO_H_ 107956115Speterstruct getresgid_args { 108056115Speter gid_t *rgid; 108156115Speter gid_t *egid; 108256115Speter gid_t *sgid; 108356115Speter}; 108456115Speter#endif 108582749Sdillon/* 108682749Sdillon * MPSAFE 108782749Sdillon */ 108856115Speter/* ARGSUSED */ 108956115Speterint 109083366Sjuliangetresgid(td, uap) 109183366Sjulian register struct thread *td; 109256115Speter struct getresgid_args *uap; 109356115Speter{ 109482749Sdillon struct ucred *cred; 109583366Sjulian struct proc *p = td->td_proc; 109656115Speter int error1 = 0, error2 = 0, error3 = 0; 109756115Speter 109882749Sdillon mtx_lock(&Giant); 109982749Sdillon cred = p->p_ucred; 110056115Speter if (uap->rgid) 110177183Srwatson error1 = copyout((caddr_t)&cred->cr_rgid, 110277183Srwatson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 110356115Speter if (uap->egid) 110477183Srwatson error2 = copyout((caddr_t)&cred->cr_groups[0], 110577183Srwatson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 110656115Speter if (uap->sgid) 110777183Srwatson error3 = copyout((caddr_t)&cred->cr_svgid, 110877183Srwatson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 110982749Sdillon mtx_unlock(&Giant); 111087218Srwatson return (error1 ? error1 : error2 ? error2 : error3); 111156115Speter} 111256115Speter 111356115Speter#ifndef _SYS_SYSPROTO_H_ 111424453Speterstruct issetugid_args { 111524453Speter int dummy; 111624453Speter}; 111724453Speter#endif 111887218Srwatson/* 111987218Srwatson * NOT MPSAFE? 112087218Srwatson */ 112124453Speter/* ARGSUSED */ 112224453Speterint 112383366Sjulianissetugid(td, uap) 112483366Sjulian register struct thread *td; 112524453Speter struct issetugid_args *uap; 112624453Speter{ 112783366Sjulian struct proc *p = td->td_proc; 112883366Sjulian 112924453Speter /* 113024453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 113124453Speter * we use P_SUGID because we consider changing the owners as 113224453Speter * "tainting" as well. 113324453Speter * This is significant for procs that start as root and "become" 113424453Speter * a user without an exec - programs cannot know *everything* 113524453Speter * that libc *might* have put in their data segment. 113624453Speter */ 113783366Sjulian td->td_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 113824453Speter return (0); 113924453Speter} 114024453Speter 114182749Sdillon/* 114282749Sdillon * MPSAFE 114382749Sdillon */ 114475426Srwatsonint 114583366Sjulian__setugid(td, uap) 114683366Sjulian struct thread *td; 114775426Srwatson struct __setugid_args *uap; 114875426Srwatson{ 114982749Sdillon#ifdef REGRESSION 115087218Srwatson int error; 115175426Srwatson 115282749Sdillon mtx_lock(&Giant); 115387218Srwatson error = 0; 115475426Srwatson switch (uap->flag) { 115575426Srwatson case 0: 115683366Sjulian td->td_proc->p_flag &= ~P_SUGID; 115782749Sdillon break; 115875426Srwatson case 1: 115983366Sjulian td->td_proc->p_flag |= P_SUGID; 116082749Sdillon break; 116175426Srwatson default: 116282749Sdillon error = EINVAL; 116382749Sdillon break; 116475426Srwatson } 116582749Sdillon mtx_unlock(&Giant); 116682749Sdillon return (error); 116775426Srwatson#else /* !REGRESSION */ 116887218Srwatson 116975426Srwatson return (ENOSYS); 117087218Srwatson#endif /* REGRESSION */ 117175426Srwatson} 117275426Srwatson 11731541Srgrimes/* 11741541Srgrimes * Check if gid is a member of the group set. 11751541Srgrimes */ 11761549Srgrimesint 11771541Srgrimesgroupmember(gid, cred) 11781541Srgrimes gid_t gid; 117977183Srwatson struct ucred *cred; 11801541Srgrimes{ 11811541Srgrimes register gid_t *gp; 11821541Srgrimes gid_t *egp; 11831541Srgrimes 11841541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 11851541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 11861541Srgrimes if (*gp == gid) 11871541Srgrimes return (1); 11881541Srgrimes return (0); 11891541Srgrimes} 11901541Srgrimes 119182424Srwatson/* 119289414Sarr * `suser_enabled' (which can be set by the security.suser_enabled 119382466Srwatson * sysctl) determines whether the system 'super-user' policy is in effect. 119482466Srwatson * If it is nonzero, an effective uid of 0 connotes special privilege, 119582466Srwatson * overriding many mandatory and discretionary protections. If it is zero, 119682466Srwatson * uid 0 is offered no special privilege in the kernel security policy. 119782466Srwatson * Setting it to zero may seriously impact the functionality of many 119882466Srwatson * existing userland programs, and should not be done without careful 119982466Srwatson * consideration of the consequences. 120082424Srwatson */ 120182693Srwatsonint suser_enabled = 1; 120289414SarrSYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, 120382693Srwatson &suser_enabled, 0, "processes with uid 0 have privilege"); 120489414SarrTUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); 120561287Srwatson 12061541Srgrimes/* 120782466Srwatson * Test whether the specified credentials imply "super-user" privilege. 120882466Srwatson * Return 0 or EPERM. 12091541Srgrimes */ 12101549Srgrimesint 121146112Sphksuser(p) 121272786Srwatson struct proc *p; 121346112Sphk{ 121487218Srwatson 121587218Srwatson return (suser_xxx(0, p, 0)); 121646112Sphk} 121746112Sphk 121883366Sjulian/* 121983366Sjulian * version for when the thread pointer is available and not the proc. 122083366Sjulian * (saves having to include proc.h into every file that needs to do the change.) 122183366Sjulian */ 122246112Sphkint 122383366Sjuliansuser_td(td) 122483366Sjulian struct thread *td; 122583366Sjulian{ 122687466Srwatson return (suser_xxx(0, td->td_proc, 0)); 122783366Sjulian} 122883366Sjulian 122983366Sjulian/* 123083366Sjulian * wrapper to use if you have the thread on hand but not the proc. 123183366Sjulian */ 123283366Sjulianint 123383366Sjuliansuser_xxx_td(cred, td, flag) 123483366Sjulian struct ucred *cred; 123583366Sjulian struct thread *td; 123683366Sjulian int flag; 123783366Sjulian{ 123883366Sjulian return(suser_xxx(cred, td->td_proc, flag)); 123983366Sjulian} 124083366Sjulian 124183366Sjulianint 124246155Sphksuser_xxx(cred, proc, flag) 124372786Srwatson struct ucred *cred; 124472786Srwatson struct proc *proc; 124546155Sphk int flag; 12461541Srgrimes{ 124782693Srwatson if (!suser_enabled) 124861282Srwatson return (EPERM); 124946155Sphk if (!cred && !proc) { 125046155Sphk printf("suser_xxx(): THINK!\n"); 125146155Sphk return (EPERM); 12521541Srgrimes } 125387218Srwatson if (cred == NULL) 125446155Sphk cred = proc->p_ucred; 125587218Srwatson if (cred->cr_uid != 0) 125646155Sphk return (EPERM); 125772786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 125846155Sphk return (EPERM); 125946155Sphk return (0); 12601541Srgrimes} 12611541Srgrimes 126283639Srwatson/* 126387218Srwatson * Test the active securelevel against a given level. securelevel_gt() 126487218Srwatson * implements (securelevel > level). securelevel_ge() implements 126587218Srwatson * (securelevel >= level). Note that the logic is inverted -- these 126687218Srwatson * functions return EPERM on "success" and 0 on "failure". 126783639Srwatson * 126883639Srwatson * cr is permitted to be NULL for the time being, as there were some 126983639Srwatson * existing securelevel checks that occurred without a process/credential 127087218Srwatson * context. In the future this will be disallowed, so a kernel message 127187218Srwatson * is displayed. 127283639Srwatson */ 127383639Srwatsonint 127483639Srwatsonsecurelevel_gt(struct ucred *cr, int level) 127583639Srwatson{ 127687218Srwatson int active_securelevel; 127783639Srwatson 127887218Srwatson active_securelevel = securelevel; 127987218Srwatson if (cr == NULL) 128083639Srwatson printf("securelevel_gt: cr is NULL\n"); 128187275Srwatson if (cr->cr_prison != NULL) { 128287275Srwatson mtx_lock(&cr->cr_prison->pr_mtx); 128387218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 128487218Srwatson active_securelevel); 128587275Srwatson mtx_unlock(&cr->cr_prison->pr_mtx); 128687275Srwatson } 128787218Srwatson return (active_securelevel > level ? EPERM : 0); 128883639Srwatson} 128983639Srwatson 129083639Srwatsonint 129183639Srwatsonsecurelevel_ge(struct ucred *cr, int level) 129283639Srwatson{ 129387218Srwatson int active_securelevel; 129483639Srwatson 129587218Srwatson active_securelevel = securelevel; 129687218Srwatson if (cr == NULL) 129787218Srwatson printf("securelevel_gt: cr is NULL\n"); 129887275Srwatson if (cr->cr_prison != NULL) { 129987275Srwatson mtx_lock(&cr->cr_prison->pr_mtx); 130087218Srwatson active_securelevel = imax(cr->cr_prison->pr_securelevel, 130187218Srwatson active_securelevel); 130287275Srwatson mtx_unlock(&cr->cr_prison->pr_mtx); 130387275Srwatson } 130487218Srwatson return (active_securelevel >= level ? EPERM : 0); 130583639Srwatson} 130683639Srwatson 130784736Srwatson/* 130887144Srwatson * 'see_other_uids' determines whether or not visibility of processes 130987218Srwatson * and sockets with credentials holding different real uids is possible 131087138Srwatson * using a variety of system MIBs. 131187218Srwatson * XXX: data declarations should be together near the beginning of the file. 131284736Srwatson */ 131387144Srwatsonstatic int see_other_uids = 1; 131489414SarrSYSCTL_INT(_security_bsd, OID_AUTO, see_other_uids, CTLFLAG_RW, 131587218Srwatson &see_other_uids, 0, 131684736Srwatson "Unprivileged processes may see subjects/objects with different real uid"); 131784736Srwatson 131882466Srwatson/*- 131982466Srwatson * Determine if u1 "can see" the subject specified by u2. 132074956Srwatson * Returns: 0 for permitted, an errno value otherwise 132174956Srwatson * Locks: none 132287218Srwatson * References: *u1 and *u2 must not change during the call 132374956Srwatson * u1 may equal u2, in which case only one reference is required 132474956Srwatson */ 132574956Srwatsonint 132683742Srwatsoncr_cansee(struct ucred *u1, struct ucred *u2) 132765237Srwatson{ 132872786Srwatson int error; 132953518Sphk 133074956Srwatson if ((error = prison_check(u1, u2))) 133172786Srwatson return (error); 133287144Srwatson if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { 133375005Srwatson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 133474956Srwatson return (ESRCH); 133565293Srwatson } 133665237Srwatson return (0); 133765237Srwatson} 133865237Srwatson 133982466Srwatson/*- 134082466Srwatson * Determine if p1 "can see" the subject specified by p2. 134182424Srwatson * Returns: 0 for permitted, an errno value otherwise 134282466Srwatson * Locks: Sufficient locks to protect p1->p_ucred and p2->p_ucred must 134382424Srwatson * be held. Normally, p1 will be curproc, and a lock must be held 134482424Srwatson * for p2. 134582424Srwatson * References: p1 and p2 must be valid for the lifetime of the call 134682424Srwatson */ 134779335Srwatsonint 134879335Srwatsonp_cansee(struct proc *p1, struct proc *p2) 134974956Srwatson{ 135074956Srwatson 135183742Srwatson /* Wrap cr_cansee() for all functionality. */ 135283742Srwatson return (cr_cansee(p1->p_ucred, p2->p_ucred)); 135374956Srwatson} 135474956Srwatson 135582466Srwatson/*- 135688943Srwatson * Determine whether cred may deliver the specified signal to proc. 135788943Srwatson * Returns: 0 for permitted, an errno value otherwise. 135888943Srwatson * Locks: A lock must be held for proc. 135988943Srwatson * References: cred and proc must be valid for the lifetime of the call. 136075437Srwatson */ 136175437Srwatsonint 136288943Srwatsoncr_cansignal(struct ucred *cred, struct proc *proc, int signum) 136353518Sphk{ 136482466Srwatson int error; 136584826Sjhb 136675437Srwatson /* 136788943Srwatson * Jail semantics limit the scope of signalling to proc in the 136888943Srwatson * same jail as cred, if cred is in jail. 136975437Srwatson */ 137088943Srwatson error = prison_check(cred, proc->p_ucred); 137188943Srwatson if (error) 137272786Srwatson return (error); 137365237Srwatson 137465237Srwatson /* 137582424Srwatson * UNIX signal semantics depend on the status of the P_SUGID 137682424Srwatson * bit on the target process. If the bit is set, then additional 137782424Srwatson * restrictions are placed on the set of available signals. 137875437Srwatson */ 137988943Srwatson if (proc->p_flag & P_SUGID) { 138075437Srwatson switch (signum) { 138175437Srwatson case 0: 138275437Srwatson case SIGKILL: 138375437Srwatson case SIGINT: 138475437Srwatson case SIGTERM: 138575437Srwatson case SIGSTOP: 138675437Srwatson case SIGTTIN: 138775437Srwatson case SIGTTOU: 138875437Srwatson case SIGTSTP: 138975437Srwatson case SIGHUP: 139075437Srwatson case SIGUSR1: 139175437Srwatson case SIGUSR2: 139282466Srwatson /* 139382466Srwatson * Generally, permit job and terminal control 139482466Srwatson * signals. 139582466Srwatson */ 139675437Srwatson break; 139775437Srwatson default: 139888943Srwatson /* Not permitted without privilege. */ 139988943Srwatson error = suser_xxx(cred, NULL, PRISON_ROOT); 140075437Srwatson if (error) 140175437Srwatson return (error); 140275437Srwatson } 140365237Srwatson } 140465237Srwatson 140575480Srwatson /* 140682424Srwatson * Generally, the target credential's ruid or svuid must match the 140775480Srwatson * subject credential's ruid or euid. 140875480Srwatson */ 140988943Srwatson if (cred->cr_ruid != proc->p_ucred->cr_ruid && 141088943Srwatson cred->cr_ruid != proc->p_ucred->cr_svuid && 141188943Srwatson cred->cr_uid != proc->p_ucred->cr_ruid && 141288943Srwatson cred->cr_uid != proc->p_ucred->cr_svuid) { 141388943Srwatson /* Not permitted without privilege. */ 141488943Srwatson error = suser_xxx(cred, NULL, PRISON_ROOT); 141575480Srwatson if (error) 141675480Srwatson return (error); 141775480Srwatson } 141875480Srwatson 141987218Srwatson return (0); 142053518Sphk} 142153518Sphk 142288943Srwatson 142382466Srwatson/*- 142488943Srwatson * Determine whether p1 may deliver the specified signal to p2. 142588943Srwatson * Returns: 0 for permitted, an errno value otherwise 142688943Srwatson * Locks: Sufficient locks to protect various components of p1 and p2 142788943Srwatson * must be held. Normally, p1 will be curproc, and a lock must 142888943Srwatson * be held for p2. 142988943Srwatson * References: p1 and p2 must be valid for the lifetime of the call 143088943Srwatson */ 143188943Srwatsonint 143288943Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum) 143388943Srwatson{ 143488943Srwatson 143588943Srwatson if (p1 == p2) 143688943Srwatson return (0); 143788943Srwatson 143888943Srwatson /* 143988943Srwatson * UNIX signalling semantics require that processes in the same 144088943Srwatson * session always be able to deliver SIGCONT to one another, 144188943Srwatson * overriding the remaining protections. 144288943Srwatson */ 144388943Srwatson if (signum == SIGCONT && p1->p_session == p2->p_session) 144488943Srwatson return (0); 144588943Srwatson 144688943Srwatson return (cr_cansignal(p1->p_ucred, p2, signum)); 144788943Srwatson} 144888943Srwatson 144988943Srwatson/*- 145087218Srwatson * Determine whether p1 may reschedule p2. 145182466Srwatson * Returns: 0 for permitted, an errno value otherwise 145282424Srwatson * Locks: Sufficient locks to protect various components of p1 and p2 145382424Srwatson * must be held. Normally, p1 will be curproc, and a lock must 145482466Srwatson * be held for p2. 145582424Srwatson * References: p1 and p2 must be valid for the lifetime of the call 145682424Srwatson */ 145779335Srwatsonint 145879335Srwatsonp_cansched(struct proc *p1, struct proc *p2) 145965237Srwatson{ 146072786Srwatson int error; 146165237Srwatson 146265237Srwatson if (p1 == p2) 146365237Srwatson return (0); 146472786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 146572786Srwatson return (error); 146677183Srwatson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 146765237Srwatson return (0); 146877183Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 146965237Srwatson return (0); 147082466Srwatson if (suser_xxx(0, p1, PRISON_ROOT) == 0) 147165237Srwatson return (0); 147265237Srwatson 147365237Srwatson#ifdef CAPABILITIES 147485874Srwatson if (!cap_check(NULL, p1, CAP_SYS_NICE, PRISON_ROOT)) 147565237Srwatson return (0); 147665237Srwatson#endif 147765237Srwatson 147865237Srwatson return (EPERM); 147965237Srwatson} 148065237Srwatson 148182424Srwatson/* 148287280Srwatson * The 'unprivileged_proc_debug' flag may be used to disable a variety of 148387280Srwatson * unprivileged inter-process debugging services, including some procfs 148487280Srwatson * functionality, ptrace(), and ktrace(). In the past, inter-process 148587280Srwatson * debugging has been involved in a variety of security problems, and sites 148687280Srwatson * not requiring the service might choose to disable it when hardening 148787280Srwatson * systems. 148882424Srwatson * 148982424Srwatson * XXX: Should modifying and reading this variable require locking? 149087218Srwatson * XXX: data declarations should be together near the beginning of the file. 149182424Srwatson */ 149287144Srwatsonstatic int unprivileged_proc_debug = 1; 149389414SarrSYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW, 149487218Srwatson &unprivileged_proc_debug, 0, 149580735Srwatson "Unprivileged processes may use process debugging facilities"); 149680735Srwatson 149782466Srwatson/*- 149882466Srwatson * Determine whether p1 may debug p2. 149982466Srwatson * Returns: 0 for permitted, an errno value otherwise 150082466Srwatson * Locks: Sufficient locks to protect various components of p1 and p2 150182466Srwatson * must be held. Normally, p1 will be curproc, and a lock must 150282466Srwatson * be held for p2. 150382424Srwatson * References: p1 and p2 must be valid for the lifetime of the call 150482424Srwatson */ 150579335Srwatsonint 150679335Srwatsonp_candebug(struct proc *p1, struct proc *p2) 150765237Srwatson{ 150887218Srwatson int credentialchanged, error, grpsubset, i, uidsubset; 150965237Srwatson 151087144Srwatson if (!unprivileged_proc_debug) { 151184727Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 151284727Srwatson if (error) 151384727Srwatson return (error); 151484727Srwatson } 151584636Sdes if (p1 == p2) 151684636Sdes return (0); 151772786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 151872786Srwatson return (error); 151965237Srwatson 152082466Srwatson /* 152185895Srwatson * Is p2's group set a subset of p1's effective group set? This 152285895Srwatson * includes p2's egid, group access list, rgid, and svgid. 152382466Srwatson */ 152485895Srwatson grpsubset = 1; 152585895Srwatson for (i = 0; i < p2->p_ucred->cr_ngroups; i++) { 152685895Srwatson if (!groupmember(p2->p_ucred->cr_groups[i], p1->p_ucred)) { 152785895Srwatson grpsubset = 0; 152885895Srwatson break; 152985895Srwatson } 153085895Srwatson } 153185895Srwatson grpsubset = grpsubset && 153285895Srwatson groupmember(p2->p_ucred->cr_rgid, p1->p_ucred) && 153385895Srwatson groupmember(p2->p_ucred->cr_svgid, p1->p_ucred); 153485895Srwatson 153585895Srwatson /* 153685895Srwatson * Are the uids present in p2's credential equal to p1's 153785895Srwatson * effective uid? This includes p2's euid, svuid, and ruid. 153885895Srwatson */ 153985895Srwatson uidsubset = (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid && 154085895Srwatson p1->p_ucred->cr_uid == p2->p_ucred->cr_svuid && 154185895Srwatson p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid); 154285895Srwatson 154385895Srwatson /* 154485895Srwatson * Has the credential of the process changed since the last exec()? 154585895Srwatson */ 154685895Srwatson credentialchanged = (p2->p_flag & P_SUGID); 154785895Srwatson 154885895Srwatson /* 154985895Srwatson * If p2's gids aren't a subset, or the uids aren't a subset, 155085895Srwatson * or the credential has changed, require appropriate privilege 155185895Srwatson * for p1 to debug p2. For POSIX.1e capabilities, this will 155285895Srwatson * require CAP_SYS_PTRACE. 155385895Srwatson */ 155485895Srwatson if (!grpsubset || !uidsubset || credentialchanged) { 155584727Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 155684727Srwatson if (error) 155765237Srwatson return (error); 155882466Srwatson } 155965237Srwatson 156087218Srwatson /* Can't trace init when securelevel > 0. */ 156187218Srwatson if (p2 == initproc) { 156283639Srwatson error = securelevel_gt(p1->p_ucred, 0); 156383639Srwatson if (error) 156483639Srwatson return (error); 156583639Srwatson } 156665237Srwatson 156785880Srwatson /* 156885880Srwatson * Can't trace a process that's currently exec'ing. 156985880Srwatson * XXX: Note, this is not a security policy decision, it's a 157085880Srwatson * basic correctness/functionality decision. Therefore, this check 157185880Srwatson * should be moved to the caller's of p_candebug(). 157285880Srwatson */ 157385598Sdes if ((p2->p_flag & P_INEXEC) != 0) 157485598Sdes return (EAGAIN); 157587466Srwatson 157665237Srwatson return (0); 157765237Srwatson} 157865237Srwatson 157953518Sphk/* 15801541Srgrimes * Allocate a zeroed cred structure. 15811541Srgrimes */ 15821541Srgrimesstruct ucred * 15831541Srgrimescrget() 15841541Srgrimes{ 15851541Srgrimes register struct ucred *cr; 15861541Srgrimes 158784826Sjhb MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); 15881541Srgrimes cr->cr_ref = 1; 158969239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 15901541Srgrimes return (cr); 15911541Srgrimes} 15921541Srgrimes 15931541Srgrimes/* 159482466Srwatson * Claim another reference to a ucred structure. 159569401Salfred */ 159684827Sjhbstruct ucred * 159769401Salfredcrhold(cr) 159869401Salfred struct ucred *cr; 159969401Salfred{ 160069401Salfred 160172200Sbmilekic mtx_lock(&cr->cr_mtx); 160269401Salfred cr->cr_ref++; 160384827Sjhb mtx_unlock(&cr->cr_mtx); 160484827Sjhb return (cr); 160569401Salfred} 160669401Salfred 160769401Salfred/* 16081541Srgrimes * Free a cred structure. 16091541Srgrimes * Throws away space when ref count gets to 0. 16101541Srgrimes */ 16111549Srgrimesvoid 16121541Srgrimescrfree(cr) 16131541Srgrimes struct ucred *cr; 16141541Srgrimes{ 161569239Salfred 161672200Sbmilekic mtx_lock(&cr->cr_mtx); 161775632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 161865495Struckman if (--cr->cr_ref == 0) { 161969239Salfred mtx_destroy(&cr->cr_mtx); 162065495Struckman /* 162165495Struckman * Some callers of crget(), such as nfs_statfs(), 162265495Struckman * allocate a temporary credential, but don't 162365495Struckman * allocate a uidinfo structure. 162465495Struckman */ 162565495Struckman if (cr->cr_uidinfo != NULL) 162665495Struckman uifree(cr->cr_uidinfo); 162777277Srwatson if (cr->cr_ruidinfo != NULL) 162877277Srwatson uifree(cr->cr_ruidinfo); 162972786Srwatson /* 163072786Srwatson * Free a prison, if any. 163172786Srwatson */ 163272786Srwatson if (jailed(cr)) 163372786Srwatson prison_free(cr->cr_prison); 16341541Srgrimes FREE((caddr_t)cr, M_CRED); 163587218Srwatson } else 163672200Sbmilekic mtx_unlock(&cr->cr_mtx); 16371541Srgrimes} 16381541Srgrimes 16391541Srgrimes/* 164084827Sjhb * Check to see if this ucred is shared. 16411541Srgrimes */ 164284827Sjhbint 164384827Sjhbcrshared(cr) 16441541Srgrimes struct ucred *cr; 16451541Srgrimes{ 164684827Sjhb int shared; 16471541Srgrimes 164872200Sbmilekic mtx_lock(&cr->cr_mtx); 164984827Sjhb shared = (cr->cr_ref > 1); 165072200Sbmilekic mtx_unlock(&cr->cr_mtx); 165184827Sjhb return (shared); 16521541Srgrimes} 16531541Srgrimes 16541541Srgrimes/* 165584827Sjhb * Copy a ucred's contents from a template. Does not block. 165684827Sjhb */ 165784827Sjhbvoid 165884827Sjhbcrcopy(dest, src) 165984827Sjhb struct ucred *dest, *src; 166084827Sjhb{ 166184827Sjhb 166284827Sjhb KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); 166384827Sjhb bcopy(&src->cr_startcopy, &dest->cr_startcopy, 166487218Srwatson (unsigned)((caddr_t)&src->cr_endcopy - 166584827Sjhb (caddr_t)&src->cr_startcopy)); 166684827Sjhb uihold(dest->cr_uidinfo); 166784827Sjhb uihold(dest->cr_ruidinfo); 166884827Sjhb if (jailed(dest)) 166984827Sjhb prison_hold(dest->cr_prison); 167084827Sjhb} 167184827Sjhb 167284827Sjhb/* 16731541Srgrimes * Dup cred struct to a new held one. 16741541Srgrimes */ 16751541Srgrimesstruct ucred * 16761541Srgrimescrdup(cr) 16771541Srgrimes struct ucred *cr; 16781541Srgrimes{ 16791541Srgrimes struct ucred *newcr; 16801541Srgrimes 168184827Sjhb newcr = crget(); 168284827Sjhb crcopy(newcr, cr); 16831541Srgrimes return (newcr); 16841541Srgrimes} 16851541Srgrimes 16861541Srgrimes/* 16871541Srgrimes * Get login name, if available. 16881541Srgrimes */ 168912221Sbde#ifndef _SYS_SYSPROTO_H_ 16901541Srgrimesstruct getlogin_args { 16911541Srgrimes char *namebuf; 16921541Srgrimes u_int namelen; 16931541Srgrimes}; 169412221Sbde#endif 169582749Sdillon/* 169682749Sdillon * MPSAFE 169782749Sdillon */ 16981541Srgrimes/* ARGSUSED */ 16991549Srgrimesint 170083366Sjuliangetlogin(td, uap) 170183366Sjulian struct thread *td; 17021541Srgrimes struct getlogin_args *uap; 17031541Srgrimes{ 170482749Sdillon int error; 170583366Sjulian struct proc *p = td->td_proc; 17061541Srgrimes 170782749Sdillon mtx_lock(&Giant); 170823358Sache if (uap->namelen > MAXLOGNAME) 170923359Sache uap->namelen = MAXLOGNAME; 171082749Sdillon error = copyout((caddr_t) p->p_pgrp->pg_session->s_login, 171182749Sdillon (caddr_t) uap->namebuf, uap->namelen); 171282749Sdillon mtx_unlock(&Giant); 171382749Sdillon return(error); 17141541Srgrimes} 17151541Srgrimes 17161541Srgrimes/* 17171541Srgrimes * Set login name. 17181541Srgrimes */ 171912221Sbde#ifndef _SYS_SYSPROTO_H_ 17201541Srgrimesstruct setlogin_args { 17211541Srgrimes char *namebuf; 17221541Srgrimes}; 172312221Sbde#endif 172482749Sdillon/* 172582749Sdillon * MPSAFE 172682749Sdillon */ 17271541Srgrimes/* ARGSUSED */ 17281549Srgrimesint 172983366Sjuliansetlogin(td, uap) 173083366Sjulian struct thread *td; 17311541Srgrimes struct setlogin_args *uap; 17321541Srgrimes{ 173383366Sjulian struct proc *p = td->td_proc; 17341541Srgrimes int error; 173523330Sache char logintmp[MAXLOGNAME]; 17361541Srgrimes 173782749Sdillon mtx_lock(&Giant); 173887218Srwatson if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0) 173982749Sdillon goto done2; 174022522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 174136845Sdfr sizeof(logintmp), (size_t *)0); 174287218Srwatson if (error == ENAMETOOLONG) 17431541Srgrimes error = EINVAL; 174487218Srwatson else if (!error) 174587218Srwatson (void)memcpy(p->p_pgrp->pg_session->s_login, logintmp, 174623330Sache sizeof(logintmp)); 174782749Sdillondone2: 174882749Sdillon mtx_unlock(&Giant); 17491541Srgrimes return (error); 17501541Srgrimes} 175131891Ssef 175231891Ssefvoid 175331891Ssefsetsugid(p) 175455338Sphk struct proc *p; 175531891Ssef{ 175631891Ssef p->p_flag |= P_SUGID; 175755707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 175831891Ssef p->p_stops = 0; 175931891Ssef} 176065495Struckman 176182466Srwatson/*- 176282466Srwatson * Change a process's effective uid. 176377183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 176477183Srwatson * References: newcred must be an exclusive credential reference for the 176577183Srwatson * duration of the call. 176665495Struckman */ 176765495Struckmanvoid 176877183Srwatsonchange_euid(newcred, euid) 176977183Srwatson struct ucred *newcred; 177077183Srwatson uid_t euid; 177165495Struckman{ 177265495Struckman 177377183Srwatson newcred->cr_uid = euid; 177477183Srwatson uifree(newcred->cr_uidinfo); 177577183Srwatson newcred->cr_uidinfo = uifind(euid); 177665495Struckman} 177765495Struckman 177882466Srwatson/*- 177982466Srwatson * Change a process's effective gid. 178077183Srwatson * Side effects: newcred->cr_gid will be modified. 178177183Srwatson * References: newcred must be an exclusive credential reference for the 178277183Srwatson * duration of the call. 178365495Struckman */ 178467629Sgallatinvoid 178577183Srwatsonchange_egid(newcred, egid) 178677183Srwatson struct ucred *newcred; 178777183Srwatson gid_t egid; 178865495Struckman{ 178965495Struckman 179077183Srwatson newcred->cr_groups[0] = egid; 179165495Struckman} 179277183Srwatson 179382466Srwatson/*- 179482466Srwatson * Change a process's real uid. 179577183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 179677183Srwatson * will be updated, and the old and new cr_ruidinfo proc 179777183Srwatson * counts will be updated. 179877183Srwatson * References: newcred must be an exclusive credential reference for the 179977183Srwatson * duration of the call. 180077183Srwatson */ 180177183Srwatsonvoid 180277183Srwatsonchange_ruid(newcred, ruid) 180377183Srwatson struct ucred *newcred; 180477183Srwatson uid_t ruid; 180577183Srwatson{ 180677183Srwatson 180777183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 180877183Srwatson newcred->cr_ruid = ruid; 180977183Srwatson uifree(newcred->cr_ruidinfo); 181077183Srwatson newcred->cr_ruidinfo = uifind(ruid); 181177183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 181277183Srwatson} 181377183Srwatson 181482466Srwatson/*- 181582466Srwatson * Change a process's real gid. 181677183Srwatson * Side effects: newcred->cr_rgid will be updated. 181777183Srwatson * References: newcred must be an exclusive credential reference for the 181877183Srwatson * duration of the call. 181977183Srwatson */ 182077183Srwatsonvoid 182177183Srwatsonchange_rgid(newcred, rgid) 182277183Srwatson struct ucred *newcred; 182377183Srwatson gid_t rgid; 182477183Srwatson{ 182577183Srwatson 182677183Srwatson newcred->cr_rgid = rgid; 182777183Srwatson} 182877183Srwatson 182982466Srwatson/*- 183082466Srwatson * Change a process's saved uid. 183177183Srwatson * Side effects: newcred->cr_svuid will be updated. 183277183Srwatson * References: newcred must be an exclusive credential reference for the 183377183Srwatson * duration of the call. 183477183Srwatson */ 183577183Srwatsonvoid 183677183Srwatsonchange_svuid(newcred, svuid) 183777183Srwatson struct ucred *newcred; 183877183Srwatson uid_t svuid; 183977183Srwatson{ 184077183Srwatson 184177183Srwatson newcred->cr_svuid = svuid; 184277183Srwatson} 184377183Srwatson 184482466Srwatson/*- 184582466Srwatson * Change a process's saved gid. 184677183Srwatson * Side effects: newcred->cr_svgid will be updated. 184777183Srwatson * References: newcred must be an exclusive credential reference for the 184877183Srwatson * duration of the call. 184977183Srwatson */ 185077183Srwatsonvoid 185177183Srwatsonchange_svgid(newcred, svgid) 185277183Srwatson struct ucred *newcred; 185377183Srwatson gid_t svgid; 185477183Srwatson{ 185577183Srwatson 185677183Srwatson newcred->cr_svgid = svgid; 185777183Srwatson} 1858