kern_prot.c revision 74728
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 74728 2001-03-24 04:00:01Z jhb $ 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> 5972786Srwatson#include <sys/jail.h> 601541Srgrimes 6130354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6230354Sphk 6312221Sbde#ifndef _SYS_SYSPROTO_H_ 6411332Sswallacestruct getpid_args { 651541Srgrimes int dummy; 661541Srgrimes}; 6712221Sbde#endif 681541Srgrimes 6958717Sdillon/* 7070317Sjake * getpid - MP SAFE 7158717Sdillon */ 7270317Sjake 731541Srgrimes/* ARGSUSED */ 741549Srgrimesint 7530994Sphkgetpid(p, uap) 761541Srgrimes struct proc *p; 7711332Sswallace struct getpid_args *uap; 781541Srgrimes{ 791541Srgrimes 8030994Sphk p->p_retval[0] = p->p_pid; 811541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8274728Sjhb PROC_LOCK(p); 8330994Sphk p->p_retval[1] = p->p_pptr->p_pid; 8474728Sjhb PROC_UNLOCK(p); 851541Srgrimes#endif 861541Srgrimes return (0); 871541Srgrimes} 881541Srgrimes 8970317Sjake/* 9070317Sjake * getppid - MP SAFE 9170317Sjake */ 9270317Sjake 9312221Sbde#ifndef _SYS_SYSPROTO_H_ 9411332Sswallacestruct getppid_args { 9511332Sswallace int dummy; 9611332Sswallace}; 9712221Sbde#endif 981541Srgrimes/* ARGSUSED */ 991549Srgrimesint 10030994Sphkgetppid(p, uap) 1011541Srgrimes struct proc *p; 10211332Sswallace struct getppid_args *uap; 1031541Srgrimes{ 1041541Srgrimes 10574728Sjhb PROC_LOCK(p); 10630994Sphk p->p_retval[0] = p->p_pptr->p_pid; 10774728Sjhb PROC_UNLOCK(p); 1081541Srgrimes return (0); 1091541Srgrimes} 1101541Srgrimes 11158717Sdillon/* 11258717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter 11358717Sdillon * 11458717Sdillon * MP SAFE 11558717Sdillon */ 11612221Sbde#ifndef _SYS_SYSPROTO_H_ 11711332Sswallacestruct getpgrp_args { 11811332Sswallace int dummy; 11911332Sswallace}; 12012221Sbde#endif 12111332Sswallace 1221549Srgrimesint 12330994Sphkgetpgrp(p, uap) 1241541Srgrimes struct proc *p; 12511332Sswallace struct getpgrp_args *uap; 1261541Srgrimes{ 1271541Srgrimes 12830994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1291541Srgrimes return (0); 1301541Srgrimes} 1311541Srgrimes 13228401Speter/* Get an arbitary pid's process group id */ 13312221Sbde#ifndef _SYS_SYSPROTO_H_ 13428401Speterstruct getpgid_args { 13528401Speter pid_t pid; 13628401Speter}; 13728401Speter#endif 13828401Speter 13928401Speterint 14030994Sphkgetpgid(p, uap) 14128401Speter struct proc *p; 14228401Speter struct getpgid_args *uap; 14328401Speter{ 14441726Struckman struct proc *pt; 14541726Struckman 14641726Struckman pt = p; 14728401Speter if (uap->pid == 0) 14828401Speter goto found; 14928401Speter 15041726Struckman if ((pt = pfind(uap->pid)) == 0) 15128401Speter return ESRCH; 15228401Speterfound: 15341726Struckman p->p_retval[0] = pt->p_pgrp->pg_id; 15428401Speter return 0; 15528401Speter} 15628401Speter 15728401Speter/* 15828401Speter * Get an arbitary pid's session id. 15928401Speter */ 16028401Speter#ifndef _SYS_SYSPROTO_H_ 16128401Speterstruct getsid_args { 16228401Speter pid_t pid; 16328401Speter}; 16428401Speter#endif 16528401Speter 16628401Speterint 16730994Sphkgetsid(p, uap) 16828401Speter struct proc *p; 16928401Speter struct getsid_args *uap; 17028401Speter{ 17141726Struckman struct proc *pt; 17241726Struckman 17341726Struckman pt = p; 17428401Speter if (uap->pid == 0) 17528401Speter goto found; 17628401Speter 17771002Sben if ((pt = pfind(uap->pid)) == 0) 17828401Speter return ESRCH; 17928401Speterfound: 18041726Struckman p->p_retval[0] = pt->p_session->s_sid; 18128401Speter return 0; 18228401Speter} 18328401Speter 18428401Speter 18558941Sdillon/* 18658941Sdillon * getuid() - MP SAFE 18758941Sdillon */ 18828401Speter#ifndef _SYS_SYSPROTO_H_ 18911332Sswallacestruct getuid_args { 19011332Sswallace int dummy; 19111332Sswallace}; 19212221Sbde#endif 19311332Sswallace 1941541Srgrimes/* ARGSUSED */ 1951549Srgrimesint 19630994Sphkgetuid(p, uap) 1971541Srgrimes struct proc *p; 19811332Sswallace struct getuid_args *uap; 1991541Srgrimes{ 2001541Srgrimes 20130994Sphk p->p_retval[0] = p->p_cred->p_ruid; 2021541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 20330994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 2041541Srgrimes#endif 2051541Srgrimes return (0); 2061541Srgrimes} 2071541Srgrimes 20858941Sdillon/* 20958941Sdillon * geteuid() - MP SAFE 21058941Sdillon */ 21112221Sbde#ifndef _SYS_SYSPROTO_H_ 21211332Sswallacestruct geteuid_args { 21311332Sswallace int dummy; 21411332Sswallace}; 21512221Sbde#endif 21611332Sswallace 2171541Srgrimes/* ARGSUSED */ 2181549Srgrimesint 21930994Sphkgeteuid(p, uap) 2201541Srgrimes struct proc *p; 22111332Sswallace struct geteuid_args *uap; 2221541Srgrimes{ 2231541Srgrimes 22430994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2251541Srgrimes return (0); 2261541Srgrimes} 2271541Srgrimes 22858941Sdillon/* 22958941Sdillon * getgid() - MP SAFE 23058941Sdillon */ 23112221Sbde#ifndef _SYS_SYSPROTO_H_ 23211332Sswallacestruct getgid_args { 23311332Sswallace int dummy; 23411332Sswallace}; 23512221Sbde#endif 23611332Sswallace 2371541Srgrimes/* ARGSUSED */ 2381549Srgrimesint 23930994Sphkgetgid(p, uap) 2401541Srgrimes struct proc *p; 24111332Sswallace struct getgid_args *uap; 2421541Srgrimes{ 2431541Srgrimes 24430994Sphk p->p_retval[0] = p->p_cred->p_rgid; 2451541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 24630994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2471541Srgrimes#endif 2481541Srgrimes return (0); 2491541Srgrimes} 2501541Srgrimes 2511541Srgrimes/* 2521541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2531541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2541541Srgrimes * correctly in a library function. 2551541Srgrimes */ 25612221Sbde#ifndef _SYS_SYSPROTO_H_ 25711332Sswallacestruct getegid_args { 25811332Sswallace int dummy; 25911332Sswallace}; 26012221Sbde#endif 26111332Sswallace 2621541Srgrimes/* ARGSUSED */ 2631549Srgrimesint 26430994Sphkgetegid(p, uap) 2651541Srgrimes struct proc *p; 26611332Sswallace struct getegid_args *uap; 2671541Srgrimes{ 2681541Srgrimes 26930994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2701541Srgrimes return (0); 2711541Srgrimes} 2721541Srgrimes 27312221Sbde#ifndef _SYS_SYSPROTO_H_ 2741541Srgrimesstruct getgroups_args { 2751541Srgrimes u_int gidsetsize; 2761541Srgrimes gid_t *gidset; 2771541Srgrimes}; 27812221Sbde#endif 2791549Srgrimesint 28030994Sphkgetgroups(p, uap) 2811541Srgrimes struct proc *p; 2821541Srgrimes register struct getgroups_args *uap; 2831541Srgrimes{ 2841541Srgrimes register struct pcred *pc = p->p_cred; 2851541Srgrimes register u_int ngrp; 2861541Srgrimes int error; 2871541Srgrimes 2881541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 28930994Sphk p->p_retval[0] = pc->pc_ucred->cr_ngroups; 2901541Srgrimes return (0); 2911541Srgrimes } 2921541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 2931541Srgrimes return (EINVAL); 2941541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 2953098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 2963098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 2971541Srgrimes return (error); 29830994Sphk p->p_retval[0] = ngrp; 2991541Srgrimes return (0); 3001541Srgrimes} 3011541Srgrimes 30212221Sbde#ifndef _SYS_SYSPROTO_H_ 30312207Sbdestruct setsid_args { 30411332Sswallace int dummy; 30511332Sswallace}; 30612221Sbde#endif 30711332Sswallace 3081541Srgrimes/* ARGSUSED */ 3091549Srgrimesint 31030994Sphksetsid(p, uap) 3111541Srgrimes register struct proc *p; 31212207Sbde struct setsid_args *uap; 3131541Srgrimes{ 3141541Srgrimes 3151541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 3161541Srgrimes return (EPERM); 3171541Srgrimes } else { 3181541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 31930994Sphk p->p_retval[0] = p->p_pid; 3201541Srgrimes return (0); 3211541Srgrimes } 3221541Srgrimes} 3231541Srgrimes 3241541Srgrimes/* 3251541Srgrimes * set process group (setpgid/old setpgrp) 3261541Srgrimes * 3271541Srgrimes * caller does setpgid(targpid, targpgid) 3281541Srgrimes * 3291541Srgrimes * pid must be caller or child of caller (ESRCH) 3301541Srgrimes * if a child 3311541Srgrimes * pid must be in same session (EPERM) 3321541Srgrimes * pid can't have done an exec (EACCES) 3331541Srgrimes * if pgid != pid 3341541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3351541Srgrimes * pid must not be session leader (EPERM) 3361541Srgrimes */ 33712221Sbde#ifndef _SYS_SYSPROTO_H_ 3381541Srgrimesstruct setpgid_args { 3391541Srgrimes int pid; /* target process id */ 3401541Srgrimes int pgid; /* target pgrp id */ 3411541Srgrimes}; 34212221Sbde#endif 3431541Srgrimes/* ARGSUSED */ 3441549Srgrimesint 34530994Sphksetpgid(curp, uap) 3461541Srgrimes struct proc *curp; 3471541Srgrimes register struct setpgid_args *uap; 3481541Srgrimes{ 3491541Srgrimes register struct proc *targp; /* target process */ 3501541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 3511541Srgrimes 35220677Sbde if (uap->pgid < 0) 35320677Sbde return (EINVAL); 3541541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 3551541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 3561541Srgrimes return (ESRCH); 35715985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 3581541Srgrimes return (EPERM); 3591541Srgrimes if (targp->p_flag & P_EXEC) 3601541Srgrimes return (EACCES); 3611541Srgrimes } else 3621541Srgrimes targp = curp; 3631541Srgrimes if (SESS_LEADER(targp)) 3641541Srgrimes return (EPERM); 3651541Srgrimes if (uap->pgid == 0) 3661541Srgrimes uap->pgid = targp->p_pid; 3671541Srgrimes else if (uap->pgid != targp->p_pid) 3681541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 3691541Srgrimes pgrp->pg_session != curp->p_session) 3701541Srgrimes return (EPERM); 3711541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 3721541Srgrimes} 3731541Srgrimes 37424448Speter/* 37524448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 37672093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 37724448Speter * case of "appropriate privilege". Once the rules are expanded out, this 37824448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 37924448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 38024448Speter * does not set the saved id - this is dangerous for traditional BSD 38124448Speter * programs. For this reason, we *really* do not want to set 38224448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 38324448Speter */ 38424448Speter#define POSIX_APPENDIX_B_4_2_2 38524448Speter 38612221Sbde#ifndef _SYS_SYSPROTO_H_ 3871541Srgrimesstruct setuid_args { 3881541Srgrimes uid_t uid; 3891541Srgrimes}; 39012221Sbde#endif 3911541Srgrimes/* ARGSUSED */ 3921549Srgrimesint 39330994Sphksetuid(p, uap) 3941541Srgrimes struct proc *p; 3951541Srgrimes struct setuid_args *uap; 3961541Srgrimes{ 3971541Srgrimes register struct pcred *pc = p->p_cred; 3981541Srgrimes register uid_t uid; 3991541Srgrimes int error; 4001541Srgrimes 40124448Speter /* 40224448Speter * See if we have "permission" by POSIX 1003.1 rules. 40324448Speter * 40424448Speter * Note that setuid(geteuid()) is a special case of 40524448Speter * "appropriate privileges" in appendix B.4.2.2. We need 40672093Sasmodai * to use this clause to be compatible with traditional BSD 40724448Speter * semantics. Basically, it means that "setuid(xx)" sets all 40824448Speter * three id's (assuming you have privs). 40924448Speter * 41024448Speter * Notes on the logic. We do things in three steps. 41124448Speter * 1: We determine if the euid is going to change, and do EPERM 41224448Speter * right away. We unconditionally change the euid later if this 41324448Speter * test is satisfied, simplifying that part of the logic. 41424448Speter * 2: We determine if the real and/or saved uid's are going to 41524448Speter * change. Determined by compile options. 41624448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 41724448Speter */ 4181541Srgrimes uid = uap->uid; 41924448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 42017994Sache#ifdef _POSIX_SAVED_IDS 42124448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 42217994Sache#endif 42324448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 42424448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 42524448Speter#endif 42646155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4271541Srgrimes return (error); 42824448Speter 42924448Speter#ifdef _POSIX_SAVED_IDS 4301541Srgrimes /* 43124448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 43224448Speter * If so, we are changing the real uid and/or saved uid. 4331541Srgrimes */ 43417994Sache if ( 43524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 43624448Speter uid == pc->pc_ucred->cr_uid || 43717994Sache#endif 43846155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 43917994Sache#endif 44024448Speter { 44124448Speter /* 44265495Struckman * Set the real uid and transfer proc count to new user. 44324448Speter */ 44424448Speter if (uid != pc->p_ruid) { 44565495Struckman change_ruid(p, uid); 44665495Struckman setsugid(p); 44724448Speter } 44824448Speter /* 44924448Speter * Set saved uid 45024448Speter * 45124448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 45224448Speter * the security of seteuid() depends on it. B.4.2.2 says it 45324448Speter * is important that we should do this. 45424448Speter */ 45524448Speter if (pc->p_svuid != uid) { 45624448Speter pc->p_svuid = uid; 45731891Ssef setsugid(p); 45824448Speter } 4598141Sache } 46024448Speter 46124448Speter /* 46224448Speter * In all permitted cases, we are changing the euid. 46324448Speter * Copy credentials so other references do not see our changes. 46424448Speter */ 46524448Speter if (pc->pc_ucred->cr_uid != uid) { 46665495Struckman change_euid(p, uid); 46731891Ssef setsugid(p); 46824448Speter } 4691541Srgrimes return (0); 4701541Srgrimes} 4711541Srgrimes 47212221Sbde#ifndef _SYS_SYSPROTO_H_ 4731541Srgrimesstruct seteuid_args { 4741541Srgrimes uid_t euid; 4751541Srgrimes}; 47612221Sbde#endif 4771541Srgrimes/* ARGSUSED */ 4781549Srgrimesint 47930994Sphkseteuid(p, uap) 4801541Srgrimes struct proc *p; 4811541Srgrimes struct seteuid_args *uap; 4821541Srgrimes{ 4831541Srgrimes register struct pcred *pc = p->p_cred; 4841541Srgrimes register uid_t euid; 4851541Srgrimes int error; 4861541Srgrimes 4871541Srgrimes euid = uap->euid; 48824449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 48924449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 49046155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 4911541Srgrimes return (error); 4921541Srgrimes /* 4931541Srgrimes * Everything's okay, do it. Copy credentials so other references do 4941541Srgrimes * not see our changes. 4951541Srgrimes */ 49624449Speter if (pc->pc_ucred->cr_uid != euid) { 49765495Struckman change_euid(p, euid); 49831891Ssef setsugid(p); 49924449Speter } 5001541Srgrimes return (0); 5011541Srgrimes} 5021541Srgrimes 50312221Sbde#ifndef _SYS_SYSPROTO_H_ 5041541Srgrimesstruct setgid_args { 5051541Srgrimes gid_t gid; 5061541Srgrimes}; 50712221Sbde#endif 5081541Srgrimes/* ARGSUSED */ 5091549Srgrimesint 51030994Sphksetgid(p, uap) 5111541Srgrimes struct proc *p; 5121541Srgrimes struct setgid_args *uap; 5131541Srgrimes{ 5141541Srgrimes register struct pcred *pc = p->p_cred; 5151541Srgrimes register gid_t gid; 5161541Srgrimes int error; 5171541Srgrimes 51824448Speter /* 51924448Speter * See if we have "permission" by POSIX 1003.1 rules. 52024448Speter * 52124448Speter * Note that setgid(getegid()) is a special case of 52224448Speter * "appropriate privileges" in appendix B.4.2.2. We need 52372093Sasmodai * to use this clause to be compatible with traditional BSD 52424448Speter * semantics. Basically, it means that "setgid(xx)" sets all 52524448Speter * three id's (assuming you have privs). 52624448Speter * 52724448Speter * For notes on the logic here, see setuid() above. 52824448Speter */ 5291541Srgrimes gid = uap->gid; 53024448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 53117994Sache#ifdef _POSIX_SAVED_IDS 53224448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 53317994Sache#endif 53424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 53524448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 53624448Speter#endif 53746155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 5381541Srgrimes return (error); 53924448Speter 54017994Sache#ifdef _POSIX_SAVED_IDS 54124448Speter /* 54224448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 54324448Speter * If so, we are changing the real uid and saved gid. 54424448Speter */ 54524448Speter if ( 54624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 54724448Speter gid == pc->pc_ucred->cr_groups[0] || 54817994Sache#endif 54946155Sphk suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 55024448Speter#endif 55124448Speter { 55224448Speter /* 55324448Speter * Set real gid 55424448Speter */ 55524448Speter if (pc->p_rgid != gid) { 55624448Speter pc->p_rgid = gid; 55731891Ssef setsugid(p); 55824448Speter } 55924448Speter /* 56024448Speter * Set saved gid 56124448Speter * 56224448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 56324448Speter * the security of setegid() depends on it. B.4.2.2 says it 56424448Speter * is important that we should do this. 56524448Speter */ 56624448Speter if (pc->p_svgid != gid) { 56724448Speter pc->p_svgid = gid; 56831891Ssef setsugid(p); 56924448Speter } 5708141Sache } 57124448Speter /* 57224448Speter * In all cases permitted cases, we are changing the egid. 57324448Speter * Copy credentials so other references do not see our changes. 57424448Speter */ 57524448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 57624448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 57724448Speter pc->pc_ucred->cr_groups[0] = gid; 57831891Ssef setsugid(p); 57924448Speter } 5801541Srgrimes return (0); 5811541Srgrimes} 5821541Srgrimes 58312221Sbde#ifndef _SYS_SYSPROTO_H_ 5841541Srgrimesstruct setegid_args { 5851541Srgrimes gid_t egid; 5861541Srgrimes}; 58712221Sbde#endif 5881541Srgrimes/* ARGSUSED */ 5891549Srgrimesint 59030994Sphksetegid(p, uap) 5911541Srgrimes struct proc *p; 5921541Srgrimes struct setegid_args *uap; 5931541Srgrimes{ 5941541Srgrimes register struct pcred *pc = p->p_cred; 5951541Srgrimes register gid_t egid; 5961541Srgrimes int error; 5971541Srgrimes 5981541Srgrimes egid = uap->egid; 59924449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 60024449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 60146155Sphk (error = suser_xxx(0, p, PRISON_ROOT))) 6021541Srgrimes return (error); 60324449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 60424449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 60524449Speter pc->pc_ucred->cr_groups[0] = egid; 60631891Ssef setsugid(p); 60724449Speter } 6081541Srgrimes return (0); 6091541Srgrimes} 6101541Srgrimes 61112221Sbde#ifndef _SYS_SYSPROTO_H_ 6121541Srgrimesstruct setgroups_args { 6131541Srgrimes u_int gidsetsize; 6141541Srgrimes gid_t *gidset; 6151541Srgrimes}; 61612221Sbde#endif 6171541Srgrimes/* ARGSUSED */ 6181549Srgrimesint 61930994Sphksetgroups(p, uap) 6201541Srgrimes struct proc *p; 6211541Srgrimes struct setgroups_args *uap; 6221541Srgrimes{ 6231541Srgrimes register struct pcred *pc = p->p_cred; 6241541Srgrimes register u_int ngrp; 6251541Srgrimes int error; 6261541Srgrimes 62746155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 6281541Srgrimes return (error); 62912063Sdg ngrp = uap->gidsetsize; 63024447Speter if (ngrp > NGROUPS) 6311541Srgrimes return (EINVAL); 63224447Speter /* 63324447Speter * XXX A little bit lazy here. We could test if anything has 63424447Speter * changed before crcopy() and setting P_SUGID. 63524447Speter */ 6361541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 63724447Speter if (ngrp < 1) { 63824447Speter /* 63924447Speter * setgroups(0, NULL) is a legitimate way of clearing the 64024447Speter * groups vector on non-BSD systems (which generally do not 64124447Speter * have the egid in the groups[0]). We risk security holes 64224447Speter * when running non-BSD software if we do not do the same. 64324447Speter */ 64424447Speter pc->pc_ucred->cr_ngroups = 1; 64524447Speter } else { 64624447Speter if ((error = copyin((caddr_t)uap->gidset, 64724447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 64824447Speter return (error); 64924447Speter pc->pc_ucred->cr_ngroups = ngrp; 65024447Speter } 65131891Ssef setsugid(p); 6521541Srgrimes return (0); 6531541Srgrimes} 6541541Srgrimes 65512221Sbde#ifndef _SYS_SYSPROTO_H_ 6561541Srgrimesstruct setreuid_args { 6579238Sache uid_t ruid; 6589238Sache uid_t euid; 6591541Srgrimes}; 66012221Sbde#endif 6611541Srgrimes/* ARGSUSED */ 6621549Srgrimesint 66330994Sphksetreuid(p, uap) 6641541Srgrimes register struct proc *p; 6651541Srgrimes struct setreuid_args *uap; 6661541Srgrimes{ 6671541Srgrimes register struct pcred *pc = p->p_cred; 6689238Sache register uid_t ruid, euid; 6698135Sache int error; 6701541Srgrimes 6719238Sache ruid = uap->ruid; 6729238Sache euid = uap->euid; 67343311Sdillon if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || 67443311Sdillon (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 67543311Sdillon euid != pc->p_ruid && euid != pc->p_svuid)) && 67646155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 6778135Sache return (error); 6789238Sache 67924450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 68065495Struckman change_euid(p, euid); 68131891Ssef setsugid(p); 68224450Speter } 68324450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 68465495Struckman change_ruid(p, ruid); 68531891Ssef setsugid(p); 6868135Sache } 68724559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 68824559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6898111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 69031891Ssef setsugid(p); 69124450Speter } 6928135Sache return (0); 6931541Srgrimes} 6941541Srgrimes 69512221Sbde#ifndef _SYS_SYSPROTO_H_ 6961541Srgrimesstruct setregid_args { 6979238Sache gid_t rgid; 6989238Sache gid_t egid; 6991541Srgrimes}; 70012221Sbde#endif 7011541Srgrimes/* ARGSUSED */ 7021549Srgrimesint 70330994Sphksetregid(p, uap) 7041541Srgrimes register struct proc *p; 7051541Srgrimes struct setregid_args *uap; 7061541Srgrimes{ 7071541Srgrimes register struct pcred *pc = p->p_cred; 7089238Sache register gid_t rgid, egid; 7098135Sache int error; 7101541Srgrimes 7119238Sache rgid = uap->rgid; 7129238Sache egid = uap->egid; 71343311Sdillon if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || 71443311Sdillon (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 71543311Sdillon egid != pc->p_rgid && egid != pc->p_svgid)) && 71646155Sphk (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 7178135Sache return (error); 7189238Sache 71924450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 72024450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 7219238Sache pc->pc_ucred->cr_groups[0] = egid; 72231891Ssef setsugid(p); 72324450Speter } 72424450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 7259238Sache pc->p_rgid = rgid; 72631891Ssef setsugid(p); 72724450Speter } 72824559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 72924559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7308111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 73131891Ssef setsugid(p); 73224450Speter } 7338135Sache return (0); 7341541Srgrimes} 7351541Srgrimes 73656115Speter/* 73756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 73856115Speter * saved uid is explicit. 73956115Speter */ 74056115Speter 74124453Speter#ifndef _SYS_SYSPROTO_H_ 74256115Speterstruct setresuid_args { 74356115Speter uid_t ruid; 74456115Speter uid_t euid; 74556115Speter uid_t suid; 74656115Speter}; 74756115Speter#endif 74856115Speter/* ARGSUSED */ 74956115Speterint 75056115Spetersetresuid(p, uap) 75156115Speter register struct proc *p; 75256115Speter struct setresuid_args *uap; 75356115Speter{ 75456115Speter register struct pcred *pc = p->p_cred; 75556115Speter register uid_t ruid, euid, suid; 75656115Speter int error; 75756115Speter 75856115Speter ruid = uap->ruid; 75956115Speter euid = uap->euid; 76056115Speter suid = uap->suid; 76156115Speter if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid && 76256115Speter ruid != pc->pc_ucred->cr_uid) || 76356115Speter (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid && 76456115Speter euid != pc->pc_ucred->cr_uid) || 76556115Speter (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid && 76656115Speter suid != pc->pc_ucred->cr_uid)) && 76756115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 76856115Speter return (error); 76956115Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 77065495Struckman change_euid(p, euid); 77156115Speter setsugid(p); 77256115Speter } 77356115Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 77465495Struckman change_ruid(p, ruid); 77556115Speter setsugid(p); 77656115Speter } 77756115Speter if (suid != (uid_t)-1 && pc->p_svuid != suid) { 77856115Speter pc->p_svuid = suid; 77956115Speter setsugid(p); 78056115Speter } 78156115Speter return (0); 78256115Speter} 78356115Speter 78456115Speter/* 78556115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 78656115Speter * saved gid is explicit. 78756115Speter */ 78856115Speter 78956115Speter#ifndef _SYS_SYSPROTO_H_ 79056115Speterstruct setresgid_args { 79156115Speter gid_t rgid; 79256115Speter gid_t egid; 79356115Speter gid_t sgid; 79456115Speter}; 79556115Speter#endif 79656115Speter/* ARGSUSED */ 79756115Speterint 79856115Spetersetresgid(p, uap) 79956115Speter register struct proc *p; 80056115Speter struct setresgid_args *uap; 80156115Speter{ 80256115Speter register struct pcred *pc = p->p_cred; 80356115Speter register gid_t rgid, egid, sgid; 80456115Speter int error; 80556115Speter 80656115Speter rgid = uap->rgid; 80756115Speter egid = uap->egid; 80856115Speter sgid = uap->sgid; 80956115Speter if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid && 81056115Speter rgid != pc->pc_ucred->cr_groups[0]) || 81156115Speter (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid && 81256115Speter egid != pc->pc_ucred->cr_groups[0]) || 81356115Speter (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && 81456115Speter sgid != pc->pc_ucred->cr_groups[0])) && 81556115Speter (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 81656115Speter return (error); 81756115Speter 81856115Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 81956115Speter pc->pc_ucred = crcopy(pc->pc_ucred); 82056115Speter pc->pc_ucred->cr_groups[0] = egid; 82156115Speter setsugid(p); 82256115Speter } 82356115Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 82456115Speter pc->p_rgid = rgid; 82556115Speter setsugid(p); 82656115Speter } 82756115Speter if (sgid != (gid_t)-1 && pc->p_svgid != sgid) { 82856115Speter pc->p_svgid = sgid; 82956115Speter setsugid(p); 83056115Speter } 83156115Speter return (0); 83256115Speter} 83356115Speter 83456115Speter#ifndef _SYS_SYSPROTO_H_ 83556115Speterstruct getresuid_args { 83656115Speter uid_t *ruid; 83756115Speter uid_t *euid; 83856115Speter uid_t *suid; 83956115Speter}; 84056115Speter#endif 84156115Speter/* ARGSUSED */ 84256115Speterint 84356115Spetergetresuid(p, uap) 84456115Speter register struct proc *p; 84556115Speter struct getresuid_args *uap; 84656115Speter{ 84756115Speter struct pcred *pc = p->p_cred; 84856115Speter int error1 = 0, error2 = 0, error3 = 0; 84956115Speter 85056115Speter if (uap->ruid) 85156115Speter error1 = copyout((caddr_t)&pc->p_ruid, 85256115Speter (caddr_t)uap->ruid, sizeof(pc->p_ruid)); 85356115Speter if (uap->euid) 85456115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid, 85556115Speter (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid)); 85656115Speter if (uap->suid) 85756115Speter error3 = copyout((caddr_t)&pc->p_svuid, 85856115Speter (caddr_t)uap->suid, sizeof(pc->p_svuid)); 85956115Speter return error1 ? error1 : (error2 ? error2 : error3); 86056115Speter} 86156115Speter 86256115Speter#ifndef _SYS_SYSPROTO_H_ 86356115Speterstruct getresgid_args { 86456115Speter gid_t *rgid; 86556115Speter gid_t *egid; 86656115Speter gid_t *sgid; 86756115Speter}; 86856115Speter#endif 86956115Speter/* ARGSUSED */ 87056115Speterint 87156115Spetergetresgid(p, uap) 87256115Speter register struct proc *p; 87356115Speter struct getresgid_args *uap; 87456115Speter{ 87556115Speter struct pcred *pc = p->p_cred; 87656115Speter int error1 = 0, error2 = 0, error3 = 0; 87756115Speter 87856115Speter if (uap->rgid) 87956115Speter error1 = copyout((caddr_t)&pc->p_rgid, 88056115Speter (caddr_t)uap->rgid, sizeof(pc->p_rgid)); 88156115Speter if (uap->egid) 88256115Speter error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0], 88356115Speter (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0])); 88456115Speter if (uap->sgid) 88556115Speter error3 = copyout((caddr_t)&pc->p_svgid, 88656115Speter (caddr_t)uap->sgid, sizeof(pc->p_svgid)); 88756115Speter return error1 ? error1 : (error2 ? error2 : error3); 88856115Speter} 88956115Speter 89056115Speter 89156115Speter#ifndef _SYS_SYSPROTO_H_ 89224453Speterstruct issetugid_args { 89324453Speter int dummy; 89424453Speter}; 89524453Speter#endif 89624453Speter/* ARGSUSED */ 89724453Speterint 89830994Sphkissetugid(p, uap) 89924453Speter register struct proc *p; 90024453Speter struct issetugid_args *uap; 90124453Speter{ 90224453Speter /* 90324453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 90424453Speter * we use P_SUGID because we consider changing the owners as 90524453Speter * "tainting" as well. 90624453Speter * This is significant for procs that start as root and "become" 90724453Speter * a user without an exec - programs cannot know *everything* 90824453Speter * that libc *might* have put in their data segment. 90924453Speter */ 91060216Speter p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 91124453Speter return (0); 91224453Speter} 91324453Speter 9141541Srgrimes/* 9151541Srgrimes * Check if gid is a member of the group set. 9161541Srgrimes */ 9171549Srgrimesint 9181541Srgrimesgroupmember(gid, cred) 9191541Srgrimes gid_t gid; 9201541Srgrimes register struct ucred *cred; 9211541Srgrimes{ 9221541Srgrimes register gid_t *gp; 9231541Srgrimes gid_t *egp; 9241541Srgrimes 9251541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 9261541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 9271541Srgrimes if (*gp == gid) 9281541Srgrimes return (1); 9291541Srgrimes return (0); 9301541Srgrimes} 9311541Srgrimes 93261287Srwatsonstatic int suser_permitted = 1; 93361287Srwatson 93461287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 93561287Srwatson "processes with uid 0 have privilege"); 93661287Srwatson 9371541Srgrimes/* 9381541Srgrimes * Test whether the specified credentials imply "super-user" 9391541Srgrimes * privilege; if so, and we have accounting info, set the flag 9401541Srgrimes * indicating use of super-powers. 9411541Srgrimes * Returns 0 or error. 9421541Srgrimes */ 9431549Srgrimesint 94446112Sphksuser(p) 94572786Srwatson struct proc *p; 94646112Sphk{ 94746155Sphk return suser_xxx(0, p, 0); 94846112Sphk} 94946112Sphk 95046112Sphkint 95146155Sphksuser_xxx(cred, proc, flag) 95272786Srwatson struct ucred *cred; 95372786Srwatson struct proc *proc; 95446155Sphk int flag; 9551541Srgrimes{ 95661282Srwatson if (!suser_permitted) 95761282Srwatson return (EPERM); 95846155Sphk if (!cred && !proc) { 95946155Sphk printf("suser_xxx(): THINK!\n"); 96046155Sphk return (EPERM); 9611541Srgrimes } 96246155Sphk if (!cred) 96346155Sphk cred = proc->p_ucred; 96446155Sphk if (cred->cr_uid != 0) 96546155Sphk return (EPERM); 96672786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 96746155Sphk return (EPERM); 96846155Sphk return (0); 9691541Srgrimes} 9701541Srgrimes 97165237Srwatsonstatic int 97272786Srwatsonp_cansee(struct proc *p1, struct proc *p2, int *privused) 97365237Srwatson{ 97472786Srwatson int error; 97553518Sphk 97665237Srwatson if (privused != NULL) 97765237Srwatson *privused = 0; 97865237Srwatson 97972786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 98072786Srwatson return (error); 98165237Srwatson 98265293Srwatson if (!ps_showallprocs && p1->p_ucred->cr_uid != p2->p_ucred->cr_uid) { 98365293Srwatson if (suser_xxx(NULL, p1, PRISON_ROOT) == 0) { 98465293Srwatson if (privused != NULL) 98565293Srwatson *privused = 1; 98665293Srwatson return (0); 98765293Srwatson } 98865237Srwatson return (ESRCH); 98965293Srwatson } 99065237Srwatson 99165237Srwatson return (0); 99265237Srwatson} 99365237Srwatson 99465237Srwatsonstatic int 99572786Srwatsonp_cankill(struct proc *p1, struct proc *p2, int *privused) 99653518Sphk{ 99772786Srwatson int error; 99853518Sphk 99965237Srwatson if (privused != NULL) 100065237Srwatson *privused = 0; 100165237Srwatson 100253518Sphk if (p1 == p2) 100353518Sphk return (0); 100465237Srwatson 100572786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 100672786Srwatson return (error); 100765237Srwatson 100853518Sphk if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 100953518Sphk return (0); 101053518Sphk if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 101153518Sphk return (0); 101265237Srwatson /* 101365237Srwatson * XXX should a process be able to affect another process 101465237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 101565237Srwatson */ 101653518Sphk if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 101753518Sphk return (0); 101853518Sphk if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 101953518Sphk return (0); 102065237Srwatson 102165237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 102265237Srwatson if (privused != NULL) 102365237Srwatson *privused = 1; 102453518Sphk return (0); 102565237Srwatson } 102665237Srwatson 102765237Srwatson#ifdef CAPABILITIES 102865237Srwatson if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) { 102965237Srwatson if (privused != NULL) 103065237Srwatson *privused = 1; 103165237Srwatson return (0); 103265237Srwatson } 103365237Srwatson#endif 103465237Srwatson 103553518Sphk return (EPERM); 103653518Sphk} 103753518Sphk 103865237Srwatsonstatic int 103972786Srwatsonp_cansched(struct proc *p1, struct proc *p2, int *privused) 104065237Srwatson{ 104172786Srwatson int error; 104265237Srwatson 104365237Srwatson if (privused != NULL) 104465237Srwatson *privused = 0; 104565237Srwatson 104665237Srwatson if (p1 == p2) 104765237Srwatson return (0); 104865237Srwatson 104972786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 105072786Srwatson return (error); 105165237Srwatson 105265237Srwatson if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 105365237Srwatson return (0); 105465237Srwatson if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 105565237Srwatson return (0); 105665237Srwatson /* 105765237Srwatson * XXX should a process be able to affect another process 105865237Srwatson * acting as the same uid (i.e., a userland nfsd or the like?) 105965237Srwatson */ 106065237Srwatson if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 106165237Srwatson return (0); 106265237Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 106365237Srwatson return (0); 106465237Srwatson 106565237Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) { 106665237Srwatson if (privused != NULL) 106765237Srwatson *privused = 1; 106865237Srwatson return (0); 106965237Srwatson } 107065237Srwatson 107165237Srwatson#ifdef CAPABILITIES 107265237Srwatson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { 107365237Srwatson if (privused != NULL) 107465237Srwatson *privused = 1; 107565237Srwatson return (0); 107665237Srwatson } 107765237Srwatson#endif 107865237Srwatson 107965237Srwatson return (EPERM); 108065237Srwatson} 108165237Srwatson 108265237Srwatsonstatic int 108372786Srwatsonp_candebug(struct proc *p1, struct proc *p2, int *privused) 108465237Srwatson{ 108572786Srwatson int error; 108665237Srwatson 108765237Srwatson if (privused != NULL) 108865237Srwatson *privused = 0; 108965237Srwatson 109065237Srwatson /* XXX it is authorized, but semantics don't permit it */ 109165237Srwatson if (p1 == p2) 109265237Srwatson return (0); 109365237Srwatson 109472786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 109572786Srwatson return (error); 109665237Srwatson 109765237Srwatson /* not owned by you, has done setuid (unless you're root) */ 109865237Srwatson /* add a CAP_SYS_PTRACE here? */ 109967999Srwatson if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid || 110067999Srwatson p1->p_cred->p_ruid != p2->p_cred->p_ruid || 110168591Srwatson p1->p_cred->p_svuid != p2->p_cred->p_ruid || 110267999Srwatson p2->p_flag & P_SUGID) { 110365237Srwatson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 110465237Srwatson return (error); 110565237Srwatson if (privused != NULL) 110665237Srwatson *privused = 1; 110765237Srwatson } 110865237Srwatson 110965237Srwatson /* can't trace init when securelevel > 0 */ 111065237Srwatson if (securelevel > 0 && p2->p_pid == 1) 111165237Srwatson return (EPERM); 111265237Srwatson 111365237Srwatson return (0); 111465237Srwatson} 111565237Srwatson 111665237Srwatsonint 111772786Srwatsonp_can(struct proc *p1, struct proc *p2, int operation, 111865237Srwatson int *privused) 111965237Srwatson{ 112065237Srwatson 112165237Srwatson switch(operation) { 112265237Srwatson case P_CAN_SEE: 112365237Srwatson return (p_cansee(p1, p2, privused)); 112465237Srwatson 112565237Srwatson case P_CAN_KILL: 112665237Srwatson return (p_cankill(p1, p2, privused)); 112765237Srwatson 112865237Srwatson case P_CAN_SCHED: 112965237Srwatson return (p_cansched(p1, p2, privused)); 113065237Srwatson 113165237Srwatson case P_CAN_DEBUG: 113265237Srwatson return (p_candebug(p1, p2, privused)); 113365237Srwatson 113465237Srwatson default: 113565237Srwatson panic("p_can: invalid operation"); 113665237Srwatson } 113765237Srwatson} 113865237Srwatson 113965237Srwatson 114053518Sphk/* 11411541Srgrimes * Allocate a zeroed cred structure. 11421541Srgrimes */ 11431541Srgrimesstruct ucred * 11441541Srgrimescrget() 11451541Srgrimes{ 11461541Srgrimes register struct ucred *cr; 11471541Srgrimes 114869239Salfred MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 11491541Srgrimes cr->cr_ref = 1; 115069239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 11511541Srgrimes return (cr); 11521541Srgrimes} 11531541Srgrimes 11541541Srgrimes/* 115572474Srwatson * Claim another reference to a ucred structure 115669401Salfred */ 115769401Salfredvoid 115869401Salfredcrhold(cr) 115969401Salfred struct ucred *cr; 116069401Salfred{ 116169401Salfred 116272200Sbmilekic mtx_lock(&cr->cr_mtx); 116369401Salfred cr->cr_ref++; 116472200Sbmilekic mtx_unlock(&(cr)->cr_mtx); 116569401Salfred} 116669401Salfred 116769401Salfred 116869401Salfred/* 11691541Srgrimes * Free a cred structure. 11701541Srgrimes * Throws away space when ref count gets to 0. 11711541Srgrimes */ 11721549Srgrimesvoid 11731541Srgrimescrfree(cr) 11741541Srgrimes struct ucred *cr; 11751541Srgrimes{ 117669239Salfred 117772200Sbmilekic mtx_lock(&cr->cr_mtx); 117865495Struckman if (--cr->cr_ref == 0) { 117969239Salfred mtx_destroy(&cr->cr_mtx); 118065495Struckman /* 118165495Struckman * Some callers of crget(), such as nfs_statfs(), 118265495Struckman * allocate a temporary credential, but don't 118365495Struckman * allocate a uidinfo structure. 118465495Struckman */ 118565495Struckman if (cr->cr_uidinfo != NULL) 118665495Struckman uifree(cr->cr_uidinfo); 118772786Srwatson /* 118872786Srwatson * Free a prison, if any. 118972786Srwatson */ 119072786Srwatson if (jailed(cr)) 119172786Srwatson prison_free(cr->cr_prison); 11921541Srgrimes FREE((caddr_t)cr, M_CRED); 119369239Salfred } else { 119472200Sbmilekic mtx_unlock(&cr->cr_mtx); 119565495Struckman } 11961541Srgrimes} 11971541Srgrimes 11981541Srgrimes/* 11991541Srgrimes * Copy cred structure to a new one and free the old one. 12001541Srgrimes */ 12011541Srgrimesstruct ucred * 12021541Srgrimescrcopy(cr) 12031541Srgrimes struct ucred *cr; 12041541Srgrimes{ 12051541Srgrimes struct ucred *newcr; 12061541Srgrimes 120772200Sbmilekic mtx_lock(&cr->cr_mtx); 120869239Salfred if (cr->cr_ref == 1) { 120972200Sbmilekic mtx_unlock(&cr->cr_mtx); 12101541Srgrimes return (cr); 121169239Salfred } 121272200Sbmilekic mtx_unlock(&cr->cr_mtx); 121369239Salfred newcr = crdup(cr); 12141541Srgrimes crfree(cr); 12151541Srgrimes return (newcr); 12161541Srgrimes} 12171541Srgrimes 12181541Srgrimes/* 12191541Srgrimes * Dup cred struct to a new held one. 12201541Srgrimes */ 12211541Srgrimesstruct ucred * 12221541Srgrimescrdup(cr) 12231541Srgrimes struct ucred *cr; 12241541Srgrimes{ 12251541Srgrimes struct ucred *newcr; 12261541Srgrimes 122769239Salfred MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 12281541Srgrimes *newcr = *cr; 122969239Salfred mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 123065495Struckman uihold(newcr->cr_uidinfo); 123172786Srwatson if (jailed(newcr)) 123272786Srwatson prison_hold(newcr->cr_prison); 12331541Srgrimes newcr->cr_ref = 1; 12341541Srgrimes return (newcr); 12351541Srgrimes} 12361541Srgrimes 12371541Srgrimes/* 12381541Srgrimes * Get login name, if available. 12391541Srgrimes */ 124012221Sbde#ifndef _SYS_SYSPROTO_H_ 12411541Srgrimesstruct getlogin_args { 12421541Srgrimes char *namebuf; 12431541Srgrimes u_int namelen; 12441541Srgrimes}; 124512221Sbde#endif 12461541Srgrimes/* ARGSUSED */ 12471549Srgrimesint 124830994Sphkgetlogin(p, uap) 12491541Srgrimes struct proc *p; 12501541Srgrimes struct getlogin_args *uap; 12511541Srgrimes{ 12521541Srgrimes 125323358Sache if (uap->namelen > MAXLOGNAME) 125423359Sache uap->namelen = MAXLOGNAME; 12551541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 12561541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 12571541Srgrimes} 12581541Srgrimes 12591541Srgrimes/* 12601541Srgrimes * Set login name. 12611541Srgrimes */ 126212221Sbde#ifndef _SYS_SYSPROTO_H_ 12631541Srgrimesstruct setlogin_args { 12641541Srgrimes char *namebuf; 12651541Srgrimes}; 126612221Sbde#endif 12671541Srgrimes/* ARGSUSED */ 12681549Srgrimesint 126930994Sphksetlogin(p, uap) 12701541Srgrimes struct proc *p; 12711541Srgrimes struct setlogin_args *uap; 12721541Srgrimes{ 12731541Srgrimes int error; 127423330Sache char logintmp[MAXLOGNAME]; 12751541Srgrimes 127646155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 12771541Srgrimes return (error); 127822522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 127936845Sdfr sizeof(logintmp), (size_t *)0); 12801541Srgrimes if (error == ENAMETOOLONG) 12811541Srgrimes error = EINVAL; 128222522Sdavidn else if (!error) 128322522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 128423330Sache sizeof(logintmp)); 12851541Srgrimes return (error); 12861541Srgrimes} 128731891Ssef 128831891Ssefvoid 128931891Ssefsetsugid(p) 129055338Sphk struct proc *p; 129131891Ssef{ 129231891Ssef p->p_flag |= P_SUGID; 129355707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 129431891Ssef p->p_stops = 0; 129531891Ssef} 129665495Struckman 129765495Struckman/* 129865495Struckman * Helper function to change the effective uid of a process 129965495Struckman */ 130065495Struckmanvoid 130165495Struckmanchange_euid(p, euid) 130265495Struckman struct proc *p; 130365495Struckman uid_t euid; 130465495Struckman{ 130565495Struckman struct pcred *pc; 130665495Struckman struct uidinfo *uip; 130765495Struckman 130865495Struckman pc = p->p_cred; 130965495Struckman /* 131065495Struckman * crcopy is essentially a NOP if ucred has a reference count 131165495Struckman * of 1, which is true if it has already been copied. 131265495Struckman */ 131365495Struckman pc->pc_ucred = crcopy(pc->pc_ucred); 131465495Struckman uip = pc->pc_ucred->cr_uidinfo; 131565495Struckman pc->pc_ucred->cr_uid = euid; 131665495Struckman pc->pc_ucred->cr_uidinfo = uifind(euid); 131765495Struckman uifree(uip); 131865495Struckman} 131965495Struckman 132065495Struckman/* 132165495Struckman * Helper function to change the real uid of a process 132265495Struckman * 132365495Struckman * The per-uid process count for this process is transfered from 132465495Struckman * the old uid to the new uid. 132565495Struckman */ 132667629Sgallatinvoid 132765495Struckmanchange_ruid(p, ruid) 132865495Struckman struct proc *p; 132965495Struckman uid_t ruid; 133065495Struckman{ 133165495Struckman struct pcred *pc; 133265495Struckman struct uidinfo *uip; 133365495Struckman 133465495Struckman pc = p->p_cred; 133565495Struckman (void)chgproccnt(pc->p_uidinfo, -1, 0); 133665495Struckman uip = pc->p_uidinfo; 133765495Struckman /* It is assumed that pcred is not shared between processes */ 133865495Struckman pc->p_ruid = ruid; 133965495Struckman pc->p_uidinfo = uifind(ruid); 134065495Struckman (void)chgproccnt(pc->p_uidinfo, 1, 0); 134165495Struckman uifree(uip); 134265495Struckman} 1343