kern_prot.c revision 72093
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 72093 2001-02-06 12:05:58Z asmodai $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes/* 431541Srgrimes * System calls related to processes and protection 441541Srgrimes */ 451541Srgrimes 4631778Seivind#include "opt_compat.h" 4731778Seivind 481541Srgrimes#include <sys/param.h> 491541Srgrimes#include <sys/acct.h> 501541Srgrimes#include <sys/systm.h> 5112221Sbde#include <sys/sysproto.h> 5241059Speter#include <sys/kernel.h> 5370317Sjake#include <sys/lock.h> 541541Srgrimes#include <sys/proc.h> 551541Srgrimes#include <sys/malloc.h> 5631891Ssef#include <sys/pioctl.h> 5765495Struckman#include <sys/resourcevar.h> 5861287Srwatson#include <sys/sysctl.h> 591541Srgrimes 6030354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6130354Sphk 6212221Sbde#ifndef _SYS_SYSPROTO_H_ 6311332Sswallacestruct getpid_args { 641541Srgrimes int dummy; 651541Srgrimes}; 6612221Sbde#endif 671541Srgrimes 6858717Sdillon/* 6970317Sjake * getpid - MP SAFE 7058717Sdillon */ 7170317Sjake 721541Srgrimes/* ARGSUSED */ 731549Srgrimesint 7430994Sphkgetpid(p, uap) 751541Srgrimes struct proc *p; 7611332Sswallace struct getpid_args *uap; 771541Srgrimes{ 781541Srgrimes 7930994Sphk p->p_retval[0] = p->p_pid; 801541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8170317Sjake PROCTREE_LOCK(PT_SHARED); 8230994Sphk p->p_retval[1] = p->p_pptr->p_pid; 8370317Sjake PROCTREE_LOCK(PT_RELEASE); 841541Srgrimes#endif 851541Srgrimes return (0); 861541Srgrimes} 871541Srgrimes 8870317Sjake/* 8970317Sjake * getppid - MP SAFE 9070317Sjake */ 9170317Sjake 9212221Sbde#ifndef _SYS_SYSPROTO_H_ 9311332Sswallacestruct getppid_args { 9411332Sswallace int dummy; 9511332Sswallace}; 9612221Sbde#endif 971541Srgrimes/* ARGSUSED */ 981549Srgrimesint 9930994Sphkgetppid(p, uap) 1001541Srgrimes struct proc *p; 10111332Sswallace struct getppid_args *uap; 1021541Srgrimes{ 1031541Srgrimes 10470317Sjake PROCTREE_LOCK(PT_SHARED); 10530994Sphk p->p_retval[0] = p->p_pptr->p_pid; 10670317Sjake PROCTREE_LOCK(PT_RELEASE); 1071541Srgrimes return (0); 1081541Srgrimes} 1091541Srgrimes 11058717Sdillon/* 11158717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter 11258717Sdillon * 11358717Sdillon * MP SAFE 11458717Sdillon */ 11512221Sbde#ifndef _SYS_SYSPROTO_H_ 11611332Sswallacestruct getpgrp_args { 11711332Sswallace int dummy; 11811332Sswallace}; 11912221Sbde#endif 12011332Sswallace 1211549Srgrimesint 12230994Sphkgetpgrp(p, uap) 1231541Srgrimes struct proc *p; 12411332Sswallace struct getpgrp_args *uap; 1251541Srgrimes{ 1261541Srgrimes 12730994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1281541Srgrimes return (0); 1291541Srgrimes} 1301541Srgrimes 13128401Speter/* Get an arbitary pid's process group id */ 13212221Sbde#ifndef _SYS_SYSPROTO_H_ 13328401Speterstruct getpgid_args { 13428401Speter pid_t pid; 13528401Speter}; 13628401Speter#endif 13728401Speter 13828401Speterint 13930994Sphkgetpgid(p, uap) 14028401Speter struct proc *p; 14128401Speter struct getpgid_args *uap; 14228401Speter{ 14341726Struckman struct proc *pt; 14441726Struckman 14541726Struckman pt = p; 14628401Speter if (uap->pid == 0) 14728401Speter goto found; 14828401Speter 14941726Struckman if ((pt = pfind(uap->pid)) == 0) 15028401Speter return ESRCH; 15128401Speterfound: 15241726Struckman p->p_retval[0] = pt->p_pgrp->pg_id; 15328401Speter return 0; 15428401Speter} 15528401Speter 15628401Speter/* 15728401Speter * Get an arbitary pid's session id. 15828401Speter */ 15928401Speter#ifndef _SYS_SYSPROTO_H_ 16028401Speterstruct getsid_args { 16128401Speter pid_t pid; 16228401Speter}; 16328401Speter#endif 16428401Speter 16528401Speterint 16630994Sphkgetsid(p, uap) 16728401Speter struct proc *p; 16828401Speter struct getsid_args *uap; 16928401Speter{ 17041726Struckman struct proc *pt; 17141726Struckman 17241726Struckman pt = p; 17328401Speter if (uap->pid == 0) 17428401Speter goto found; 17528401Speter 17671002Sben if ((pt = pfind(uap->pid)) == 0) 17728401Speter return ESRCH; 17828401Speterfound: 17941726Struckman p->p_retval[0] = pt->p_session->s_sid; 18028401Speter return 0; 18128401Speter} 18228401Speter 18328401Speter 18458941Sdillon/* 18558941Sdillon * getuid() - MP SAFE 18658941Sdillon */ 18728401Speter#ifndef _SYS_SYSPROTO_H_ 18811332Sswallacestruct getuid_args { 18911332Sswallace int dummy; 19011332Sswallace}; 19112221Sbde#endif 19211332Sswallace 1931541Srgrimes/* ARGSUSED */ 1941549Srgrimesint 19530994Sphkgetuid(p, uap) 1961541Srgrimes struct proc *p; 19711332Sswallace struct getuid_args *uap; 1981541Srgrimes{ 1991541Srgrimes 20030994Sphk p->p_retval[0] = p->p_cred->p_ruid; 2011541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 20230994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 2031541Srgrimes#endif 2041541Srgrimes return (0); 2051541Srgrimes} 2061541Srgrimes 20758941Sdillon/* 20858941Sdillon * geteuid() - MP SAFE 20958941Sdillon */ 21012221Sbde#ifndef _SYS_SYSPROTO_H_ 21111332Sswallacestruct geteuid_args { 21211332Sswallace int dummy; 21311332Sswallace}; 21412221Sbde#endif 21511332Sswallace 2161541Srgrimes/* ARGSUSED */ 2171549Srgrimesint 21830994Sphkgeteuid(p, uap) 2191541Srgrimes struct proc *p; 22011332Sswallace struct geteuid_args *uap; 2211541Srgrimes{ 2221541Srgrimes 22330994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2241541Srgrimes return (0); 2251541Srgrimes} 2261541Srgrimes 22758941Sdillon/* 22858941Sdillon * getgid() - MP SAFE 22958941Sdillon */ 23012221Sbde#ifndef _SYS_SYSPROTO_H_ 23111332Sswallacestruct getgid_args { 23211332Sswallace int dummy; 23311332Sswallace}; 23412221Sbde#endif 23511332Sswallace 2361541Srgrimes/* ARGSUSED */ 2371549Srgrimesint 23830994Sphkgetgid(p, uap) 2391541Srgrimes struct proc *p; 24011332Sswallace struct getgid_args *uap; 2411541Srgrimes{ 2421541Srgrimes 24330994Sphk p->p_retval[0] = p->p_cred->p_rgid; 2441541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 24530994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2461541Srgrimes#endif 2471541Srgrimes return (0); 2481541Srgrimes} 2491541Srgrimes 2501541Srgrimes/* 2511541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2521541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2531541Srgrimes * correctly in a library function. 2541541Srgrimes */ 25512221Sbde#ifndef _SYS_SYSPROTO_H_ 25611332Sswallacestruct getegid_args { 25711332Sswallace int dummy; 25811332Sswallace}; 25912221Sbde#endif 26011332Sswallace 2611541Srgrimes/* ARGSUSED */ 2621549Srgrimesint 26330994Sphkgetegid(p, uap) 2641541Srgrimes struct proc *p; 26511332Sswallace struct getegid_args *uap; 2661541Srgrimes{ 2671541Srgrimes 26830994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2691541Srgrimes return (0); 2701541Srgrimes} 2711541Srgrimes 27212221Sbde#ifndef _SYS_SYSPROTO_H_ 2731541Srgrimesstruct getgroups_args { 2741541Srgrimes u_int gidsetsize; 2751541Srgrimes gid_t *gidset; 2761541Srgrimes}; 27712221Sbde#endif 2781549Srgrimesint 27930994Sphkgetgroups(p, uap) 2801541Srgrimes struct proc *p; 2811541Srgrimes register struct getgroups_args *uap; 2821541Srgrimes{ 2831541Srgrimes register struct pcred *pc = p->p_cred; 2841541Srgrimes register u_int ngrp; 2851541Srgrimes int error; 2861541Srgrimes 2871541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 28830994Sphk p->p_retval[0] = pc->pc_ucred->cr_ngroups; 2891541Srgrimes return (0); 2901541Srgrimes } 2911541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 2921541Srgrimes return (EINVAL); 2931541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 2943098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 2953098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 2961541Srgrimes return (error); 29730994Sphk p->p_retval[0] = ngrp; 2981541Srgrimes return (0); 2991541Srgrimes} 3001541Srgrimes 30112221Sbde#ifndef _SYS_SYSPROTO_H_ 30212207Sbdestruct setsid_args { 30311332Sswallace int dummy; 30411332Sswallace}; 30512221Sbde#endif 30611332Sswallace 3071541Srgrimes/* ARGSUSED */ 3081549Srgrimesint 30930994Sphksetsid(p, uap) 3101541Srgrimes register struct proc *p; 31112207Sbde struct setsid_args *uap; 3121541Srgrimes{ 3131541Srgrimes 3141541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 3151541Srgrimes return (EPERM); 3161541Srgrimes } else { 3171541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 31830994Sphk p->p_retval[0] = p->p_pid; 3191541Srgrimes return (0); 3201541Srgrimes } 3211541Srgrimes} 3221541Srgrimes 3231541Srgrimes/* 3241541Srgrimes * set process group (setpgid/old setpgrp) 3251541Srgrimes * 3261541Srgrimes * caller does setpgid(targpid, targpgid) 3271541Srgrimes * 3281541Srgrimes * pid must be caller or child of caller (ESRCH) 3291541Srgrimes * if a child 3301541Srgrimes * pid must be in same session (EPERM) 3311541Srgrimes * pid can't have done an exec (EACCES) 3321541Srgrimes * if pgid != pid 3331541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3341541Srgrimes * pid must not be session leader (EPERM) 3351541Srgrimes */ 33612221Sbde#ifndef _SYS_SYSPROTO_H_ 3371541Srgrimesstruct setpgid_args { 3381541Srgrimes int pid; /* target process id */ 3391541Srgrimes int pgid; /* target pgrp id */ 3401541Srgrimes}; 34112221Sbde#endif 3421541Srgrimes/* ARGSUSED */ 3431549Srgrimesint 34430994Sphksetpgid(curp, uap) 3451541Srgrimes struct proc *curp; 3461541Srgrimes register struct setpgid_args *uap; 3471541Srgrimes{ 3481541Srgrimes register struct proc *targp; /* target process */ 3491541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 3501541Srgrimes 35120677Sbde if (uap->pgid < 0) 35220677Sbde return (EINVAL); 3531541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 3541541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 3551541Srgrimes return (ESRCH); 35615985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 3571541Srgrimes return (EPERM); 3581541Srgrimes if (targp->p_flag & P_EXEC) 3591541Srgrimes return (EACCES); 3601541Srgrimes } else 3611541Srgrimes targp = curp; 3621541Srgrimes if (SESS_LEADER(targp)) 3631541Srgrimes return (EPERM); 3641541Srgrimes if (uap->pgid == 0) 3651541Srgrimes uap->pgid = targp->p_pid; 3661541Srgrimes else if (uap->pgid != targp->p_pid) 3671541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 3681541Srgrimes pgrp->pg_session != curp->p_session) 3691541Srgrimes return (EPERM); 3701541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 3711541Srgrimes} 3721541Srgrimes 37324448Speter/* 37424448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 37572093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 37624448Speter * case of "appropriate privilege". Once the rules are expanded out, this 37724448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 37824448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 37924448Speter * does not set the saved id - this is dangerous for traditional BSD 38024448Speter * programs. For this reason, we *really* do not want to set 38124448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 38224448Speter */ 38324448Speter#define POSIX_APPENDIX_B_4_2_2 38424448Speter 38512221Sbde#ifndef _SYS_SYSPROTO_H_ 3861541Srgrimesstruct setuid_args { 3871541Srgrimes uid_t uid; 3881541Srgrimes}; 38912221Sbde#endif 3901541Srgrimes/* ARGSUSED */ 3911549Srgrimesint 39230994Sphksetuid(p, uap) 3931541Srgrimes struct proc *p; 3941541Srgrimes struct setuid_args *uap; 3951541Srgrimes{ 3961541Srgrimes register struct pcred *pc = p->p_cred; 3971541Srgrimes register uid_t uid; 3981541Srgrimes int error; 3991541Srgrimes 40024448Speter /* 40124448Speter * See if we have "permission" by POSIX 1003.1 rules. 40224448Speter * 40324448Speter * Note that setuid(geteuid()) is a special case of 40424448Speter * "appropriate privileges" in appendix B.4.2.2. We need 40572093Sasmodai * to use this clause to be compatible with traditional BSD 40624448Speter * semantics. Basically, it means that "setuid(xx)" sets all 40724448Speter * three id's (assuming you have privs). 40824448Speter * 40924448Speter * Notes on the logic. We do things in three steps. 41024448Speter * 1: We determine if the euid is going to change, and do EPERM 41124448Speter * right away. We unconditionally change the euid later if this 41224448Speter * test is satisfied, simplifying that part of the logic. 41324448Speter * 2: We determine if the real and/or saved uid's are going to 41424448Speter * change. Determined by compile options. 41524448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 41624448Speter */ 4171541Srgrimes uid = uap->uid; 41824448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 41917994Sache#ifdef _POSIX_SAVED_IDS 42024448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 42117994Sache#endif 42224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 42324448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 42424448Speter#endif 42546155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4261541Srgrimes return (error); 42724448Speter 42824448Speter#ifdef _POSIX_SAVED_IDS 4291541Srgrimes /* 43024448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 43124448Speter * If so, we are changing the real uid and/or saved uid. 4321541Srgrimes */ 43317994Sache if ( 43424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 43524448Speter uid == pc->pc_ucred->cr_uid || 43617994Sache#endif 43746155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 43817994Sache#endif 43924448Speter { 44024448Speter /* 44165495Struckman * Set the real uid and transfer proc count to new user. 44224448Speter */ 44324448Speter if (uid != pc->p_ruid) { 44465495Struckman change_ruid(p, uid); 44565495Struckman setsugid(p); 44624448Speter } 44724448Speter /* 44824448Speter * Set saved uid 44924448Speter * 45024448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 45124448Speter * the security of seteuid() depends on it. B.4.2.2 says it 45224448Speter * is important that we should do this. 45324448Speter */ 45424448Speter if (pc->p_svuid != uid) { 45524448Speter pc->p_svuid = uid; 45631891Ssef setsugid(p); 45724448Speter } 4588141Sache } 45924448Speter 46024448Speter /* 46124448Speter * In all permitted cases, we are changing the euid. 46224448Speter * Copy credentials so other references do not see our changes. 46324448Speter */ 46424448Speter if (pc->pc_ucred->cr_uid != uid) { 46565495Struckman change_euid(p, uid); 46631891Ssef setsugid(p); 46724448Speter } 4681541Srgrimes return (0); 4691541Srgrimes} 4701541Srgrimes 47112221Sbde#ifndef _SYS_SYSPROTO_H_ 4721541Srgrimesstruct seteuid_args { 4731541Srgrimes uid_t euid; 4741541Srgrimes}; 47512221Sbde#endif 4761541Srgrimes/* ARGSUSED */ 4771549Srgrimesint 47830994Sphkseteuid(p, uap) 4791541Srgrimes struct proc *p; 4801541Srgrimes struct seteuid_args *uap; 4811541Srgrimes{ 4821541Srgrimes register struct pcred *pc = p->p_cred; 4831541Srgrimes register uid_t euid; 4841541Srgrimes int error; 4851541Srgrimes 4861541Srgrimes euid = uap->euid; 48724449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 48824449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 48946155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4901541Srgrimes return (error); 4911541Srgrimes /* 4921541Srgrimes * Everything's okay, do it. Copy credentials so other references do 4931541Srgrimes * not see our changes. 4941541Srgrimes */ 49524449Speter if (pc->pc_ucred->cr_uid != euid) { 49665495Struckman change_euid(p, euid); 49731891Ssef setsugid(p); 49824449Speter } 4991541Srgrimes return (0); 5001541Srgrimes} 5011541Srgrimes 50212221Sbde#ifndef _SYS_SYSPROTO_H_ 5031541Srgrimesstruct setgid_args { 5041541Srgrimes gid_t gid; 5051541Srgrimes}; 50612221Sbde#endif 5071541Srgrimes/* ARGSUSED */ 5081549Srgrimesint 50930994Sphksetgid(p, uap) 5101541Srgrimes struct proc *p; 5111541Srgrimes struct setgid_args *uap; 5121541Srgrimes{ 5131541Srgrimes register struct pcred *pc = p->p_cred; 5141541Srgrimes register gid_t gid; 5151541Srgrimes int error; 5161541Srgrimes 51724448Speter /* 51824448Speter * See if we have "permission" by POSIX 1003.1 rules. 51924448Speter * 52024448Speter * Note that setgid(getegid()) is a special case of 52124448Speter * "appropriate privileges" in appendix B.4.2.2. We need 52272093Sasmodai * to use this clause to be compatible with traditional BSD 52324448Speter * semantics. Basically, it means that "setgid(xx)" sets all 52424448Speter * three id's (assuming you have privs). 52524448Speter * 52624448Speter * For notes on the logic here, see setuid() above. 52724448Speter */ 5281541Srgrimes gid = uap->gid; 52924448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 53017994Sache#ifdef _POSIX_SAVED_IDS 53124448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 53217994Sache#endif 53324448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 53424448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 53524448Speter#endif 53646155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 5371541Srgrimes return (error); 53824448Speter 53917994Sache#ifdef _POSIX_SAVED_IDS 54024448Speter /* 54124448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 54224448Speter * If so, we are changing the real uid and saved gid. 54324448Speter */ 54424448Speter if ( 54524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 54624448Speter gid == pc->pc_ucred->cr_groups[0] || 54717994Sache#endif 54846155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 54924448Speter#endif 55024448Speter { 55124448Speter /* 55224448Speter * Set real gid 55324448Speter */ 55424448Speter if (pc->p_rgid != gid) { 55524448Speter pc->p_rgid = gid; 55631891Ssef setsugid(p); 55724448Speter } 55824448Speter /* 55924448Speter * Set saved gid 56024448Speter * 56124448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 56224448Speter * the security of setegid() depends on it. B.4.2.2 says it 56324448Speter * is important that we should do this. 56424448Speter */ 56524448Speter if (pc->p_svgid != gid) { 56624448Speter pc->p_svgid = gid; 56731891Ssef setsugid(p); 56824448Speter } 5698141Sache } 57024448Speter /* 57124448Speter * In all cases permitted cases, we are changing the egid. 57224448Speter * Copy credentials so other references do not see our changes. 57324448Speter */ 57424448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 57524448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 57624448Speter pc->pc_ucred->cr_groups[0] = gid; 57731891Ssef setsugid(p); 57824448Speter } 5791541Srgrimes return (0); 5801541Srgrimes} 5811541Srgrimes 58212221Sbde#ifndef _SYS_SYSPROTO_H_ 5831541Srgrimesstruct setegid_args { 5841541Srgrimes gid_t egid; 5851541Srgrimes}; 58612221Sbde#endif 5871541Srgrimes/* ARGSUSED */ 5881549Srgrimesint 58930994Sphksetegid(p, uap) 5901541Srgrimes struct proc *p; 5911541Srgrimes struct setegid_args *uap; 5921541Srgrimes{ 5931541Srgrimes register struct pcred *pc = p->p_cred; 5941541Srgrimes register gid_t egid; 5951541Srgrimes int error; 5961541Srgrimes 5971541Srgrimes egid = uap->egid; 59824449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 59924449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 60046155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 6011541Srgrimes return (error); 60224449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 60324449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 60424449Speter pc->pc_ucred->cr_groups[0] = egid; 60531891Ssef setsugid(p); 60624449Speter } 6071541Srgrimes return (0); 6081541Srgrimes} 6091541Srgrimes 61012221Sbde#ifndef _SYS_SYSPROTO_H_ 6111541Srgrimesstruct setgroups_args { 6121541Srgrimes u_int gidsetsize; 6131541Srgrimes gid_t *gidset; 6141541Srgrimes}; 61512221Sbde#endif 6161541Srgrimes/* ARGSUSED */ 6171549Srgrimesint 61830994Sphksetgroups(p, uap) 6191541Srgrimes struct proc *p; 6201541Srgrimes struct setgroups_args *uap; 6211541Srgrimes{ 6221541Srgrimes register struct pcred *pc = p->p_cred; 6231541Srgrimes register u_int ngrp; 6241541Srgrimes int error; 6251541Srgrimes 62646155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 6271541Srgrimes return (error); 62812063Sdg ngrp = uap->gidsetsize; 62924447Speter if (ngrp > NGROUPS) 6301541Srgrimes return (EINVAL); 63124447Speter /* 63224447Speter * XXX A little bit lazy here. We could test if anything has 63324447Speter * changed before crcopy() and setting P_SUGID. 63424447Speter */ 6351541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 63624447Speter if (ngrp < 1) { 63724447Speter /* 63824447Speter * setgroups(0, NULL) is a legitimate way of clearing the 63924447Speter * groups vector on non-BSD systems (which generally do not 64024447Speter * have the egid in the groups[0]). We risk security holes 64124447Speter * when running non-BSD software if we do not do the same. 64224447Speter */ 64324447Speter pc->pc_ucred->cr_ngroups = 1; 64424447Speter } else { 64524447Speter if ((error = copyin((caddr_t)uap->gidset, 64624447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 64724447Speter return (error); 64824447Speter pc->pc_ucred->cr_ngroups = ngrp; 64924447Speter } 65031891Ssef setsugid(p); 6511541Srgrimes return (0); 6521541Srgrimes} 6531541Srgrimes 65412221Sbde#ifndef _SYS_SYSPROTO_H_ 6551541Srgrimesstruct setreuid_args { 6569238Sache uid_t ruid; 6579238Sache uid_t euid; 6581541Srgrimes}; 65912221Sbde#endif 6601541Srgrimes/* ARGSUSED */ 6611549Srgrimesint 66230994Sphksetreuid(p, uap) 6631541Srgrimes register struct proc *p; 6641541Srgrimes struct setreuid_args *uap; 6651541Srgrimes{ 6661541Srgrimes register struct pcred *pc = p->p_cred; 6679238Sache register uid_t ruid, euid; 6688135Sache int error; 6691541Srgrimes 6709238Sache ruid = uap->ruid; 6719238Sache euid = uap->euid; 67243311Sdillon if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || 67343311Sdillon (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 67443311Sdillon euid != pc->p_ruid && euid != pc->p_svuid)) && 67546155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 6768135Sache return (error); 6779238Sache 67824450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 67965495Struckman change_euid(p, euid); 68031891Ssef setsugid(p); 68124450Speter } 68224450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 68365495Struckman change_ruid(p, ruid); 68431891Ssef setsugid(p); 6858135Sache } 68624559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 68724559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6888111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 68931891Ssef setsugid(p); 69024450Speter } 6918135Sache return (0); 6921541Srgrimes} 6931541Srgrimes 69412221Sbde#ifndef _SYS_SYSPROTO_H_ 6951541Srgrimesstruct setregid_args { 6969238Sache gid_t rgid; 6979238Sache gid_t egid; 6981541Srgrimes}; 69912221Sbde#endif 7001541Srgrimes/* ARGSUSED */ 7011549Srgrimesint 70230994Sphksetregid(p, uap) 7031541Srgrimes register struct proc *p; 7041541Srgrimes struct setregid_args *uap; 7051541Srgrimes{ 7061541Srgrimes register struct pcred *pc = p->p_cred; 7079238Sache register gid_t rgid, egid; 7088135Sache int error; 7091541Srgrimes 7109238Sache rgid = uap->rgid; 7119238Sache egid = uap->egid; 71243311Sdillon if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || 71343311Sdillon (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 71443311Sdillon egid != pc->p_rgid && egid != pc->p_svgid)) && 71546155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 7168135Sache return (error); 7179238Sache 71824450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 71924450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 7209238Sache pc->pc_ucred->cr_groups[0] = egid; 72131891Ssef setsugid(p); 72224450Speter } 72324450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 7249238Sache pc->p_rgid = rgid; 72531891Ssef setsugid(p); 72624450Speter } 72724559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 72824559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7298111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 73031891Ssef setsugid(p); 73124450Speter } 7328135Sache return (0); 7331541Srgrimes} 7341541Srgrimes 73556115Speter/* 73656115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 73756115Speter * saved uid is explicit. 73856115Speter */ 73956115Speter 74024453Speter#ifndef _SYS_SYSPROTO_H_ 74156115Speterstruct setresuid_args { 74256115Speter uid_t ruid; 74356115Speter uid_t euid; 74456115Speter uid_t suid; 74556115Speter}; 74656115Speter#endif 74756115Speter/* ARGSUSED */ 74856115Speterint 74956115Spetersetresuid(p, uap) 75056115Speter register struct proc *p; 75156115Speter struct setresuid_args *uap; 75256115Speter{ 75356115Speter register struct pcred *pc = p->p_cred; 75456115Speter register uid_t ruid, euid, suid; 75556115Speter int error; 75656115Speter 75756115Speter ruid = uap->ruid; 75856115Speter euid = uap->euid; 75956115Speter suid = uap->suid; 76056115Speter if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid && 76156115Speter ruid != pc->pc_ucred->cr_uid) || 76256115Speter (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid && 76356115Speter euid != pc->pc_ucred->cr_uid) || 76456115Speter (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid && 76556115Speter suid != pc->pc_ucred->cr_uid)) && 76656115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 76756115Speter return (error); 76856115Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 76965495Struckman change_euid(p, euid); 77056115Speter setsugid(p); 77156115Speter } 77256115Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 77365495Struckman change_ruid(p, ruid); 77456115Speter setsugid(p); 77556115Speter } 77656115Speter if (suid != (uid_t)-1 && pc->p_svuid != suid) { 77756115Speter pc->p_svuid = suid; 77856115Speter setsugid(p); 77956115Speter } 78056115Speter return (0); 78156115Speter} 78256115Speter 78356115Speter/* 78456115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 78556115Speter * saved gid is explicit. 78656115Speter */ 78756115Speter 78856115Speter#ifndef _SYS_SYSPROTO_H_ 78956115Speterstruct setresgid_args { 79056115Speter gid_t rgid; 79156115Speter gid_t egid; 79256115Speter gid_t sgid; 79356115Speter}; 79456115Speter#endif 79556115Speter/* ARGSUSED */ 79656115Speterint 79756115Spetersetresgid(p, uap) 79856115Speter register struct proc *p; 79956115Speter struct setresgid_args *uap; 80056115Speter{ 80156115Speter register struct pcred *pc = p->p_cred; 80256115Speter register gid_t rgid, egid, sgid; 80356115Speter int error; 80456115Speter 80556115Speter rgid = uap->rgid; 80656115Speter egid = uap->egid; 80756115Speter sgid = uap->sgid; 80856115Speter if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid && 80956115Speter rgid != pc->pc_ucred->cr_groups[0]) || 81056115Speter (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid && 81156115Speter egid != pc->pc_ucred->cr_groups[0]) || 81256115Speter (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && 81356115Speter sgid != pc->pc_ucred->cr_groups[0])) && 81456115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 81556115Speter return (error); 81656115Speter 81756115Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 81856115Speter pc->pc_ucred = crcopy(pc->pc_ucred); 81956115Speter pc->pc_ucred->cr_groups[0] = egid; 82056115Speter setsugid(p); 82156115Speter } 82256115Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 82356115Speter pc->p_rgid = rgid; 82456115Speter setsugid(p); 82556115Speter } 82656115Speter if (sgid != (gid_t)-1 && pc->p_svgid != sgid) { 82756115Speter pc->p_svgid = sgid; 82856115Speter setsugid(p); 82956115Speter } 83056115Speter return (0); 83156115Speter} 83256115Speter 83356115Speter#ifndef _SYS_SYSPROTO_H_ 83456115Speterstruct getresuid_args { 83556115Speter uid_t *ruid; 83656115Speter uid_t *euid; 83756115Speter uid_t *suid; 83856115Speter}; 83956115Speter#endif 84056115Speter/* ARGSUSED */ 84156115Speterint 84256115Spetergetresuid(p, uap) 84356115Speter register struct proc *p; 84456115Speter struct getresuid_args *uap; 84556115Speter{ 84656115Speter struct pcred *pc = p->p_cred; 84756115Speter int error1 = 0, error2 = 0, error3 = 0; 84856115Speter 84956115Speter if (uap->ruid) 85056115Speter error1 = copyout((caddr_t)&pc->p_ruid, 85156115Speter (caddr_t)uap->ruid, sizeof(pc->p_ruid)); 85256115Speter if (uap->euid) 85356115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid, 85456115Speter (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid)); 85556115Speter if (uap->suid) 85656115Speter error3 = copyout((caddr_t)&pc->p_svuid, 85756115Speter (caddr_t)uap->suid, sizeof(pc->p_svuid)); 85856115Speter return error1 ? error1 : (error2 ? error2 : error3); 85956115Speter} 86056115Speter 86156115Speter#ifndef _SYS_SYSPROTO_H_ 86256115Speterstruct getresgid_args { 86356115Speter gid_t *rgid; 86456115Speter gid_t *egid; 86556115Speter gid_t *sgid; 86656115Speter}; 86756115Speter#endif 86856115Speter/* ARGSUSED */ 86956115Speterint 87056115Spetergetresgid(p, uap) 87156115Speter register struct proc *p; 87256115Speter struct getresgid_args *uap; 87356115Speter{ 87456115Speter struct pcred *pc = p->p_cred; 87556115Speter int error1 = 0, error2 = 0, error3 = 0; 87656115Speter 87756115Speter if (uap->rgid) 87856115Speter error1 = copyout((caddr_t)&pc->p_rgid, 87956115Speter (caddr_t)uap->rgid, sizeof(pc->p_rgid)); 88056115Speter if (uap->egid) 88156115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0], 88256115Speter (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0])); 88356115Speter if (uap->sgid) 88456115Speter error3 = copyout((caddr_t)&pc->p_svgid, 88556115Speter (caddr_t)uap->sgid, sizeof(pc->p_svgid)); 88656115Speter return error1 ? error1 : (error2 ? error2 : error3); 88756115Speter} 88856115Speter 88956115Speter 89056115Speter#ifndef _SYS_SYSPROTO_H_ 89124453Speterstruct issetugid_args { 89224453Speter int dummy; 89324453Speter}; 89424453Speter#endif 89524453Speter/* ARGSUSED */ 89624453Speterint 89730994Sphkissetugid(p, uap) 89824453Speter register struct proc *p; 89924453Speter struct issetugid_args *uap; 90024453Speter{ 90124453Speter /* 90224453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 90324453Speter * we use P_SUGID because we consider changing the owners as 90424453Speter * "tainting" as well. 90524453Speter * This is significant for procs that start as root and "become" 90624453Speter * a user without an exec - programs cannot know *everything* 90724453Speter * that libc *might* have put in their data segment. 90824453Speter */ 90960216Speter p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 91024453Speter return (0); 91124453Speter} 91224453Speter 9131541Srgrimes/* 9141541Srgrimes * Check if gid is a member of the group set. 9151541Srgrimes */ 9161549Srgrimesint 9171541Srgrimesgroupmember(gid, cred) 9181541Srgrimes gid_t gid; 9191541Srgrimes register struct ucred *cred; 9201541Srgrimes{ 9211541Srgrimes register gid_t *gp; 9221541Srgrimes gid_t *egp; 9231541Srgrimes 9241541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 9251541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 9261541Srgrimes if (*gp == gid) 9271541Srgrimes return (1); 9281541Srgrimes return (0); 9291541Srgrimes} 9301541Srgrimes 93161287Srwatsonstatic int suser_permitted = 1; 93261287Srwatson 93361287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 93461287Srwatson "processes with uid 0 have privilege"); 93561287Srwatson 9361541Srgrimes/* 9371541Srgrimes * Test whether the specified credentials imply "super-user" 9381541Srgrimes * privilege; if so, and we have accounting info, set the flag 9391541Srgrimes * indicating use of super-powers. 9401541Srgrimes * Returns 0 or error. 9411541Srgrimes */ 9421549Srgrimesint 94346112Sphksuser(p) 94465237Srwatson const struct proc *p; 94546112Sphk{ 94646155Sphk return suser_xxx(0, p, 0); 94746112Sphk} 94846112Sphk 94946112Sphkint 95046155Sphksuser_xxx(cred, proc, flag) 95165237Srwatson const struct ucred *cred; 95265237Srwatson const struct proc *proc; 95346155Sphk int flag; 9541541Srgrimes{ 95561282Srwatson if (!suser_permitted) 95661282Srwatson return (EPERM); 95746155Sphk if (!cred && !proc) { 95846155Sphk printf("suser_xxx(): THINK!\n"); 95946155Sphk return (EPERM); 9601541Srgrimes } 96146155Sphk if (!cred) 96246155Sphk cred = proc->p_ucred; 96346155Sphk if (cred->cr_uid != 0) 96446155Sphk return (EPERM); 96546155Sphk if (proc && proc->p_prison && !(flag & PRISON_ROOT)) 96646155Sphk return (EPERM); 96746155Sphk return (0); 9681541Srgrimes} 9691541Srgrimes 97065237Srwatsonstatic int 97165237Srwatsonp_cansee(const struct proc *p1, const struct proc *p2, int *privused) 97265237Srwatson{ 97353518Sphk 97465237Srwatson if (privused != NULL) 97565237Srwatson *privused = 0; 97665237Srwatson 97765237Srwatson if (!PRISON_CHECK(p1, p2)) 97865237Srwatson return (ESRCH); 97965237Srwatson 98065293Srwatson if (!ps_showallprocs && p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) { 98165293Srwatson if (suser_xxx(NULL, p1, PRISON_ROOT) == 0) { 98265293Srwatson if (privused != NULL) 98365293Srwatson *privused = 1; 98465293Srwatson return (0); 98565293Srwatson } 98665237Srwatson return (ESRCH); 98765293Srwatson } 98865237Srwatson 98965237Srwatson return (0); 99065237Srwatson} 99165237Srwatson 99265237Srwatsonstatic int 99365237Srwatsonp_cankill(const struct proc *p1, const struct proc *p2, int *privused) 99453518Sphk{ 99553518Sphk 99665237Srwatson if (privused != NULL) 99765237Srwatson *privused = 0; 99865237Srwatson 99953518Sphk if (p1 == p2) 100053518Sphk return (0); 100165237Srwatson 100253518Sphk if (!PRISON_CHECK(p1, p2)) 100353518Sphk return (ESRCH); 100465237Srwatson 100553518Sphk if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 100653518Sphk return (0); 100753518Sphk if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 100853518Sphk return (0); 100965237Srwatson /* 101065237Srwatson * XXX should a process be able to affect another process 101165237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 101265237Srwatson */ 101353518Sphk if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 101453518Sphk return (0); 101553518Sphk if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 101653518Sphk return (0); 101765237Srwatson 101865237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 101965237Srwatson if (privused != NULL) 102065237Srwatson *privused = 1; 102153518Sphk return (0); 102265237Srwatson } 102365237Srwatson 102465237Srwatson#ifdef CAPABILITIES 102565237Srwatson if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) { 102665237Srwatson if (privused != NULL) 102765237Srwatson *privused = 1; 102865237Srwatson return (0); 102965237Srwatson } 103065237Srwatson#endif 103165237Srwatson 103253518Sphk return (EPERM); 103353518Sphk} 103453518Sphk 103565237Srwatsonstatic int 103665237Srwatsonp_cansched(const struct proc *p1, const struct proc *p2, int *privused) 103765237Srwatson{ 103865237Srwatson 103965237Srwatson if (privused != NULL) 104065237Srwatson *privused = 0; 104165237Srwatson 104265237Srwatson if (p1 == p2) 104365237Srwatson return (0); 104465237Srwatson 104565237Srwatson if (!PRISON_CHECK(p1, p2)) 104665237Srwatson return (ESRCH); 104765237Srwatson 104865237Srwatson if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 104965237Srwatson return (0); 105065237Srwatson if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 105165237Srwatson return (0); 105265237Srwatson /* 105365237Srwatson * XXX should a process be able to affect another process 105465237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 105565237Srwatson */ 105665237Srwatson if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 105765237Srwatson return (0); 105865237Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 105965237Srwatson return (0); 106065237Srwatson 106165237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 106265237Srwatson if (privused != NULL) 106365237Srwatson *privused = 1; 106465237Srwatson return (0); 106565237Srwatson } 106665237Srwatson 106765237Srwatson#ifdef CAPABILITIES 106865237Srwatson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { 106965237Srwatson if (privused != NULL) 107065237Srwatson *privused = 1; 107165237Srwatson return (0); 107265237Srwatson } 107365237Srwatson#endif 107465237Srwatson 107565237Srwatson return (EPERM); 107665237Srwatson} 107765237Srwatson 107865237Srwatsonstatic int 107965237Srwatsonp_candebug(const struct proc *p1, const struct proc *p2, int *privused) 108065237Srwatson{ 108165237Srwatson int error; 108265237Srwatson 108365237Srwatson if (privused != NULL) 108465237Srwatson *privused = 0; 108565237Srwatson 108665237Srwatson /* XXX it is authorized, but semantics don't permit it */ 108765237Srwatson if (p1 == p2) 108865237Srwatson return (0); 108965237Srwatson 109065237Srwatson if (!PRISON_CHECK(p1, p2)) 109165237Srwatson return (ESRCH); 109265237Srwatson 109365237Srwatson /* not owned by you, has done setuid (unless you're root) */ 109465237Srwatson /* add a CAP_SYS_PTRACE here? */ 109567999Srwatson if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid || 109667999Srwatson p1->p_cred->p_ruid != p2->p_cred->p_ruid || 109768591Srwatson p1->p_cred->p_svuid != p2->p_cred->p_ruid || 109867999Srwatson p2->p_flag & P_SUGID) { 109965237Srwatson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 110065237Srwatson return (error); 110165237Srwatson if (privused != NULL) 110265237Srwatson *privused = 1; 110365237Srwatson } 110465237Srwatson 110565237Srwatson /* can't trace init when securelevel > 0 */ 110665237Srwatson if (securelevel > 0 && p2->p_pid == 1) 110765237Srwatson return (EPERM); 110865237Srwatson 110965237Srwatson return (0); 111065237Srwatson} 111165237Srwatson 111265237Srwatsonint 111365237Srwatsonp_can(const struct proc *p1, const struct proc *p2, int operation, 111465237Srwatson int *privused) 111565237Srwatson{ 111665237Srwatson 111765237Srwatson switch(operation) { 111865237Srwatson case P_CAN_SEE: 111965237Srwatson return (p_cansee(p1, p2, privused)); 112065237Srwatson 112165237Srwatson case P_CAN_KILL: 112265237Srwatson return (p_cankill(p1, p2, privused)); 112365237Srwatson 112465237Srwatson case P_CAN_SCHED: 112565237Srwatson return (p_cansched(p1, p2, privused)); 112665237Srwatson 112765237Srwatson case P_CAN_DEBUG: 112865237Srwatson return (p_candebug(p1, p2, privused)); 112965237Srwatson 113065237Srwatson default: 113165237Srwatson panic("p_can: invalid operation"); 113265237Srwatson } 113365237Srwatson} 113465237Srwatson 113565237Srwatson 113653518Sphk/* 11371541Srgrimes * Allocate a zeroed cred structure. 11381541Srgrimes */ 11391541Srgrimesstruct ucred * 11401541Srgrimescrget() 11411541Srgrimes{ 11421541Srgrimes register struct ucred *cr; 11431541Srgrimes 114469239Salfred MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 11451541Srgrimes cr->cr_ref = 1; 114669239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 11471541Srgrimes return (cr); 11481541Srgrimes} 11491541Srgrimes 11501541Srgrimes/* 115169401Salfred * Claim another referernce to a ucred structure 115269401Salfred */ 115369401Salfredvoid 115469401Salfredcrhold(cr) 115569401Salfred struct ucred *cr; 115669401Salfred{ 115769401Salfred 115869401Salfred mtx_enter(&cr->cr_mtx, MTX_DEF); 115969401Salfred cr->cr_ref++; 116069401Salfred mtx_exit(&(cr)->cr_mtx, MTX_DEF); 116169401Salfred} 116269401Salfred 116369401Salfred 116469401Salfred/* 11651541Srgrimes * Free a cred structure. 11661541Srgrimes * Throws away space when ref count gets to 0. 11671541Srgrimes */ 11681549Srgrimesvoid 11691541Srgrimescrfree(cr) 11701541Srgrimes struct ucred *cr; 11711541Srgrimes{ 117269239Salfred 117369239Salfred mtx_enter(&cr->cr_mtx, MTX_DEF); 117465495Struckman if (--cr->cr_ref == 0) { 117569239Salfred mtx_destroy(&cr->cr_mtx); 117665495Struckman /* 117765495Struckman * Some callers of crget(), such as nfs_statfs(), 117865495Struckman * allocate a temporary credential, but don't 117965495Struckman * allocate a uidinfo structure. 118065495Struckman */ 118165495Struckman if (cr->cr_uidinfo != NULL) 118265495Struckman uifree(cr->cr_uidinfo); 11831541Srgrimes FREE((caddr_t)cr, M_CRED); 118469239Salfred } else { 118569239Salfred mtx_exit(&cr->cr_mtx, MTX_DEF); 118665495Struckman } 11871541Srgrimes} 11881541Srgrimes 11891541Srgrimes/* 11901541Srgrimes * Copy cred structure to a new one and free the old one. 11911541Srgrimes */ 11921541Srgrimesstruct ucred * 11931541Srgrimescrcopy(cr) 11941541Srgrimes struct ucred *cr; 11951541Srgrimes{ 11961541Srgrimes struct ucred *newcr; 11971541Srgrimes 119869239Salfred mtx_enter(&cr->cr_mtx, MTX_DEF); 119969239Salfred if (cr->cr_ref == 1) { 120069239Salfred mtx_exit(&cr->cr_mtx, MTX_DEF); 12011541Srgrimes return (cr); 120269239Salfred } 120369239Salfred mtx_exit(&cr->cr_mtx, MTX_DEF); 120469239Salfred newcr = crdup(cr); 12051541Srgrimes crfree(cr); 12061541Srgrimes return (newcr); 12071541Srgrimes} 12081541Srgrimes 12091541Srgrimes/* 12101541Srgrimes * Dup cred struct to a new held one. 12111541Srgrimes */ 12121541Srgrimesstruct ucred * 12131541Srgrimescrdup(cr) 12141541Srgrimes struct ucred *cr; 12151541Srgrimes{ 12161541Srgrimes struct ucred *newcr; 12171541Srgrimes 121869239Salfred MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 12191541Srgrimes *newcr = *cr; 122069239Salfred mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 122165495Struckman uihold(newcr->cr_uidinfo); 12221541Srgrimes newcr->cr_ref = 1; 12231541Srgrimes return (newcr); 12241541Srgrimes} 12251541Srgrimes 12261541Srgrimes/* 12271541Srgrimes * Get login name, if available. 12281541Srgrimes */ 122912221Sbde#ifndef _SYS_SYSPROTO_H_ 12301541Srgrimesstruct getlogin_args { 12311541Srgrimes char *namebuf; 12321541Srgrimes u_int namelen; 12331541Srgrimes}; 123412221Sbde#endif 12351541Srgrimes/* ARGSUSED */ 12361549Srgrimesint 123730994Sphkgetlogin(p, uap) 12381541Srgrimes struct proc *p; 12391541Srgrimes struct getlogin_args *uap; 12401541Srgrimes{ 12411541Srgrimes 124223358Sache if (uap->namelen > MAXLOGNAME) 124323359Sache uap->namelen = MAXLOGNAME; 12441541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 12451541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 12461541Srgrimes} 12471541Srgrimes 12481541Srgrimes/* 12491541Srgrimes * Set login name. 12501541Srgrimes */ 125112221Sbde#ifndef _SYS_SYSPROTO_H_ 12521541Srgrimesstruct setlogin_args { 12531541Srgrimes char *namebuf; 12541541Srgrimes}; 125512221Sbde#endif 12561541Srgrimes/* ARGSUSED */ 12571549Srgrimesint 125830994Sphksetlogin(p, uap) 12591541Srgrimes struct proc *p; 12601541Srgrimes struct setlogin_args *uap; 12611541Srgrimes{ 12621541Srgrimes int error; 126323330Sache char logintmp[MAXLOGNAME]; 12641541Srgrimes 126546155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 12661541Srgrimes return (error); 126722522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 126836845Sdfr sizeof(logintmp), (size_t *)0); 12691541Srgrimes if (error == ENAMETOOLONG) 12701541Srgrimes error = EINVAL; 127122522Sdavidn else if (!error) 127222522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 127323330Sache sizeof(logintmp)); 12741541Srgrimes return (error); 12751541Srgrimes} 127631891Ssef 127731891Ssefvoid 127831891Ssefsetsugid(p) 127955338Sphk struct proc *p; 128031891Ssef{ 128131891Ssef p->p_flag |= P_SUGID; 128255707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 128331891Ssef p->p_stops = 0; 128431891Ssef} 128565495Struckman 128665495Struckman/* 128765495Struckman * Helper function to change the effective uid of a process 128865495Struckman */ 128965495Struckmanvoid 129065495Struckmanchange_euid(p, euid) 129165495Struckman struct proc *p; 129265495Struckman uid_t euid; 129365495Struckman{ 129465495Struckman struct pcred *pc; 129565495Struckman struct uidinfo *uip; 129665495Struckman 129765495Struckman pc = p->p_cred; 129865495Struckman /* 129965495Struckman * crcopy is essentially a NOP if ucred has a reference count 130065495Struckman * of 1, which is true if it has already been copied. 130165495Struckman */ 130265495Struckman pc->pc_ucred = crcopy(pc->pc_ucred); 130365495Struckman uip = pc->pc_ucred->cr_uidinfo; 130465495Struckman pc->pc_ucred->cr_uid = euid; 130565495Struckman pc->pc_ucred->cr_uidinfo = uifind(euid); 130665495Struckman uifree(uip); 130765495Struckman} 130865495Struckman 130965495Struckman/* 131065495Struckman * Helper function to change the real uid of a process 131165495Struckman * 131265495Struckman * The per-uid process count for this process is transfered from 131365495Struckman * the old uid to the new uid. 131465495Struckman */ 131567629Sgallatinvoid 131665495Struckmanchange_ruid(p, ruid) 131765495Struckman struct proc *p; 131865495Struckman uid_t ruid; 131965495Struckman{ 132065495Struckman struct pcred *pc; 132165495Struckman struct uidinfo *uip; 132265495Struckman 132365495Struckman pc = p->p_cred; 132465495Struckman (void)chgproccnt(pc->p_uidinfo, -1, 0); 132565495Struckman uip = pc->p_uidinfo; 132665495Struckman /* It is assumed that pcred is not shared between processes */ 132765495Struckman pc->p_ruid = ruid; 132865495Struckman pc->p_uidinfo = uifind(ruid); 132965495Struckman (void)chgproccnt(pc->p_uidinfo, 1, 0); 133065495Struckman uifree(uip); 133165495Struckman} 1332