kern_prot.c revision 75426
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 51541Srgrimes * All or some portions of this file are derived from material licensed 61541Srgrimes * to the University of California by American Telephone and Telegraph 71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81541Srgrimes * the permission of UNIX System Laboratories, Inc. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 3. All advertising materials mentioning features or use of this software 191541Srgrimes * must display the following acknowledgement: 201541Srgrimes * This product includes software developed by the University of 211541Srgrimes * California, Berkeley and its contributors. 221541Srgrimes * 4. Neither the name of the University nor the names of its contributors 231541Srgrimes * may be used to endorse or promote products derived from this software 241541Srgrimes * without specific prior written permission. 251541Srgrimes * 261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361541Srgrimes * SUCH DAMAGE. 371541Srgrimes * 381541Srgrimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 3950477Speter * $FreeBSD: head/sys/kern/kern_prot.c 75426 2001-04-11 20:20:40Z rwatson $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes/* 431541Srgrimes * System calls related to processes and protection 441541Srgrimes */ 451541Srgrimes 4631778Seivind#include "opt_compat.h" 4775426Srwatson#include "opt_global.h" 4831778Seivind 491541Srgrimes#include <sys/param.h> 501541Srgrimes#include <sys/acct.h> 511541Srgrimes#include <sys/systm.h> 5212221Sbde#include <sys/sysproto.h> 5341059Speter#include <sys/kernel.h> 5470317Sjake#include <sys/lock.h> 551541Srgrimes#include <sys/proc.h> 561541Srgrimes#include <sys/malloc.h> 5731891Ssef#include <sys/pioctl.h> 5865495Struckman#include <sys/resourcevar.h> 5961287Srwatson#include <sys/sysctl.h> 6072786Srwatson#include <sys/jail.h> 611541Srgrimes 6230354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6330354Sphk 6412221Sbde#ifndef _SYS_SYSPROTO_H_ 6511332Sswallacestruct getpid_args { 661541Srgrimes int dummy; 671541Srgrimes}; 6812221Sbde#endif 691541Srgrimes 7058717Sdillon/* 7170317Sjake * getpid - MP SAFE 7258717Sdillon */ 7370317Sjake 741541Srgrimes/* ARGSUSED */ 751549Srgrimesint 7630994Sphkgetpid(p, uap) 771541Srgrimes struct proc *p; 7811332Sswallace struct getpid_args *uap; 791541Srgrimes{ 801541Srgrimes 8130994Sphk p->p_retval[0] = p->p_pid; 821541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8374728Sjhb PROC_LOCK(p); 8430994Sphk p->p_retval[1] = p->p_pptr->p_pid; 8574728Sjhb PROC_UNLOCK(p); 861541Srgrimes#endif 871541Srgrimes return (0); 881541Srgrimes} 891541Srgrimes 9070317Sjake/* 9170317Sjake * getppid - MP SAFE 9270317Sjake */ 9370317Sjake 9412221Sbde#ifndef _SYS_SYSPROTO_H_ 9511332Sswallacestruct getppid_args { 9611332Sswallace int dummy; 9711332Sswallace}; 9812221Sbde#endif 991541Srgrimes/* ARGSUSED */ 1001549Srgrimesint 10130994Sphkgetppid(p, uap) 1021541Srgrimes struct proc *p; 10311332Sswallace struct getppid_args *uap; 1041541Srgrimes{ 1051541Srgrimes 10674728Sjhb PROC_LOCK(p); 10730994Sphk p->p_retval[0] = p->p_pptr->p_pid; 10874728Sjhb PROC_UNLOCK(p); 1091541Srgrimes return (0); 1101541Srgrimes} 1111541Srgrimes 11258717Sdillon/* 11358717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter 11458717Sdillon * 11558717Sdillon * MP SAFE 11658717Sdillon */ 11712221Sbde#ifndef _SYS_SYSPROTO_H_ 11811332Sswallacestruct getpgrp_args { 11911332Sswallace int dummy; 12011332Sswallace}; 12112221Sbde#endif 12211332Sswallace 1231549Srgrimesint 12430994Sphkgetpgrp(p, uap) 1251541Srgrimes struct proc *p; 12611332Sswallace struct getpgrp_args *uap; 1271541Srgrimes{ 1281541Srgrimes 12930994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1301541Srgrimes return (0); 1311541Srgrimes} 1321541Srgrimes 13328401Speter/* Get an arbitary pid's process group id */ 13412221Sbde#ifndef _SYS_SYSPROTO_H_ 13528401Speterstruct getpgid_args { 13628401Speter pid_t pid; 13728401Speter}; 13828401Speter#endif 13928401Speter 14028401Speterint 14130994Sphkgetpgid(p, uap) 14228401Speter struct proc *p; 14328401Speter struct getpgid_args *uap; 14428401Speter{ 14541726Struckman struct proc *pt; 14641726Struckman 14741726Struckman pt = p; 14828401Speter if (uap->pid == 0) 14928401Speter goto found; 15028401Speter 15141726Struckman if ((pt = pfind(uap->pid)) == 0) 15228401Speter return ESRCH; 15328401Speterfound: 15441726Struckman p->p_retval[0] = pt->p_pgrp->pg_id; 15528401Speter return 0; 15628401Speter} 15728401Speter 15828401Speter/* 15928401Speter * Get an arbitary pid's session id. 16028401Speter */ 16128401Speter#ifndef _SYS_SYSPROTO_H_ 16228401Speterstruct getsid_args { 16328401Speter pid_t pid; 16428401Speter}; 16528401Speter#endif 16628401Speter 16728401Speterint 16830994Sphkgetsid(p, uap) 16928401Speter struct proc *p; 17028401Speter struct getsid_args *uap; 17128401Speter{ 17241726Struckman struct proc *pt; 17341726Struckman 17441726Struckman pt = p; 17528401Speter if (uap->pid == 0) 17628401Speter goto found; 17728401Speter 17871002Sben if ((pt = pfind(uap->pid)) == 0) 17928401Speter return ESRCH; 18028401Speterfound: 18141726Struckman p->p_retval[0] = pt->p_session->s_sid; 18228401Speter return 0; 18328401Speter} 18428401Speter 18528401Speter 18658941Sdillon/* 18758941Sdillon * getuid() - MP SAFE 18858941Sdillon */ 18928401Speter#ifndef _SYS_SYSPROTO_H_ 19011332Sswallacestruct getuid_args { 19111332Sswallace int dummy; 19211332Sswallace}; 19312221Sbde#endif 19411332Sswallace 1951541Srgrimes/* ARGSUSED */ 1961549Srgrimesint 19730994Sphkgetuid(p, uap) 1981541Srgrimes struct proc *p; 19911332Sswallace struct getuid_args *uap; 2001541Srgrimes{ 2011541Srgrimes 20230994Sphk p->p_retval[0] = p->p_cred->p_ruid; 2031541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 20430994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 2051541Srgrimes#endif 2061541Srgrimes return (0); 2071541Srgrimes} 2081541Srgrimes 20958941Sdillon/* 21058941Sdillon * geteuid() - MP SAFE 21158941Sdillon */ 21212221Sbde#ifndef _SYS_SYSPROTO_H_ 21311332Sswallacestruct geteuid_args { 21411332Sswallace int dummy; 21511332Sswallace}; 21612221Sbde#endif 21711332Sswallace 2181541Srgrimes/* ARGSUSED */ 2191549Srgrimesint 22030994Sphkgeteuid(p, uap) 2211541Srgrimes struct proc *p; 22211332Sswallace struct geteuid_args *uap; 2231541Srgrimes{ 2241541Srgrimes 22530994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2261541Srgrimes return (0); 2271541Srgrimes} 2281541Srgrimes 22958941Sdillon/* 23058941Sdillon * getgid() - MP SAFE 23158941Sdillon */ 23212221Sbde#ifndef _SYS_SYSPROTO_H_ 23311332Sswallacestruct getgid_args { 23411332Sswallace int dummy; 23511332Sswallace}; 23612221Sbde#endif 23711332Sswallace 2381541Srgrimes/* ARGSUSED */ 2391549Srgrimesint 24030994Sphkgetgid(p, uap) 2411541Srgrimes struct proc *p; 24211332Sswallace struct getgid_args *uap; 2431541Srgrimes{ 2441541Srgrimes 24530994Sphk p->p_retval[0] = p->p_cred->p_rgid; 2461541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 24730994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2481541Srgrimes#endif 2491541Srgrimes return (0); 2501541Srgrimes} 2511541Srgrimes 2521541Srgrimes/* 2531541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2541541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2551541Srgrimes * correctly in a library function. 2561541Srgrimes */ 25712221Sbde#ifndef _SYS_SYSPROTO_H_ 25811332Sswallacestruct getegid_args { 25911332Sswallace int dummy; 26011332Sswallace}; 26112221Sbde#endif 26211332Sswallace 2631541Srgrimes/* ARGSUSED */ 2641549Srgrimesint 26530994Sphkgetegid(p, uap) 2661541Srgrimes struct proc *p; 26711332Sswallace struct getegid_args *uap; 2681541Srgrimes{ 2691541Srgrimes 27030994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2711541Srgrimes return (0); 2721541Srgrimes} 2731541Srgrimes 27412221Sbde#ifndef _SYS_SYSPROTO_H_ 2751541Srgrimesstruct getgroups_args { 2761541Srgrimes u_int gidsetsize; 2771541Srgrimes gid_t *gidset; 2781541Srgrimes}; 27912221Sbde#endif 2801549Srgrimesint 28130994Sphkgetgroups(p, uap) 2821541Srgrimes struct proc *p; 2831541Srgrimes register struct getgroups_args *uap; 2841541Srgrimes{ 2851541Srgrimes register struct pcred *pc = p->p_cred; 2861541Srgrimes register u_int ngrp; 2871541Srgrimes int error; 2881541Srgrimes 2891541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 29030994Sphk p->p_retval[0] = pc->pc_ucred->cr_ngroups; 2911541Srgrimes return (0); 2921541Srgrimes } 2931541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 2941541Srgrimes return (EINVAL); 2951541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 2963098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 2973098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 2981541Srgrimes return (error); 29930994Sphk p->p_retval[0] = ngrp; 3001541Srgrimes return (0); 3011541Srgrimes} 3021541Srgrimes 30312221Sbde#ifndef _SYS_SYSPROTO_H_ 30412207Sbdestruct setsid_args { 30511332Sswallace int dummy; 30611332Sswallace}; 30712221Sbde#endif 30811332Sswallace 3091541Srgrimes/* ARGSUSED */ 3101549Srgrimesint 31130994Sphksetsid(p, uap) 3121541Srgrimes register struct proc *p; 31312207Sbde struct setsid_args *uap; 3141541Srgrimes{ 3151541Srgrimes 3161541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 3171541Srgrimes return (EPERM); 3181541Srgrimes } else { 3191541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 32030994Sphk p->p_retval[0] = p->p_pid; 3211541Srgrimes return (0); 3221541Srgrimes } 3231541Srgrimes} 3241541Srgrimes 3251541Srgrimes/* 3261541Srgrimes * set process group (setpgid/old setpgrp) 3271541Srgrimes * 3281541Srgrimes * caller does setpgid(targpid, targpgid) 3291541Srgrimes * 3301541Srgrimes * pid must be caller or child of caller (ESRCH) 3311541Srgrimes * if a child 3321541Srgrimes * pid must be in same session (EPERM) 3331541Srgrimes * pid can't have done an exec (EACCES) 3341541Srgrimes * if pgid != pid 3351541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3361541Srgrimes * pid must not be session leader (EPERM) 3371541Srgrimes */ 33812221Sbde#ifndef _SYS_SYSPROTO_H_ 3391541Srgrimesstruct setpgid_args { 3401541Srgrimes int pid; /* target process id */ 3411541Srgrimes int pgid; /* target pgrp id */ 3421541Srgrimes}; 34312221Sbde#endif 3441541Srgrimes/* ARGSUSED */ 3451549Srgrimesint 34630994Sphksetpgid(curp, uap) 3471541Srgrimes struct proc *curp; 3481541Srgrimes register struct setpgid_args *uap; 3491541Srgrimes{ 3501541Srgrimes register struct proc *targp; /* target process */ 3511541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 3521541Srgrimes 35320677Sbde if (uap->pgid < 0) 35420677Sbde return (EINVAL); 3551541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 3561541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 3571541Srgrimes return (ESRCH); 35815985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 3591541Srgrimes return (EPERM); 3601541Srgrimes if (targp->p_flag & P_EXEC) 3611541Srgrimes return (EACCES); 3621541Srgrimes } else 3631541Srgrimes targp = curp; 3641541Srgrimes if (SESS_LEADER(targp)) 3651541Srgrimes return (EPERM); 3661541Srgrimes if (uap->pgid == 0) 3671541Srgrimes uap->pgid = targp->p_pid; 3681541Srgrimes else if (uap->pgid != targp->p_pid) 3691541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 3701541Srgrimes pgrp->pg_session != curp->p_session) 3711541Srgrimes return (EPERM); 3721541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 3731541Srgrimes} 3741541Srgrimes 37524448Speter/* 37624448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 37772093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 37824448Speter * case of "appropriate privilege". Once the rules are expanded out, this 37924448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 38024448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 38124448Speter * does not set the saved id - this is dangerous for traditional BSD 38224448Speter * programs. For this reason, we *really* do not want to set 38324448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 38424448Speter */ 38524448Speter#define POSIX_APPENDIX_B_4_2_2 38624448Speter 38712221Sbde#ifndef _SYS_SYSPROTO_H_ 3881541Srgrimesstruct setuid_args { 3891541Srgrimes uid_t uid; 3901541Srgrimes}; 39112221Sbde#endif 3921541Srgrimes/* ARGSUSED */ 3931549Srgrimesint 39430994Sphksetuid(p, uap) 3951541Srgrimes struct proc *p; 3961541Srgrimes struct setuid_args *uap; 3971541Srgrimes{ 3981541Srgrimes register struct pcred *pc = p->p_cred; 3991541Srgrimes register uid_t uid; 4001541Srgrimes int error; 4011541Srgrimes 40224448Speter /* 40324448Speter * See if we have "permission" by POSIX 1003.1 rules. 40424448Speter * 40524448Speter * Note that setuid(geteuid()) is a special case of 40624448Speter * "appropriate privileges" in appendix B.4.2.2. We need 40772093Sasmodai * to use this clause to be compatible with traditional BSD 40824448Speter * semantics. Basically, it means that "setuid(xx)" sets all 40924448Speter * three id's (assuming you have privs). 41024448Speter * 41124448Speter * Notes on the logic. We do things in three steps. 41224448Speter * 1: We determine if the euid is going to change, and do EPERM 41324448Speter * right away. We unconditionally change the euid later if this 41424448Speter * test is satisfied, simplifying that part of the logic. 41524448Speter * 2: We determine if the real and/or saved uid's are going to 41624448Speter * change. Determined by compile options. 41724448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 41824448Speter */ 4191541Srgrimes uid = uap->uid; 42024448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 42117994Sache#ifdef _POSIX_SAVED_IDS 42224448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 42317994Sache#endif 42424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 42524448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 42624448Speter#endif 42746155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4281541Srgrimes return (error); 42924448Speter 43024448Speter#ifdef _POSIX_SAVED_IDS 4311541Srgrimes /* 43224448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 43324448Speter * If so, we are changing the real uid and/or saved uid. 4341541Srgrimes */ 43517994Sache if ( 43624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 43724448Speter uid == pc->pc_ucred->cr_uid || 43817994Sache#endif 43946155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 44017994Sache#endif 44124448Speter { 44224448Speter /* 44365495Struckman * Set the real uid and transfer proc count to new user. 44424448Speter */ 44524448Speter if (uid != pc->p_ruid) { 44665495Struckman change_ruid(p, uid); 44765495Struckman setsugid(p); 44824448Speter } 44924448Speter /* 45024448Speter * Set saved uid 45124448Speter * 45224448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 45324448Speter * the security of seteuid() depends on it. B.4.2.2 says it 45424448Speter * is important that we should do this. 45524448Speter */ 45624448Speter if (pc->p_svuid != uid) { 45724448Speter pc->p_svuid = uid; 45831891Ssef setsugid(p); 45924448Speter } 4608141Sache } 46124448Speter 46224448Speter /* 46324448Speter * In all permitted cases, we are changing the euid. 46424448Speter * Copy credentials so other references do not see our changes. 46524448Speter */ 46624448Speter if (pc->pc_ucred->cr_uid != uid) { 46765495Struckman change_euid(p, uid); 46831891Ssef setsugid(p); 46924448Speter } 4701541Srgrimes return (0); 4711541Srgrimes} 4721541Srgrimes 47312221Sbde#ifndef _SYS_SYSPROTO_H_ 4741541Srgrimesstruct seteuid_args { 4751541Srgrimes uid_t euid; 4761541Srgrimes}; 47712221Sbde#endif 4781541Srgrimes/* ARGSUSED */ 4791549Srgrimesint 48030994Sphkseteuid(p, uap) 4811541Srgrimes struct proc *p; 4821541Srgrimes struct seteuid_args *uap; 4831541Srgrimes{ 4841541Srgrimes register struct pcred *pc = p->p_cred; 4851541Srgrimes register uid_t euid; 4861541Srgrimes int error; 4871541Srgrimes 4881541Srgrimes euid = uap->euid; 48924449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 49024449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 49146155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4921541Srgrimes return (error); 4931541Srgrimes /* 4941541Srgrimes * Everything's okay, do it. Copy credentials so other references do 4951541Srgrimes * not see our changes. 4961541Srgrimes */ 49724449Speter if (pc->pc_ucred->cr_uid != euid) { 49865495Struckman change_euid(p, euid); 49931891Ssef setsugid(p); 50024449Speter } 5011541Srgrimes return (0); 5021541Srgrimes} 5031541Srgrimes 50412221Sbde#ifndef _SYS_SYSPROTO_H_ 5051541Srgrimesstruct setgid_args { 5061541Srgrimes gid_t gid; 5071541Srgrimes}; 50812221Sbde#endif 5091541Srgrimes/* ARGSUSED */ 5101549Srgrimesint 51130994Sphksetgid(p, uap) 5121541Srgrimes struct proc *p; 5131541Srgrimes struct setgid_args *uap; 5141541Srgrimes{ 5151541Srgrimes register struct pcred *pc = p->p_cred; 5161541Srgrimes register gid_t gid; 5171541Srgrimes int error; 5181541Srgrimes 51924448Speter /* 52024448Speter * See if we have "permission" by POSIX 1003.1 rules. 52124448Speter * 52224448Speter * Note that setgid(getegid()) 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 "setgid(xx)" sets all 52624448Speter * three id's (assuming you have privs). 52724448Speter * 52824448Speter * For notes on the logic here, see setuid() above. 52924448Speter */ 5301541Srgrimes gid = uap->gid; 53124448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 53217994Sache#ifdef _POSIX_SAVED_IDS 53324448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 53417994Sache#endif 53524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 53624448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 53724448Speter#endif 53846155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 5391541Srgrimes return (error); 54024448Speter 54117994Sache#ifdef _POSIX_SAVED_IDS 54224448Speter /* 54324448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 54424448Speter * If so, we are changing the real uid and saved gid. 54524448Speter */ 54624448Speter if ( 54724448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 54824448Speter gid == pc->pc_ucred->cr_groups[0] || 54917994Sache#endif 55046155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 55124448Speter#endif 55224448Speter { 55324448Speter /* 55424448Speter * Set real gid 55524448Speter */ 55624448Speter if (pc->p_rgid != gid) { 55724448Speter pc->p_rgid = gid; 55831891Ssef setsugid(p); 55924448Speter } 56024448Speter /* 56124448Speter * Set saved gid 56224448Speter * 56324448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 56424448Speter * the security of setegid() depends on it. B.4.2.2 says it 56524448Speter * is important that we should do this. 56624448Speter */ 56724448Speter if (pc->p_svgid != gid) { 56824448Speter pc->p_svgid = gid; 56931891Ssef setsugid(p); 57024448Speter } 5718141Sache } 57224448Speter /* 57324448Speter * In all cases permitted cases, we are changing the egid. 57424448Speter * Copy credentials so other references do not see our changes. 57524448Speter */ 57624448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 57724448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 57824448Speter pc->pc_ucred->cr_groups[0] = gid; 57931891Ssef setsugid(p); 58024448Speter } 5811541Srgrimes return (0); 5821541Srgrimes} 5831541Srgrimes 58412221Sbde#ifndef _SYS_SYSPROTO_H_ 5851541Srgrimesstruct setegid_args { 5861541Srgrimes gid_t egid; 5871541Srgrimes}; 58812221Sbde#endif 5891541Srgrimes/* ARGSUSED */ 5901549Srgrimesint 59130994Sphksetegid(p, uap) 5921541Srgrimes struct proc *p; 5931541Srgrimes struct setegid_args *uap; 5941541Srgrimes{ 5951541Srgrimes register struct pcred *pc = p->p_cred; 5961541Srgrimes register gid_t egid; 5971541Srgrimes int error; 5981541Srgrimes 5991541Srgrimes egid = uap->egid; 60024449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 60124449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 60246155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 6031541Srgrimes return (error); 60424449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 60524449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 60624449Speter pc->pc_ucred->cr_groups[0] = egid; 60731891Ssef setsugid(p); 60824449Speter } 6091541Srgrimes return (0); 6101541Srgrimes} 6111541Srgrimes 61212221Sbde#ifndef _SYS_SYSPROTO_H_ 6131541Srgrimesstruct setgroups_args { 6141541Srgrimes u_int gidsetsize; 6151541Srgrimes gid_t *gidset; 6161541Srgrimes}; 61712221Sbde#endif 6181541Srgrimes/* ARGSUSED */ 6191549Srgrimesint 62030994Sphksetgroups(p, uap) 6211541Srgrimes struct proc *p; 6221541Srgrimes struct setgroups_args *uap; 6231541Srgrimes{ 6241541Srgrimes register struct pcred *pc = p->p_cred; 6251541Srgrimes register u_int ngrp; 6261541Srgrimes int error; 6271541Srgrimes 62846155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 6291541Srgrimes return (error); 63012063Sdg ngrp = uap->gidsetsize; 63124447Speter if (ngrp > NGROUPS) 6321541Srgrimes return (EINVAL); 63324447Speter /* 63424447Speter * XXX A little bit lazy here. We could test if anything has 63524447Speter * changed before crcopy() and setting P_SUGID. 63624447Speter */ 6371541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 63824447Speter if (ngrp < 1) { 63924447Speter /* 64024447Speter * setgroups(0, NULL) is a legitimate way of clearing the 64124447Speter * groups vector on non-BSD systems (which generally do not 64224447Speter * have the egid in the groups[0]). We risk security holes 64324447Speter * when running non-BSD software if we do not do the same. 64424447Speter */ 64524447Speter pc->pc_ucred->cr_ngroups = 1; 64624447Speter } else { 64724447Speter if ((error = copyin((caddr_t)uap->gidset, 64824447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 64924447Speter return (error); 65024447Speter pc->pc_ucred->cr_ngroups = ngrp; 65124447Speter } 65231891Ssef setsugid(p); 6531541Srgrimes return (0); 6541541Srgrimes} 6551541Srgrimes 65612221Sbde#ifndef _SYS_SYSPROTO_H_ 6571541Srgrimesstruct setreuid_args { 6589238Sache uid_t ruid; 6599238Sache uid_t euid; 6601541Srgrimes}; 66112221Sbde#endif 6621541Srgrimes/* ARGSUSED */ 6631549Srgrimesint 66430994Sphksetreuid(p, uap) 6651541Srgrimes register struct proc *p; 6661541Srgrimes struct setreuid_args *uap; 6671541Srgrimes{ 6681541Srgrimes register struct pcred *pc = p->p_cred; 6699238Sache register uid_t ruid, euid; 6708135Sache int error; 6711541Srgrimes 6729238Sache ruid = uap->ruid; 6739238Sache euid = uap->euid; 67443311Sdillon if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || 67543311Sdillon (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 67643311Sdillon euid != pc->p_ruid && euid != pc->p_svuid)) && 67746155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 6788135Sache return (error); 6799238Sache 68024450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 68165495Struckman change_euid(p, euid); 68231891Ssef setsugid(p); 68324450Speter } 68424450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 68565495Struckman change_ruid(p, ruid); 68631891Ssef setsugid(p); 6878135Sache } 68824559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 68924559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6908111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 69131891Ssef setsugid(p); 69224450Speter } 6938135Sache return (0); 6941541Srgrimes} 6951541Srgrimes 69612221Sbde#ifndef _SYS_SYSPROTO_H_ 6971541Srgrimesstruct setregid_args { 6989238Sache gid_t rgid; 6999238Sache gid_t egid; 7001541Srgrimes}; 70112221Sbde#endif 7021541Srgrimes/* ARGSUSED */ 7031549Srgrimesint 70430994Sphksetregid(p, uap) 7051541Srgrimes register struct proc *p; 7061541Srgrimes struct setregid_args *uap; 7071541Srgrimes{ 7081541Srgrimes register struct pcred *pc = p->p_cred; 7099238Sache register gid_t rgid, egid; 7108135Sache int error; 7111541Srgrimes 7129238Sache rgid = uap->rgid; 7139238Sache egid = uap->egid; 71443311Sdillon if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || 71543311Sdillon (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 71643311Sdillon egid != pc->p_rgid && egid != pc->p_svgid)) && 71746155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 7188135Sache return (error); 7199238Sache 72024450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 72124450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 7229238Sache pc->pc_ucred->cr_groups[0] = egid; 72331891Ssef setsugid(p); 72424450Speter } 72524450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 7269238Sache pc->p_rgid = rgid; 72731891Ssef setsugid(p); 72824450Speter } 72924559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 73024559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7318111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 73231891Ssef setsugid(p); 73324450Speter } 7348135Sache return (0); 7351541Srgrimes} 7361541Srgrimes 73756115Speter/* 73856115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 73956115Speter * saved uid is explicit. 74056115Speter */ 74156115Speter 74224453Speter#ifndef _SYS_SYSPROTO_H_ 74356115Speterstruct setresuid_args { 74456115Speter uid_t ruid; 74556115Speter uid_t euid; 74656115Speter uid_t suid; 74756115Speter}; 74856115Speter#endif 74956115Speter/* ARGSUSED */ 75056115Speterint 75156115Spetersetresuid(p, uap) 75256115Speter register struct proc *p; 75356115Speter struct setresuid_args *uap; 75456115Speter{ 75556115Speter register struct pcred *pc = p->p_cred; 75656115Speter register uid_t ruid, euid, suid; 75756115Speter int error; 75856115Speter 75956115Speter ruid = uap->ruid; 76056115Speter euid = uap->euid; 76156115Speter suid = uap->suid; 76256115Speter if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid && 76356115Speter ruid != pc->pc_ucred->cr_uid) || 76456115Speter (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid && 76556115Speter euid != pc->pc_ucred->cr_uid) || 76656115Speter (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid && 76756115Speter suid != pc->pc_ucred->cr_uid)) && 76856115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 76956115Speter return (error); 77056115Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 77165495Struckman change_euid(p, euid); 77256115Speter setsugid(p); 77356115Speter } 77456115Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 77565495Struckman change_ruid(p, ruid); 77656115Speter setsugid(p); 77756115Speter } 77856115Speter if (suid != (uid_t)-1 && pc->p_svuid != suid) { 77956115Speter pc->p_svuid = suid; 78056115Speter setsugid(p); 78156115Speter } 78256115Speter return (0); 78356115Speter} 78456115Speter 78556115Speter/* 78656115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 78756115Speter * saved gid is explicit. 78856115Speter */ 78956115Speter 79056115Speter#ifndef _SYS_SYSPROTO_H_ 79156115Speterstruct setresgid_args { 79256115Speter gid_t rgid; 79356115Speter gid_t egid; 79456115Speter gid_t sgid; 79556115Speter}; 79656115Speter#endif 79756115Speter/* ARGSUSED */ 79856115Speterint 79956115Spetersetresgid(p, uap) 80056115Speter register struct proc *p; 80156115Speter struct setresgid_args *uap; 80256115Speter{ 80356115Speter register struct pcred *pc = p->p_cred; 80456115Speter register gid_t rgid, egid, sgid; 80556115Speter int error; 80656115Speter 80756115Speter rgid = uap->rgid; 80856115Speter egid = uap->egid; 80956115Speter sgid = uap->sgid; 81056115Speter if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid && 81156115Speter rgid != pc->pc_ucred->cr_groups[0]) || 81256115Speter (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid && 81356115Speter egid != pc->pc_ucred->cr_groups[0]) || 81456115Speter (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && 81556115Speter sgid != pc->pc_ucred->cr_groups[0])) && 81656115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 81756115Speter return (error); 81856115Speter 81956115Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 82056115Speter pc->pc_ucred = crcopy(pc->pc_ucred); 82156115Speter pc->pc_ucred->cr_groups[0] = egid; 82256115Speter setsugid(p); 82356115Speter } 82456115Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 82556115Speter pc->p_rgid = rgid; 82656115Speter setsugid(p); 82756115Speter } 82856115Speter if (sgid != (gid_t)-1 && pc->p_svgid != sgid) { 82956115Speter pc->p_svgid = sgid; 83056115Speter setsugid(p); 83156115Speter } 83256115Speter return (0); 83356115Speter} 83456115Speter 83556115Speter#ifndef _SYS_SYSPROTO_H_ 83656115Speterstruct getresuid_args { 83756115Speter uid_t *ruid; 83856115Speter uid_t *euid; 83956115Speter uid_t *suid; 84056115Speter}; 84156115Speter#endif 84256115Speter/* ARGSUSED */ 84356115Speterint 84456115Spetergetresuid(p, uap) 84556115Speter register struct proc *p; 84656115Speter struct getresuid_args *uap; 84756115Speter{ 84856115Speter struct pcred *pc = p->p_cred; 84956115Speter int error1 = 0, error2 = 0, error3 = 0; 85056115Speter 85156115Speter if (uap->ruid) 85256115Speter error1 = copyout((caddr_t)&pc->p_ruid, 85356115Speter (caddr_t)uap->ruid, sizeof(pc->p_ruid)); 85456115Speter if (uap->euid) 85556115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid, 85656115Speter (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid)); 85756115Speter if (uap->suid) 85856115Speter error3 = copyout((caddr_t)&pc->p_svuid, 85956115Speter (caddr_t)uap->suid, sizeof(pc->p_svuid)); 86056115Speter return error1 ? error1 : (error2 ? error2 : error3); 86156115Speter} 86256115Speter 86356115Speter#ifndef _SYS_SYSPROTO_H_ 86456115Speterstruct getresgid_args { 86556115Speter gid_t *rgid; 86656115Speter gid_t *egid; 86756115Speter gid_t *sgid; 86856115Speter}; 86956115Speter#endif 87056115Speter/* ARGSUSED */ 87156115Speterint 87256115Spetergetresgid(p, uap) 87356115Speter register struct proc *p; 87456115Speter struct getresgid_args *uap; 87556115Speter{ 87656115Speter struct pcred *pc = p->p_cred; 87756115Speter int error1 = 0, error2 = 0, error3 = 0; 87856115Speter 87956115Speter if (uap->rgid) 88056115Speter error1 = copyout((caddr_t)&pc->p_rgid, 88156115Speter (caddr_t)uap->rgid, sizeof(pc->p_rgid)); 88256115Speter if (uap->egid) 88356115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0], 88456115Speter (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0])); 88556115Speter if (uap->sgid) 88656115Speter error3 = copyout((caddr_t)&pc->p_svgid, 88756115Speter (caddr_t)uap->sgid, sizeof(pc->p_svgid)); 88856115Speter return error1 ? error1 : (error2 ? error2 : error3); 88956115Speter} 89056115Speter 89156115Speter 89256115Speter#ifndef _SYS_SYSPROTO_H_ 89324453Speterstruct issetugid_args { 89424453Speter int dummy; 89524453Speter}; 89624453Speter#endif 89724453Speter/* ARGSUSED */ 89824453Speterint 89930994Sphkissetugid(p, uap) 90024453Speter register struct proc *p; 90124453Speter struct issetugid_args *uap; 90224453Speter{ 90324453Speter /* 90424453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 90524453Speter * we use P_SUGID because we consider changing the owners as 90624453Speter * "tainting" as well. 90724453Speter * This is significant for procs that start as root and "become" 90824453Speter * a user without an exec - programs cannot know *everything* 90924453Speter * that libc *might* have put in their data segment. 91024453Speter */ 91160216Speter p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 91224453Speter return (0); 91324453Speter} 91424453Speter 91575426Srwatsonint 91675426Srwatson__setugid(p, uap) 91775426Srwatson struct proc *p; 91875426Srwatson struct __setugid_args *uap; 91975426Srwatson{ 92075426Srwatson 92175426Srwatson#ifdef REGRESSION 92275426Srwatson switch (uap->flag) { 92375426Srwatson case 0: 92475426Srwatson p->p_flag &= ~P_SUGID; 92575426Srwatson return (0); 92675426Srwatson case 1: 92775426Srwatson p->p_flag |= P_SUGID; 92875426Srwatson return (0); 92975426Srwatson default: 93075426Srwatson return (EINVAL); 93175426Srwatson } 93275426Srwatson#else /* !REGRESSION */ 93375426Srwatson return (ENOSYS); 93475426Srwatson#endif /* !REGRESSION */ 93575426Srwatson} 93675426Srwatson 9371541Srgrimes/* 9381541Srgrimes * Check if gid is a member of the group set. 9391541Srgrimes */ 9401549Srgrimesint 9411541Srgrimesgroupmember(gid, cred) 9421541Srgrimes gid_t gid; 9431541Srgrimes register struct ucred *cred; 9441541Srgrimes{ 9451541Srgrimes register gid_t *gp; 9461541Srgrimes gid_t *egp; 9471541Srgrimes 9481541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 9491541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 9501541Srgrimes if (*gp == gid) 9511541Srgrimes return (1); 9521541Srgrimes return (0); 9531541Srgrimes} 9541541Srgrimes 95561287Srwatsonstatic int suser_permitted = 1; 95661287Srwatson 95761287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 95861287Srwatson "processes with uid 0 have privilege"); 95961287Srwatson 9601541Srgrimes/* 9611541Srgrimes * Test whether the specified credentials imply "super-user" 9621541Srgrimes * privilege; if so, and we have accounting info, set the flag 9631541Srgrimes * indicating use of super-powers. 9641541Srgrimes * Returns 0 or error. 9651541Srgrimes */ 9661549Srgrimesint 96746112Sphksuser(p) 96872786Srwatson struct proc *p; 96946112Sphk{ 97046155Sphk return suser_xxx(0, p, 0); 97146112Sphk} 97246112Sphk 97346112Sphkint 97446155Sphksuser_xxx(cred, proc, flag) 97572786Srwatson struct ucred *cred; 97672786Srwatson struct proc *proc; 97746155Sphk int flag; 9781541Srgrimes{ 97961282Srwatson if (!suser_permitted) 98061282Srwatson return (EPERM); 98146155Sphk if (!cred && !proc) { 98246155Sphk printf("suser_xxx(): THINK!\n"); 98346155Sphk return (EPERM); 9841541Srgrimes } 98546155Sphk if (!cred) 98646155Sphk cred = proc->p_ucred; 98746155Sphk if (cred->cr_uid != 0) 98846155Sphk return (EPERM); 98972786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 99046155Sphk return (EPERM); 99146155Sphk return (0); 9921541Srgrimes} 9931541Srgrimes 99474956Srwatson/* 99574956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2 99674956Srwatson * Arguments: imutable credentials u1, u2 99774956Srwatson * Returns: 0 for permitted, an errno value otherwise 99874956Srwatson * Locks: none 99974956Srwatson * References: u1 and u2 must be valid for the lifetime of the call 100074956Srwatson * u1 may equal u2, in which case only one reference is required 100174956Srwatson */ 100274956Srwatsonint 100374956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2) 100465237Srwatson{ 100572786Srwatson int error; 100653518Sphk 100774956Srwatson if ((error = prison_check(u1, u2))) 100872786Srwatson return (error); 100974956Srwatson if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) { 101075005Srwatson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 101174956Srwatson return (ESRCH); 101265293Srwatson } 101365237Srwatson return (0); 101465237Srwatson} 101565237Srwatson 101665237Srwatsonstatic int 101774956Srwatsonp_cansee(struct proc *p1, struct proc *p2, int *privused) 101874956Srwatson{ 101974956Srwatson 102074956Srwatson /* XXX: privused is going away, so don't do that here. */ 102174956Srwatson if (privused != NULL) 102274956Srwatson *privused = 0; 102374956Srwatson /* Wrap u_cansee() for all functionality. */ 102474956Srwatson return (u_cansee(p1->p_ucred, p2->p_ucred)); 102574956Srwatson} 102674956Srwatson 102774956Srwatsonstatic int 102872786Srwatsonp_cankill(struct proc *p1, struct proc *p2, int *privused) 102953518Sphk{ 103072786Srwatson int error; 103153518Sphk 103265237Srwatson if (privused != NULL) 103365237Srwatson *privused = 0; 103465237Srwatson 103553518Sphk if (p1 == p2) 103653518Sphk return (0); 103765237Srwatson 103872786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 103972786Srwatson return (error); 104065237Srwatson 104153518Sphk if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 104253518Sphk return (0); 104353518Sphk if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 104453518Sphk return (0); 104565237Srwatson /* 104665237Srwatson * XXX should a process be able to affect another process 104765237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 104865237Srwatson */ 104953518Sphk if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 105053518Sphk return (0); 105153518Sphk if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 105253518Sphk return (0); 105365237Srwatson 105465237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 105565237Srwatson if (privused != NULL) 105665237Srwatson *privused = 1; 105753518Sphk return (0); 105865237Srwatson } 105965237Srwatson 106065237Srwatson#ifdef CAPABILITIES 106165237Srwatson if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) { 106265237Srwatson if (privused != NULL) 106365237Srwatson *privused = 1; 106465237Srwatson return (0); 106565237Srwatson } 106665237Srwatson#endif 106765237Srwatson 106853518Sphk return (EPERM); 106953518Sphk} 107053518Sphk 107165237Srwatsonstatic int 107272786Srwatsonp_cansched(struct proc *p1, struct proc *p2, int *privused) 107365237Srwatson{ 107472786Srwatson int error; 107565237Srwatson 107665237Srwatson if (privused != NULL) 107765237Srwatson *privused = 0; 107865237Srwatson 107965237Srwatson if (p1 == p2) 108065237Srwatson return (0); 108165237Srwatson 108272786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 108372786Srwatson return (error); 108465237Srwatson 108565237Srwatson if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 108665237Srwatson return (0); 108765237Srwatson if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 108865237Srwatson return (0); 108965237Srwatson /* 109065237Srwatson * XXX should a process be able to affect another process 109165237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 109265237Srwatson */ 109365237Srwatson if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 109465237Srwatson return (0); 109565237Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 109665237Srwatson return (0); 109765237Srwatson 109865237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 109965237Srwatson if (privused != NULL) 110065237Srwatson *privused = 1; 110165237Srwatson return (0); 110265237Srwatson } 110365237Srwatson 110465237Srwatson#ifdef CAPABILITIES 110565237Srwatson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { 110665237Srwatson if (privused != NULL) 110765237Srwatson *privused = 1; 110865237Srwatson return (0); 110965237Srwatson } 111065237Srwatson#endif 111165237Srwatson 111265237Srwatson return (EPERM); 111365237Srwatson} 111465237Srwatson 111565237Srwatsonstatic int 111672786Srwatsonp_candebug(struct proc *p1, struct proc *p2, int *privused) 111765237Srwatson{ 111872786Srwatson int error; 111965237Srwatson 112065237Srwatson if (privused != NULL) 112165237Srwatson *privused = 0; 112265237Srwatson 112365237Srwatson /* XXX it is authorized, but semantics don't permit it */ 112465237Srwatson if (p1 == p2) 112565237Srwatson return (0); 112665237Srwatson 112772786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 112872786Srwatson return (error); 112965237Srwatson 113065237Srwatson /* not owned by you, has done setuid (unless you're root) */ 113165237Srwatson /* add a CAP_SYS_PTRACE here? */ 113267999Srwatson if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid || 113367999Srwatson p1->p_cred->p_ruid != p2->p_cred->p_ruid || 113468591Srwatson p1->p_cred->p_svuid != p2->p_cred->p_ruid || 113567999Srwatson p2->p_flag & P_SUGID) { 113665237Srwatson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 113765237Srwatson return (error); 113865237Srwatson if (privused != NULL) 113965237Srwatson *privused = 1; 114065237Srwatson } 114165237Srwatson 114265237Srwatson /* can't trace init when securelevel > 0 */ 114365237Srwatson if (securelevel > 0 && p2->p_pid == 1) 114465237Srwatson return (EPERM); 114565237Srwatson 114665237Srwatson return (0); 114765237Srwatson} 114865237Srwatson 114965237Srwatsonint 115072786Srwatsonp_can(struct proc *p1, struct proc *p2, int operation, 115165237Srwatson int *privused) 115265237Srwatson{ 115365237Srwatson 115465237Srwatson switch(operation) { 115565237Srwatson case P_CAN_SEE: 115665237Srwatson return (p_cansee(p1, p2, privused)); 115765237Srwatson 115865237Srwatson case P_CAN_KILL: 115965237Srwatson return (p_cankill(p1, p2, privused)); 116065237Srwatson 116165237Srwatson case P_CAN_SCHED: 116265237Srwatson return (p_cansched(p1, p2, privused)); 116365237Srwatson 116465237Srwatson case P_CAN_DEBUG: 116565237Srwatson return (p_candebug(p1, p2, privused)); 116665237Srwatson 116765237Srwatson default: 116865237Srwatson panic("p_can: invalid operation"); 116965237Srwatson } 117065237Srwatson} 117165237Srwatson 117265237Srwatson 117353518Sphk/* 11741541Srgrimes * Allocate a zeroed cred structure. 11751541Srgrimes */ 11761541Srgrimesstruct ucred * 11771541Srgrimescrget() 11781541Srgrimes{ 11791541Srgrimes register struct ucred *cr; 11801541Srgrimes 118169239Salfred MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 11821541Srgrimes cr->cr_ref = 1; 118369239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 11841541Srgrimes return (cr); 11851541Srgrimes} 11861541Srgrimes 11871541Srgrimes/* 118872474Srwatson * Claim another reference to a ucred structure 118969401Salfred */ 119069401Salfredvoid 119169401Salfredcrhold(cr) 119269401Salfred struct ucred *cr; 119369401Salfred{ 119469401Salfred 119572200Sbmilekic mtx_lock(&cr->cr_mtx); 119669401Salfred cr->cr_ref++; 119772200Sbmilekic mtx_unlock(&(cr)->cr_mtx); 119869401Salfred} 119969401Salfred 120069401Salfred 120169401Salfred/* 12021541Srgrimes * Free a cred structure. 12031541Srgrimes * Throws away space when ref count gets to 0. 12041541Srgrimes */ 12051549Srgrimesvoid 12061541Srgrimescrfree(cr) 12071541Srgrimes struct ucred *cr; 12081541Srgrimes{ 120969239Salfred 121072200Sbmilekic mtx_lock(&cr->cr_mtx); 121165495Struckman if (--cr->cr_ref == 0) { 121269239Salfred mtx_destroy(&cr->cr_mtx); 121365495Struckman /* 121465495Struckman * Some callers of crget(), such as nfs_statfs(), 121565495Struckman * allocate a temporary credential, but don't 121665495Struckman * allocate a uidinfo structure. 121765495Struckman */ 121865495Struckman if (cr->cr_uidinfo != NULL) 121965495Struckman uifree(cr->cr_uidinfo); 122072786Srwatson /* 122172786Srwatson * Free a prison, if any. 122272786Srwatson */ 122372786Srwatson if (jailed(cr)) 122472786Srwatson prison_free(cr->cr_prison); 12251541Srgrimes FREE((caddr_t)cr, M_CRED); 122669239Salfred } else { 122772200Sbmilekic mtx_unlock(&cr->cr_mtx); 122865495Struckman } 12291541Srgrimes} 12301541Srgrimes 12311541Srgrimes/* 12321541Srgrimes * Copy cred structure to a new one and free the old one. 12331541Srgrimes */ 12341541Srgrimesstruct ucred * 12351541Srgrimescrcopy(cr) 12361541Srgrimes struct ucred *cr; 12371541Srgrimes{ 12381541Srgrimes struct ucred *newcr; 12391541Srgrimes 124072200Sbmilekic mtx_lock(&cr->cr_mtx); 124169239Salfred if (cr->cr_ref == 1) { 124272200Sbmilekic mtx_unlock(&cr->cr_mtx); 12431541Srgrimes return (cr); 124469239Salfred } 124572200Sbmilekic mtx_unlock(&cr->cr_mtx); 124669239Salfred newcr = crdup(cr); 12471541Srgrimes crfree(cr); 12481541Srgrimes return (newcr); 12491541Srgrimes} 12501541Srgrimes 12511541Srgrimes/* 12521541Srgrimes * Dup cred struct to a new held one. 12531541Srgrimes */ 12541541Srgrimesstruct ucred * 12551541Srgrimescrdup(cr) 12561541Srgrimes struct ucred *cr; 12571541Srgrimes{ 12581541Srgrimes struct ucred *newcr; 12591541Srgrimes 126069239Salfred MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 12611541Srgrimes *newcr = *cr; 126269239Salfred mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 126365495Struckman uihold(newcr->cr_uidinfo); 126472786Srwatson if (jailed(newcr)) 126572786Srwatson prison_hold(newcr->cr_prison); 12661541Srgrimes newcr->cr_ref = 1; 12671541Srgrimes return (newcr); 12681541Srgrimes} 12691541Srgrimes 12701541Srgrimes/* 12711541Srgrimes * Get login name, if available. 12721541Srgrimes */ 127312221Sbde#ifndef _SYS_SYSPROTO_H_ 12741541Srgrimesstruct getlogin_args { 12751541Srgrimes char *namebuf; 12761541Srgrimes u_int namelen; 12771541Srgrimes}; 127812221Sbde#endif 12791541Srgrimes/* ARGSUSED */ 12801549Srgrimesint 128130994Sphkgetlogin(p, uap) 12821541Srgrimes struct proc *p; 12831541Srgrimes struct getlogin_args *uap; 12841541Srgrimes{ 12851541Srgrimes 128623358Sache if (uap->namelen > MAXLOGNAME) 128723359Sache uap->namelen = MAXLOGNAME; 12881541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 12891541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 12901541Srgrimes} 12911541Srgrimes 12921541Srgrimes/* 12931541Srgrimes * Set login name. 12941541Srgrimes */ 129512221Sbde#ifndef _SYS_SYSPROTO_H_ 12961541Srgrimesstruct setlogin_args { 12971541Srgrimes char *namebuf; 12981541Srgrimes}; 129912221Sbde#endif 13001541Srgrimes/* ARGSUSED */ 13011549Srgrimesint 130230994Sphksetlogin(p, uap) 13031541Srgrimes struct proc *p; 13041541Srgrimes struct setlogin_args *uap; 13051541Srgrimes{ 13061541Srgrimes int error; 130723330Sache char logintmp[MAXLOGNAME]; 13081541Srgrimes 130946155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 13101541Srgrimes return (error); 131122522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 131236845Sdfr sizeof(logintmp), (size_t *)0); 13131541Srgrimes if (error == ENAMETOOLONG) 13141541Srgrimes error = EINVAL; 131522522Sdavidn else if (!error) 131622522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 131723330Sache sizeof(logintmp)); 13181541Srgrimes return (error); 13191541Srgrimes} 132031891Ssef 132131891Ssefvoid 132231891Ssefsetsugid(p) 132355338Sphk struct proc *p; 132431891Ssef{ 132531891Ssef p->p_flag |= P_SUGID; 132655707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 132731891Ssef p->p_stops = 0; 132831891Ssef} 132965495Struckman 133065495Struckman/* 133165495Struckman * Helper function to change the effective uid of a process 133265495Struckman */ 133365495Struckmanvoid 133465495Struckmanchange_euid(p, euid) 133565495Struckman struct proc *p; 133665495Struckman uid_t euid; 133765495Struckman{ 133865495Struckman struct pcred *pc; 133965495Struckman struct uidinfo *uip; 134065495Struckman 134165495Struckman pc = p->p_cred; 134265495Struckman /* 134365495Struckman * crcopy is essentially a NOP if ucred has a reference count 134465495Struckman * of 1, which is true if it has already been copied. 134565495Struckman */ 134665495Struckman pc->pc_ucred = crcopy(pc->pc_ucred); 134765495Struckman uip = pc->pc_ucred->cr_uidinfo; 134865495Struckman pc->pc_ucred->cr_uid = euid; 134965495Struckman pc->pc_ucred->cr_uidinfo = uifind(euid); 135065495Struckman uifree(uip); 135165495Struckman} 135265495Struckman 135365495Struckman/* 135465495Struckman * Helper function to change the real uid of a process 135565495Struckman * 135665495Struckman * The per-uid process count for this process is transfered from 135765495Struckman * the old uid to the new uid. 135865495Struckman */ 135967629Sgallatinvoid 136065495Struckmanchange_ruid(p, ruid) 136165495Struckman struct proc *p; 136265495Struckman uid_t ruid; 136365495Struckman{ 136465495Struckman struct pcred *pc; 136565495Struckman struct uidinfo *uip; 136665495Struckman 136765495Struckman pc = p->p_cred; 136865495Struckman (void)chgproccnt(pc->p_uidinfo, -1, 0); 136965495Struckman uip = pc->p_uidinfo; 137065495Struckman /* It is assumed that pcred is not shared between processes */ 137165495Struckman pc->p_ruid = ruid; 137265495Struckman pc->p_uidinfo = uifind(ruid); 137365495Struckman (void)chgproccnt(pc->p_uidinfo, 1, 0); 137465495Struckman uifree(uip); 137565495Struckman} 1376