kern_prot.c revision 79335
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 79335 2001-07-05 17:10:46Z rwatson $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes/* 431541Srgrimes * System calls related to processes and protection 441541Srgrimes */ 451541Srgrimes 4631778Seivind#include "opt_compat.h" 4775426Srwatson#include "opt_global.h" 4831778Seivind 491541Srgrimes#include <sys/param.h> 5076166Smarkm#include <sys/systm.h> 511541Srgrimes#include <sys/acct.h> 5241059Speter#include <sys/kernel.h> 5370317Sjake#include <sys/lock.h> 5476166Smarkm#include <sys/mutex.h> 551541Srgrimes#include <sys/proc.h> 5676166Smarkm#include <sys/sysproto.h> 571541Srgrimes#include <sys/malloc.h> 5831891Ssef#include <sys/pioctl.h> 5965495Struckman#include <sys/resourcevar.h> 6061287Srwatson#include <sys/sysctl.h> 6172786Srwatson#include <sys/jail.h> 621541Srgrimes 6330354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 6430354Sphk 6512221Sbde#ifndef _SYS_SYSPROTO_H_ 6611332Sswallacestruct getpid_args { 671541Srgrimes int dummy; 681541Srgrimes}; 6912221Sbde#endif 701541Srgrimes 7158717Sdillon/* 7270317Sjake * getpid - MP SAFE 7358717Sdillon */ 7470317Sjake 751541Srgrimes/* ARGSUSED */ 761549Srgrimesint 7730994Sphkgetpid(p, uap) 781541Srgrimes struct proc *p; 7911332Sswallace struct getpid_args *uap; 801541Srgrimes{ 811541Srgrimes 8230994Sphk p->p_retval[0] = p->p_pid; 831541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8474728Sjhb PROC_LOCK(p); 8530994Sphk p->p_retval[1] = p->p_pptr->p_pid; 8674728Sjhb PROC_UNLOCK(p); 871541Srgrimes#endif 881541Srgrimes return (0); 891541Srgrimes} 901541Srgrimes 9170317Sjake/* 9270317Sjake * getppid - MP SAFE 9370317Sjake */ 9470317Sjake 9512221Sbde#ifndef _SYS_SYSPROTO_H_ 9611332Sswallacestruct getppid_args { 9711332Sswallace int dummy; 9811332Sswallace}; 9912221Sbde#endif 1001541Srgrimes/* ARGSUSED */ 1011549Srgrimesint 10230994Sphkgetppid(p, uap) 1031541Srgrimes struct proc *p; 10411332Sswallace struct getppid_args *uap; 1051541Srgrimes{ 1061541Srgrimes 10774728Sjhb PROC_LOCK(p); 10830994Sphk p->p_retval[0] = p->p_pptr->p_pid; 10974728Sjhb PROC_UNLOCK(p); 1101541Srgrimes return (0); 1111541Srgrimes} 1121541Srgrimes 11358717Sdillon/* 11458717Sdillon * Get process group ID; note that POSIX getpgrp takes no parameter 11558717Sdillon * 11658717Sdillon * MP SAFE 11758717Sdillon */ 11812221Sbde#ifndef _SYS_SYSPROTO_H_ 11911332Sswallacestruct getpgrp_args { 12011332Sswallace int dummy; 12111332Sswallace}; 12212221Sbde#endif 12311332Sswallace 1241549Srgrimesint 12530994Sphkgetpgrp(p, uap) 1261541Srgrimes struct proc *p; 12711332Sswallace struct getpgrp_args *uap; 1281541Srgrimes{ 1291541Srgrimes 13030994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1311541Srgrimes return (0); 1321541Srgrimes} 1331541Srgrimes 13428401Speter/* Get an arbitary pid's process group id */ 13512221Sbde#ifndef _SYS_SYSPROTO_H_ 13628401Speterstruct getpgid_args { 13728401Speter pid_t pid; 13828401Speter}; 13928401Speter#endif 14028401Speter 14128401Speterint 14230994Sphkgetpgid(p, uap) 14328401Speter struct proc *p; 14428401Speter struct getpgid_args *uap; 14528401Speter{ 14641726Struckman struct proc *pt; 14775448Srwatson int error; 14841726Struckman 14928401Speter if (uap->pid == 0) 15075893Sjhb p->p_retval[0] = p->p_pgrp->pg_id; 15175893Sjhb else { 15275893Sjhb if ((pt = pfind(uap->pid)) == NULL) 15375893Sjhb return ESRCH; 15479335Srwatson if ((error = p_cansee(p, pt))) { 15575893Sjhb PROC_UNLOCK(pt); 15675893Sjhb return (error); 15775893Sjhb } 15875893Sjhb p->p_retval[0] = pt->p_pgrp->pg_id; 15975893Sjhb PROC_UNLOCK(pt); 16075893Sjhb } 16128401Speter return 0; 16228401Speter} 16328401Speter 16428401Speter/* 16528401Speter * Get an arbitary pid's session id. 16628401Speter */ 16728401Speter#ifndef _SYS_SYSPROTO_H_ 16828401Speterstruct getsid_args { 16928401Speter pid_t pid; 17028401Speter}; 17128401Speter#endif 17228401Speter 17328401Speterint 17430994Sphkgetsid(p, uap) 17528401Speter struct proc *p; 17628401Speter struct getsid_args *uap; 17728401Speter{ 17841726Struckman struct proc *pt; 17975448Srwatson int error; 18041726Struckman 18128401Speter if (uap->pid == 0) 18275893Sjhb p->p_retval[0] = p->p_session->s_sid; 18375893Sjhb else { 18475893Sjhb if ((pt = pfind(uap->pid)) == NULL) 18575893Sjhb return ESRCH; 18679335Srwatson if ((error = p_cansee(p, pt))) { 18775893Sjhb PROC_UNLOCK(pt); 18875893Sjhb return (error); 18975893Sjhb } 19075893Sjhb p->p_retval[0] = pt->p_session->s_sid; 19175893Sjhb PROC_UNLOCK(pt); 19275893Sjhb } 19328401Speter return 0; 19428401Speter} 19528401Speter 19628401Speter 19758941Sdillon/* 19858941Sdillon * getuid() - MP SAFE 19958941Sdillon */ 20028401Speter#ifndef _SYS_SYSPROTO_H_ 20111332Sswallacestruct getuid_args { 20211332Sswallace int dummy; 20311332Sswallace}; 20412221Sbde#endif 20511332Sswallace 2061541Srgrimes/* ARGSUSED */ 2071549Srgrimesint 20830994Sphkgetuid(p, uap) 2091541Srgrimes struct proc *p; 21011332Sswallace struct getuid_args *uap; 2111541Srgrimes{ 2121541Srgrimes 21377183Srwatson p->p_retval[0] = p->p_ucred->cr_ruid; 2141541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 21530994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 2161541Srgrimes#endif 2171541Srgrimes return (0); 2181541Srgrimes} 2191541Srgrimes 22058941Sdillon/* 22158941Sdillon * geteuid() - MP SAFE 22258941Sdillon */ 22312221Sbde#ifndef _SYS_SYSPROTO_H_ 22411332Sswallacestruct geteuid_args { 22511332Sswallace int dummy; 22611332Sswallace}; 22712221Sbde#endif 22811332Sswallace 2291541Srgrimes/* ARGSUSED */ 2301549Srgrimesint 23130994Sphkgeteuid(p, uap) 2321541Srgrimes struct proc *p; 23311332Sswallace struct geteuid_args *uap; 2341541Srgrimes{ 2351541Srgrimes 23630994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2371541Srgrimes return (0); 2381541Srgrimes} 2391541Srgrimes 24058941Sdillon/* 24158941Sdillon * getgid() - MP SAFE 24258941Sdillon */ 24312221Sbde#ifndef _SYS_SYSPROTO_H_ 24411332Sswallacestruct getgid_args { 24511332Sswallace int dummy; 24611332Sswallace}; 24712221Sbde#endif 24811332Sswallace 2491541Srgrimes/* ARGSUSED */ 2501549Srgrimesint 25130994Sphkgetgid(p, uap) 2521541Srgrimes struct proc *p; 25311332Sswallace struct getgid_args *uap; 2541541Srgrimes{ 2551541Srgrimes 25677183Srwatson p->p_retval[0] = p->p_ucred->cr_rgid; 2571541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 25830994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2591541Srgrimes#endif 2601541Srgrimes return (0); 2611541Srgrimes} 2621541Srgrimes 2631541Srgrimes/* 2641541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2651541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2661541Srgrimes * correctly in a library function. 2671541Srgrimes */ 26812221Sbde#ifndef _SYS_SYSPROTO_H_ 26911332Sswallacestruct getegid_args { 27011332Sswallace int dummy; 27111332Sswallace}; 27212221Sbde#endif 27311332Sswallace 2741541Srgrimes/* ARGSUSED */ 2751549Srgrimesint 27630994Sphkgetegid(p, uap) 2771541Srgrimes struct proc *p; 27811332Sswallace struct getegid_args *uap; 2791541Srgrimes{ 2801541Srgrimes 28130994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2821541Srgrimes return (0); 2831541Srgrimes} 2841541Srgrimes 28512221Sbde#ifndef _SYS_SYSPROTO_H_ 2861541Srgrimesstruct getgroups_args { 2871541Srgrimes u_int gidsetsize; 2881541Srgrimes gid_t *gidset; 2891541Srgrimes}; 29012221Sbde#endif 2911549Srgrimesint 29230994Sphkgetgroups(p, uap) 2931541Srgrimes struct proc *p; 2941541Srgrimes register struct getgroups_args *uap; 2951541Srgrimes{ 29677183Srwatson struct ucred *cred = p->p_ucred; 29777183Srwatson u_int ngrp; 2981541Srgrimes int error; 2991541Srgrimes 3001541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 30177183Srwatson p->p_retval[0] = cred->cr_ngroups; 3021541Srgrimes return (0); 3031541Srgrimes } 30477183Srwatson if (ngrp < cred->cr_ngroups) 3051541Srgrimes return (EINVAL); 30677183Srwatson ngrp = cred->cr_ngroups; 30777183Srwatson if ((error = copyout((caddr_t)cred->cr_groups, 3083098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 3091541Srgrimes return (error); 31030994Sphk p->p_retval[0] = ngrp; 3111541Srgrimes return (0); 3121541Srgrimes} 3131541Srgrimes 31412221Sbde#ifndef _SYS_SYSPROTO_H_ 31512207Sbdestruct setsid_args { 31611332Sswallace int dummy; 31711332Sswallace}; 31812221Sbde#endif 31911332Sswallace 3201541Srgrimes/* ARGSUSED */ 3211549Srgrimesint 32230994Sphksetsid(p, uap) 3231541Srgrimes register struct proc *p; 32412207Sbde struct setsid_args *uap; 3251541Srgrimes{ 3261541Srgrimes 3271541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 3281541Srgrimes return (EPERM); 3291541Srgrimes } else { 3301541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 33130994Sphk p->p_retval[0] = p->p_pid; 3321541Srgrimes return (0); 3331541Srgrimes } 3341541Srgrimes} 3351541Srgrimes 3361541Srgrimes/* 3371541Srgrimes * set process group (setpgid/old setpgrp) 3381541Srgrimes * 3391541Srgrimes * caller does setpgid(targpid, targpgid) 3401541Srgrimes * 3411541Srgrimes * pid must be caller or child of caller (ESRCH) 3421541Srgrimes * if a child 3431541Srgrimes * pid must be in same session (EPERM) 3441541Srgrimes * pid can't have done an exec (EACCES) 3451541Srgrimes * if pgid != pid 3461541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3471541Srgrimes * pid must not be session leader (EPERM) 3481541Srgrimes */ 34912221Sbde#ifndef _SYS_SYSPROTO_H_ 3501541Srgrimesstruct setpgid_args { 3511541Srgrimes int pid; /* target process id */ 3521541Srgrimes int pgid; /* target pgrp id */ 3531541Srgrimes}; 35412221Sbde#endif 3551541Srgrimes/* ARGSUSED */ 3561549Srgrimesint 35730994Sphksetpgid(curp, uap) 3581541Srgrimes struct proc *curp; 3591541Srgrimes register struct setpgid_args *uap; 3601541Srgrimes{ 3611541Srgrimes register struct proc *targp; /* target process */ 3621541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 36375448Srwatson int error; 3641541Srgrimes 36520677Sbde if (uap->pgid < 0) 36620677Sbde return (EINVAL); 3671541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 36875893Sjhb if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 36975893Sjhb if (targp) 37075893Sjhb PROC_UNLOCK(targp); 3711541Srgrimes return (ESRCH); 37275893Sjhb } 37379335Srwatson if ((error = p_cansee(curproc, targp))) { 37475893Sjhb PROC_UNLOCK(targp); 37575448Srwatson return (error); 37675893Sjhb } 37775893Sjhb if (targp->p_pgrp == NULL || 37875893Sjhb targp->p_session != curp->p_session) { 37975893Sjhb PROC_UNLOCK(targp); 3801541Srgrimes return (EPERM); 38175893Sjhb } 38275893Sjhb if (targp->p_flag & P_EXEC) { 38375893Sjhb PROC_UNLOCK(targp); 3841541Srgrimes return (EACCES); 38575893Sjhb } 38675893Sjhb } else { 3871541Srgrimes targp = curp; 38875893Sjhb PROC_LOCK(curp); /* XXX: not needed */ 38975893Sjhb } 39075893Sjhb if (SESS_LEADER(targp)) { 39175893Sjhb PROC_UNLOCK(targp); 3921541Srgrimes return (EPERM); 39375893Sjhb } 3941541Srgrimes if (uap->pgid == 0) 3951541Srgrimes uap->pgid = targp->p_pid; 3961541Srgrimes else if (uap->pgid != targp->p_pid) 3971541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 39875893Sjhb pgrp->pg_session != curp->p_session) { 39975893Sjhb PROC_UNLOCK(targp); 4001541Srgrimes return (EPERM); 40175893Sjhb } 40275893Sjhb /* XXX: We should probably hold the lock across enterpgrp. */ 40375893Sjhb PROC_UNLOCK(targp); 4041541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 4051541Srgrimes} 4061541Srgrimes 40724448Speter/* 40824448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 40972093Sasmodai * compatible. It says that setting the uid/gid to euid/egid is a special 41024448Speter * case of "appropriate privilege". Once the rules are expanded out, this 41124448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 41224448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 41324448Speter * does not set the saved id - this is dangerous for traditional BSD 41424448Speter * programs. For this reason, we *really* do not want to set 41524448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 41624448Speter */ 41724448Speter#define POSIX_APPENDIX_B_4_2_2 41824448Speter 41912221Sbde#ifndef _SYS_SYSPROTO_H_ 4201541Srgrimesstruct setuid_args { 4211541Srgrimes uid_t uid; 4221541Srgrimes}; 42312221Sbde#endif 4241541Srgrimes/* ARGSUSED */ 4251549Srgrimesint 42630994Sphksetuid(p, uap) 4271541Srgrimes struct proc *p; 4281541Srgrimes struct setuid_args *uap; 4291541Srgrimes{ 43077183Srwatson struct ucred *newcred, *oldcred; 43177183Srwatson uid_t uid; 4321541Srgrimes int error; 4331541Srgrimes 43477183Srwatson uid = uap->uid; 43577183Srwatson oldcred = p->p_ucred; 43624448Speter /* 43724448Speter * See if we have "permission" by POSIX 1003.1 rules. 43824448Speter * 43924448Speter * Note that setuid(geteuid()) is a special case of 44024448Speter * "appropriate privileges" in appendix B.4.2.2. We need 44172093Sasmodai * to use this clause to be compatible with traditional BSD 44224448Speter * semantics. Basically, it means that "setuid(xx)" sets all 44324448Speter * three id's (assuming you have privs). 44424448Speter * 44524448Speter * Notes on the logic. We do things in three steps. 44624448Speter * 1: We determine if the euid is going to change, and do EPERM 44724448Speter * right away. We unconditionally change the euid later if this 44824448Speter * test is satisfied, simplifying that part of the logic. 44924448Speter * 2: We determine if the real and/or saved uid's are going to 45024448Speter * change. Determined by compile options. 45124448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 45224448Speter */ 45377183Srwatson if (uid != oldcred->cr_ruid && /* allow setuid(getuid()) */ 45417994Sache#ifdef _POSIX_SAVED_IDS 45577183Srwatson uid != oldcred->cr_svuid && /* allow setuid(saved gid) */ 45617994Sache#endif 45724448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 45877183Srwatson uid != oldcred->cr_uid && /* allow setuid(geteuid()) */ 45924448Speter#endif 46077183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 4611541Srgrimes return (error); 46224448Speter 46377183Srwatson newcred = crdup(oldcred); 46424448Speter#ifdef _POSIX_SAVED_IDS 4651541Srgrimes /* 46624448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 46724448Speter * If so, we are changing the real uid and/or saved uid. 4681541Srgrimes */ 46917994Sache if ( 47024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 47177183Srwatson uid == oldcred->cr_uid || 47217994Sache#endif 47377183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 47417994Sache#endif 47524448Speter { 47624448Speter /* 47765495Struckman * Set the real uid and transfer proc count to new user. 47824448Speter */ 47977183Srwatson if (uid != oldcred->cr_ruid) { 48077183Srwatson change_ruid(newcred, uid); 48165495Struckman setsugid(p); 48224448Speter } 48324448Speter /* 48424448Speter * Set saved uid 48524448Speter * 48624448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 48724448Speter * the security of seteuid() depends on it. B.4.2.2 says it 48824448Speter * is important that we should do this. 48924448Speter */ 49077183Srwatson if (uid != oldcred->cr_svuid) { 49177183Srwatson change_svuid(newcred, uid); 49231891Ssef setsugid(p); 49324448Speter } 4948141Sache } 49524448Speter 49624448Speter /* 49724448Speter * In all permitted cases, we are changing the euid. 49824448Speter * Copy credentials so other references do not see our changes. 49924448Speter */ 50077183Srwatson if (uid != oldcred->cr_uid) { 50177183Srwatson change_euid(newcred, uid); 50231891Ssef setsugid(p); 50324448Speter } 50477183Srwatson p->p_ucred = newcred; 50577183Srwatson crfree(oldcred); 5061541Srgrimes return (0); 5071541Srgrimes} 5081541Srgrimes 50912221Sbde#ifndef _SYS_SYSPROTO_H_ 5101541Srgrimesstruct seteuid_args { 5111541Srgrimes uid_t euid; 5121541Srgrimes}; 51312221Sbde#endif 5141541Srgrimes/* ARGSUSED */ 5151549Srgrimesint 51630994Sphkseteuid(p, uap) 5171541Srgrimes struct proc *p; 5181541Srgrimes struct seteuid_args *uap; 5191541Srgrimes{ 52077183Srwatson struct ucred *newcred, *oldcred; 52177183Srwatson uid_t euid; 5221541Srgrimes int error; 5231541Srgrimes 5241541Srgrimes euid = uap->euid; 52577183Srwatson oldcred = p->p_ucred; 52677183Srwatson if (euid != oldcred->cr_ruid && /* allow seteuid(getuid()) */ 52777183Srwatson euid != oldcred->cr_svuid && /* allow seteuid(saved uid) */ 52877183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 5291541Srgrimes return (error); 5301541Srgrimes /* 5311541Srgrimes * Everything's okay, do it. Copy credentials so other references do 5321541Srgrimes * not see our changes. 5331541Srgrimes */ 53477183Srwatson newcred = crdup(oldcred); 53577183Srwatson if (oldcred->cr_uid != euid) { 53677183Srwatson change_euid(newcred, euid); 53731891Ssef setsugid(p); 53824449Speter } 53977183Srwatson p->p_ucred = newcred; 54077183Srwatson crfree(oldcred); 5411541Srgrimes return (0); 5421541Srgrimes} 5431541Srgrimes 54412221Sbde#ifndef _SYS_SYSPROTO_H_ 5451541Srgrimesstruct setgid_args { 5461541Srgrimes gid_t gid; 5471541Srgrimes}; 54812221Sbde#endif 5491541Srgrimes/* ARGSUSED */ 5501549Srgrimesint 55130994Sphksetgid(p, uap) 5521541Srgrimes struct proc *p; 5531541Srgrimes struct setgid_args *uap; 5541541Srgrimes{ 55577183Srwatson struct ucred *newcred, *oldcred; 55677183Srwatson gid_t gid; 5571541Srgrimes int error; 5581541Srgrimes 55977183Srwatson gid = uap->gid; 56077183Srwatson oldcred = p->p_ucred; 56124448Speter /* 56224448Speter * See if we have "permission" by POSIX 1003.1 rules. 56324448Speter * 56424448Speter * Note that setgid(getegid()) is a special case of 56524448Speter * "appropriate privileges" in appendix B.4.2.2. We need 56672093Sasmodai * to use this clause to be compatible with traditional BSD 56724448Speter * semantics. Basically, it means that "setgid(xx)" sets all 56824448Speter * three id's (assuming you have privs). 56924448Speter * 57024448Speter * For notes on the logic here, see setuid() above. 57124448Speter */ 57277183Srwatson if (gid != oldcred->cr_rgid && /* allow setgid(getgid()) */ 57317994Sache#ifdef _POSIX_SAVED_IDS 57477183Srwatson gid != oldcred->cr_svgid && /* allow setgid(saved gid) */ 57517994Sache#endif 57624448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 57777183Srwatson gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */ 57824448Speter#endif 57977183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 5801541Srgrimes return (error); 58124448Speter 58277183Srwatson newcred = crdup(oldcred); 58317994Sache#ifdef _POSIX_SAVED_IDS 58424448Speter /* 58524448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 58624448Speter * If so, we are changing the real uid and saved gid. 58724448Speter */ 58824448Speter if ( 58924448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 59077183Srwatson gid == oldcred->cr_groups[0] || 59117994Sache#endif 59277183Srwatson suser_xxx(oldcred, NULL, PRISON_ROOT) == 0) /* we are using privs */ 59324448Speter#endif 59424448Speter { 59524448Speter /* 59624448Speter * Set real gid 59724448Speter */ 59877183Srwatson if (oldcred->cr_rgid != gid) { 59977183Srwatson change_rgid(newcred, gid); 60031891Ssef setsugid(p); 60124448Speter } 60224448Speter /* 60324448Speter * Set saved gid 60424448Speter * 60524448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 60624448Speter * the security of setegid() depends on it. B.4.2.2 says it 60724448Speter * is important that we should do this. 60824448Speter */ 60977183Srwatson if (oldcred->cr_svgid != gid) { 61077183Srwatson change_svgid(newcred, gid); 61131891Ssef setsugid(p); 61224448Speter } 6138141Sache } 61424448Speter /* 61524448Speter * In all cases permitted cases, we are changing the egid. 61624448Speter * Copy credentials so other references do not see our changes. 61724448Speter */ 61877183Srwatson if (oldcred->cr_groups[0] != gid) { 61977183Srwatson change_egid(newcred, gid); 62031891Ssef setsugid(p); 62124448Speter } 62277183Srwatson p->p_ucred = newcred; 62377183Srwatson crfree(oldcred); 6241541Srgrimes return (0); 6251541Srgrimes} 6261541Srgrimes 62712221Sbde#ifndef _SYS_SYSPROTO_H_ 6281541Srgrimesstruct setegid_args { 6291541Srgrimes gid_t egid; 6301541Srgrimes}; 63112221Sbde#endif 6321541Srgrimes/* ARGSUSED */ 6331549Srgrimesint 63430994Sphksetegid(p, uap) 6351541Srgrimes struct proc *p; 6361541Srgrimes struct setegid_args *uap; 6371541Srgrimes{ 63877183Srwatson struct ucred *newcred, *oldcred; 63977183Srwatson gid_t egid; 6401541Srgrimes int error; 6411541Srgrimes 6421541Srgrimes egid = uap->egid; 64377183Srwatson oldcred = p->p_ucred; 64477183Srwatson if (egid != oldcred->cr_rgid && /* allow setegid(getgid()) */ 64577183Srwatson egid != oldcred->cr_svgid && /* allow setegid(saved gid) */ 64677183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 6471541Srgrimes return (error); 64877183Srwatson newcred = crdup(oldcred); 64977183Srwatson if (oldcred->cr_groups[0] != egid) { 65077183Srwatson change_egid(newcred, egid); 65131891Ssef setsugid(p); 65224449Speter } 65377183Srwatson p->p_ucred = newcred; 65477183Srwatson crfree(oldcred); 6551541Srgrimes return (0); 6561541Srgrimes} 6571541Srgrimes 65812221Sbde#ifndef _SYS_SYSPROTO_H_ 6591541Srgrimesstruct setgroups_args { 6601541Srgrimes u_int gidsetsize; 6611541Srgrimes gid_t *gidset; 6621541Srgrimes}; 66312221Sbde#endif 6641541Srgrimes/* ARGSUSED */ 6651549Srgrimesint 66630994Sphksetgroups(p, uap) 6671541Srgrimes struct proc *p; 6681541Srgrimes struct setgroups_args *uap; 6691541Srgrimes{ 67077183Srwatson struct ucred *newcred, *oldcred; 67177183Srwatson u_int ngrp; 6721541Srgrimes int error; 6731541Srgrimes 67477183Srwatson ngrp = uap->gidsetsize; 67577183Srwatson oldcred = p->p_ucred; 67677183Srwatson if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT))) 6771541Srgrimes return (error); 67824447Speter if (ngrp > NGROUPS) 6791541Srgrimes return (EINVAL); 68024447Speter /* 68124447Speter * XXX A little bit lazy here. We could test if anything has 68224447Speter * changed before crcopy() and setting P_SUGID. 68324447Speter */ 68477183Srwatson newcred = crdup(oldcred); 68524447Speter if (ngrp < 1) { 68624447Speter /* 68724447Speter * setgroups(0, NULL) is a legitimate way of clearing the 68824447Speter * groups vector on non-BSD systems (which generally do not 68924447Speter * have the egid in the groups[0]). We risk security holes 69024447Speter * when running non-BSD software if we do not do the same. 69124447Speter */ 69277183Srwatson newcred->cr_ngroups = 1; 69324447Speter } else { 69424447Speter if ((error = copyin((caddr_t)uap->gidset, 69577183Srwatson (caddr_t)newcred->cr_groups, ngrp * sizeof(gid_t)))) { 69677183Srwatson crfree(newcred); 69724447Speter return (error); 69877183Srwatson } 69977183Srwatson newcred->cr_ngroups = ngrp; 70024447Speter } 70131891Ssef setsugid(p); 70277183Srwatson p->p_ucred = newcred; 70377183Srwatson crfree(oldcred); 7041541Srgrimes return (0); 7051541Srgrimes} 7061541Srgrimes 70712221Sbde#ifndef _SYS_SYSPROTO_H_ 7081541Srgrimesstruct setreuid_args { 7099238Sache uid_t ruid; 7109238Sache uid_t euid; 7111541Srgrimes}; 71212221Sbde#endif 7131541Srgrimes/* ARGSUSED */ 7141549Srgrimesint 71530994Sphksetreuid(p, uap) 7161541Srgrimes register struct proc *p; 7171541Srgrimes struct setreuid_args *uap; 7181541Srgrimes{ 71977183Srwatson struct ucred *newcred, *oldcred; 72077183Srwatson uid_t ruid, euid; 7218135Sache int error; 7221541Srgrimes 7239238Sache ruid = uap->ruid; 7249238Sache euid = uap->euid; 72577183Srwatson oldcred = p->p_ucred; 72677183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 72777183Srwatson ruid != oldcred->cr_svuid) || 72877183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_uid && 72977183Srwatson euid != oldcred->cr_ruid && euid != oldcred->cr_svuid)) && 73077183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 7318135Sache return (error); 73277183Srwatson newcred = crdup(oldcred); 73377183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 73477183Srwatson change_euid(newcred, euid); 73531891Ssef setsugid(p); 73624450Speter } 73777183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 73877183Srwatson change_ruid(newcred, ruid); 73931891Ssef setsugid(p); 7408135Sache } 74177183Srwatson if ((ruid != (uid_t)-1 || newcred->cr_uid != newcred->cr_ruid) && 74277183Srwatson newcred->cr_svuid != newcred->cr_uid) { 74377183Srwatson change_svuid(newcred, newcred->cr_uid); 74431891Ssef setsugid(p); 74524450Speter } 74677183Srwatson p->p_ucred = newcred; 74777183Srwatson crfree(oldcred); 7488135Sache return (0); 7491541Srgrimes} 7501541Srgrimes 75112221Sbde#ifndef _SYS_SYSPROTO_H_ 7521541Srgrimesstruct setregid_args { 7539238Sache gid_t rgid; 7549238Sache gid_t egid; 7551541Srgrimes}; 75612221Sbde#endif 7571541Srgrimes/* ARGSUSED */ 7581549Srgrimesint 75930994Sphksetregid(p, uap) 7601541Srgrimes register struct proc *p; 7611541Srgrimes struct setregid_args *uap; 7621541Srgrimes{ 76377183Srwatson struct ucred *newcred, *oldcred; 76477183Srwatson gid_t rgid, egid; 7658135Sache int error; 7661541Srgrimes 7679238Sache rgid = uap->rgid; 7689238Sache egid = uap->egid; 76977183Srwatson oldcred = p->p_ucred; 77077183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 77177183Srwatson rgid != oldcred->cr_svgid) || 77277183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] && 77377183Srwatson egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) && 77477183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 7758135Sache return (error); 7769238Sache 77777183Srwatson newcred = crdup(oldcred); 77877183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 77977183Srwatson change_egid(newcred, egid); 78031891Ssef setsugid(p); 78124450Speter } 78277183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 78377183Srwatson change_rgid(newcred, rgid); 78431891Ssef setsugid(p); 78524450Speter } 78677183Srwatson if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) && 78777183Srwatson newcred->cr_svgid != newcred->cr_groups[0]) { 78877183Srwatson change_svgid(newcred, newcred->cr_groups[0]); 78931891Ssef setsugid(p); 79024450Speter } 79177812Sru p->p_ucred = newcred; 79277812Sru crfree(oldcred); 7938135Sache return (0); 7941541Srgrimes} 7951541Srgrimes 79656115Speter/* 79756115Speter * setresuid(ruid, euid, suid) is like setreuid except control over the 79856115Speter * saved uid is explicit. 79956115Speter */ 80056115Speter 80124453Speter#ifndef _SYS_SYSPROTO_H_ 80256115Speterstruct setresuid_args { 80356115Speter uid_t ruid; 80456115Speter uid_t euid; 80556115Speter uid_t suid; 80656115Speter}; 80756115Speter#endif 80856115Speter/* ARGSUSED */ 80956115Speterint 81056115Spetersetresuid(p, uap) 81156115Speter register struct proc *p; 81256115Speter struct setresuid_args *uap; 81356115Speter{ 81477183Srwatson struct ucred *newcred, *oldcred; 81577183Srwatson uid_t ruid, euid, suid; 81656115Speter int error; 81756115Speter 81856115Speter ruid = uap->ruid; 81956115Speter euid = uap->euid; 82056115Speter suid = uap->suid; 82177183Srwatson oldcred = p->p_ucred; 82277183Srwatson if (((ruid != (uid_t)-1 && ruid != oldcred->cr_ruid && 82377183Srwatson ruid != oldcred->cr_svuid && 82477183Srwatson ruid != oldcred->cr_uid) || 82577183Srwatson (euid != (uid_t)-1 && euid != oldcred->cr_ruid && 82677183Srwatson euid != oldcred->cr_svuid && 82777183Srwatson euid != oldcred->cr_uid) || 82877183Srwatson (suid != (uid_t)-1 && suid != oldcred->cr_ruid && 82977183Srwatson suid != oldcred->cr_svuid && 83077183Srwatson suid != oldcred->cr_uid)) && 83177183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 83256115Speter return (error); 83377183Srwatson 83477183Srwatson newcred = crdup(oldcred); 83577183Srwatson if (euid != (uid_t)-1 && oldcred->cr_uid != euid) { 83677183Srwatson change_euid(newcred, euid); 83756115Speter setsugid(p); 83856115Speter } 83977183Srwatson if (ruid != (uid_t)-1 && oldcred->cr_ruid != ruid) { 84077183Srwatson change_ruid(newcred, ruid); 84156115Speter setsugid(p); 84256115Speter } 84377183Srwatson if (suid != (uid_t)-1 && oldcred->cr_svuid != suid) { 84477183Srwatson change_svuid(newcred, suid); 84556115Speter setsugid(p); 84656115Speter } 84777183Srwatson p->p_ucred = newcred; 84877183Srwatson crfree(oldcred); 84956115Speter return (0); 85056115Speter} 85156115Speter 85256115Speter/* 85356115Speter * setresgid(rgid, egid, sgid) is like setregid except control over the 85456115Speter * saved gid is explicit. 85556115Speter */ 85656115Speter 85756115Speter#ifndef _SYS_SYSPROTO_H_ 85856115Speterstruct setresgid_args { 85956115Speter gid_t rgid; 86056115Speter gid_t egid; 86156115Speter gid_t sgid; 86256115Speter}; 86356115Speter#endif 86456115Speter/* ARGSUSED */ 86556115Speterint 86656115Spetersetresgid(p, uap) 86756115Speter register struct proc *p; 86856115Speter struct setresgid_args *uap; 86956115Speter{ 87077183Srwatson struct ucred *newcred, *oldcred; 87177183Srwatson gid_t rgid, egid, sgid; 87256115Speter int error; 87356115Speter 87456115Speter rgid = uap->rgid; 87556115Speter egid = uap->egid; 87656115Speter sgid = uap->sgid; 87777183Srwatson oldcred = p->p_ucred; 87877183Srwatson if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid && 87977183Srwatson rgid != oldcred->cr_svgid && 88077183Srwatson rgid != oldcred->cr_groups[0]) || 88177183Srwatson (egid != (gid_t)-1 && egid != oldcred->cr_rgid && 88277183Srwatson egid != oldcred->cr_svgid && 88377183Srwatson egid != oldcred->cr_groups[0]) || 88477183Srwatson (sgid != (gid_t)-1 && sgid != oldcred->cr_rgid && 88577183Srwatson sgid != oldcred->cr_svgid && 88677183Srwatson sgid != oldcred->cr_groups[0])) && 88777183Srwatson (error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) 88856115Speter return (error); 88956115Speter 89077183Srwatson newcred = crdup(oldcred); 89177183Srwatson if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) { 89277183Srwatson change_egid(newcred, egid); 89356115Speter setsugid(p); 89456115Speter } 89577183Srwatson if (rgid != (gid_t)-1 && oldcred->cr_rgid != rgid) { 89677183Srwatson change_rgid(newcred, rgid); 89756115Speter setsugid(p); 89856115Speter } 89977183Srwatson if (sgid != (gid_t)-1 && oldcred->cr_svgid != sgid) { 90077183Srwatson change_svgid(newcred, sgid); 90156115Speter setsugid(p); 90256115Speter } 90377183Srwatson p->p_ucred = newcred; 90477183Srwatson crfree(oldcred); 90556115Speter return (0); 90656115Speter} 90756115Speter 90856115Speter#ifndef _SYS_SYSPROTO_H_ 90956115Speterstruct getresuid_args { 91056115Speter uid_t *ruid; 91156115Speter uid_t *euid; 91256115Speter uid_t *suid; 91356115Speter}; 91456115Speter#endif 91556115Speter/* ARGSUSED */ 91656115Speterint 91756115Spetergetresuid(p, uap) 91856115Speter register struct proc *p; 91956115Speter struct getresuid_args *uap; 92056115Speter{ 92177183Srwatson struct ucred *cred = p->p_ucred; 92256115Speter int error1 = 0, error2 = 0, error3 = 0; 92356115Speter 92456115Speter if (uap->ruid) 92577183Srwatson error1 = copyout((caddr_t)&cred->cr_ruid, 92677183Srwatson (caddr_t)uap->ruid, sizeof(cred->cr_ruid)); 92756115Speter if (uap->euid) 92877183Srwatson error2 = copyout((caddr_t)&cred->cr_uid, 92977183Srwatson (caddr_t)uap->euid, sizeof(cred->cr_uid)); 93056115Speter if (uap->suid) 93177183Srwatson error3 = copyout((caddr_t)&cred->cr_svuid, 93277183Srwatson (caddr_t)uap->suid, sizeof(cred->cr_svuid)); 93356115Speter return error1 ? error1 : (error2 ? error2 : error3); 93456115Speter} 93556115Speter 93656115Speter#ifndef _SYS_SYSPROTO_H_ 93756115Speterstruct getresgid_args { 93856115Speter gid_t *rgid; 93956115Speter gid_t *egid; 94056115Speter gid_t *sgid; 94156115Speter}; 94256115Speter#endif 94356115Speter/* ARGSUSED */ 94456115Speterint 94556115Spetergetresgid(p, uap) 94656115Speter register struct proc *p; 94756115Speter struct getresgid_args *uap; 94856115Speter{ 94977183Srwatson struct ucred *cred = p->p_ucred; 95056115Speter int error1 = 0, error2 = 0, error3 = 0; 95156115Speter 95256115Speter if (uap->rgid) 95377183Srwatson error1 = copyout((caddr_t)&cred->cr_rgid, 95477183Srwatson (caddr_t)uap->rgid, sizeof(cred->cr_rgid)); 95556115Speter if (uap->egid) 95677183Srwatson error2 = copyout((caddr_t)&cred->cr_groups[0], 95777183Srwatson (caddr_t)uap->egid, sizeof(cred->cr_groups[0])); 95856115Speter if (uap->sgid) 95977183Srwatson error3 = copyout((caddr_t)&cred->cr_svgid, 96077183Srwatson (caddr_t)uap->sgid, sizeof(cred->cr_svgid)); 96156115Speter return error1 ? error1 : (error2 ? error2 : error3); 96256115Speter} 96356115Speter 96456115Speter 96556115Speter#ifndef _SYS_SYSPROTO_H_ 96624453Speterstruct issetugid_args { 96724453Speter int dummy; 96824453Speter}; 96924453Speter#endif 97024453Speter/* ARGSUSED */ 97124453Speterint 97230994Sphkissetugid(p, uap) 97324453Speter register struct proc *p; 97424453Speter struct issetugid_args *uap; 97524453Speter{ 97624453Speter /* 97724453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 97824453Speter * we use P_SUGID because we consider changing the owners as 97924453Speter * "tainting" as well. 98024453Speter * This is significant for procs that start as root and "become" 98124453Speter * a user without an exec - programs cannot know *everything* 98224453Speter * that libc *might* have put in their data segment. 98324453Speter */ 98460216Speter p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 98524453Speter return (0); 98624453Speter} 98724453Speter 98875426Srwatsonint 98975426Srwatson__setugid(p, uap) 99075426Srwatson struct proc *p; 99175426Srwatson struct __setugid_args *uap; 99275426Srwatson{ 99375426Srwatson 99475426Srwatson#ifdef REGRESSION 99575426Srwatson switch (uap->flag) { 99675426Srwatson case 0: 99775426Srwatson p->p_flag &= ~P_SUGID; 99875426Srwatson return (0); 99975426Srwatson case 1: 100075426Srwatson p->p_flag |= P_SUGID; 100175426Srwatson return (0); 100275426Srwatson default: 100375426Srwatson return (EINVAL); 100475426Srwatson } 100575426Srwatson#else /* !REGRESSION */ 100675426Srwatson return (ENOSYS); 100775426Srwatson#endif /* !REGRESSION */ 100875426Srwatson} 100975426Srwatson 10101541Srgrimes/* 10111541Srgrimes * Check if gid is a member of the group set. 10121541Srgrimes */ 10131549Srgrimesint 10141541Srgrimesgroupmember(gid, cred) 10151541Srgrimes gid_t gid; 101677183Srwatson struct ucred *cred; 10171541Srgrimes{ 10181541Srgrimes register gid_t *gp; 10191541Srgrimes gid_t *egp; 10201541Srgrimes 10211541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 10221541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 10231541Srgrimes if (*gp == gid) 10241541Srgrimes return (1); 10251541Srgrimes return (0); 10261541Srgrimes} 10271541Srgrimes 102861287Srwatsonstatic int suser_permitted = 1; 102961287Srwatson 103061287SrwatsonSYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 103161287Srwatson "processes with uid 0 have privilege"); 103261287Srwatson 10331541Srgrimes/* 10341541Srgrimes * Test whether the specified credentials imply "super-user" 10351541Srgrimes * privilege; if so, and we have accounting info, set the flag 10361541Srgrimes * indicating use of super-powers. 10371541Srgrimes * Returns 0 or error. 10381541Srgrimes */ 10391549Srgrimesint 104046112Sphksuser(p) 104172786Srwatson struct proc *p; 104246112Sphk{ 104346155Sphk return suser_xxx(0, p, 0); 104446112Sphk} 104546112Sphk 104646112Sphkint 104746155Sphksuser_xxx(cred, proc, flag) 104872786Srwatson struct ucred *cred; 104972786Srwatson struct proc *proc; 105046155Sphk int flag; 10511541Srgrimes{ 105261282Srwatson if (!suser_permitted) 105361282Srwatson return (EPERM); 105446155Sphk if (!cred && !proc) { 105546155Sphk printf("suser_xxx(): THINK!\n"); 105646155Sphk return (EPERM); 10571541Srgrimes } 105846155Sphk if (!cred) 105946155Sphk cred = proc->p_ucred; 106046155Sphk if (cred->cr_uid != 0) 106146155Sphk return (EPERM); 106272786Srwatson if (jailed(cred) && !(flag & PRISON_ROOT)) 106346155Sphk return (EPERM); 106446155Sphk return (0); 10651541Srgrimes} 10661541Srgrimes 106774956Srwatson/* 106874956Srwatson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2 106974956Srwatson * Arguments: imutable credentials u1, u2 107074956Srwatson * Returns: 0 for permitted, an errno value otherwise 107174956Srwatson * Locks: none 107274956Srwatson * References: u1 and u2 must be valid for the lifetime of the call 107374956Srwatson * u1 may equal u2, in which case only one reference is required 107474956Srwatson */ 107574956Srwatsonint 107674956Srwatsonu_cansee(struct ucred *u1, struct ucred *u2) 107765237Srwatson{ 107872786Srwatson int error; 107953518Sphk 108074956Srwatson if ((error = prison_check(u1, u2))) 108172786Srwatson return (error); 108277183Srwatson if (!ps_showallprocs && u1->cr_ruid != u2->cr_ruid) { 108375005Srwatson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 108474956Srwatson return (ESRCH); 108565293Srwatson } 108665237Srwatson return (0); 108765237Srwatson} 108865237Srwatson 108979335Srwatsonint 109079335Srwatsonp_cansee(struct proc *p1, struct proc *p2) 109174956Srwatson{ 109274956Srwatson 109374956Srwatson /* Wrap u_cansee() for all functionality. */ 109474956Srwatson return (u_cansee(p1->p_ucred, p2->p_ucred)); 109574956Srwatson} 109674956Srwatson 109775437Srwatson/* 109875437Srwatson * Can process p1 send the signal signum to process p2? 109975437Srwatson */ 110075437Srwatsonint 110175437Srwatsonp_cansignal(struct proc *p1, struct proc *p2, int signum) 110253518Sphk{ 110375437Srwatson int error; 110475437Srwatson 110553518Sphk if (p1 == p2) 110653518Sphk return (0); 110765237Srwatson 110875437Srwatson /* 110975437Srwatson * Jail semantics limit the scope of signalling to p2 in the same 111075437Srwatson * jail as p1, if p1 is in jail. 111175437Srwatson */ 111272786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 111372786Srwatson return (error); 111465237Srwatson 111565237Srwatson /* 111675437Srwatson * UNIX signalling semantics require that processes in the same 111775437Srwatson * session always be able to deliver SIGCONT to one another, 111875437Srwatson * overriding the remaining protections. 111965237Srwatson */ 112075437Srwatson if (signum == SIGCONT && p1->p_session == p2->p_session) 112153518Sphk return (0); 112265237Srwatson 112375437Srwatson /* 112475437Srwatson * UNIX uid semantics depend on the status of the P_SUGID 112575437Srwatson * bit on the target process. If the bit is set, then more 112675437Srwatson * restricted signal sets are permitted. 112775437Srwatson */ 112875437Srwatson if (p2->p_flag & P_SUGID) { 112975437Srwatson switch (signum) { 113075437Srwatson case 0: 113175437Srwatson case SIGKILL: 113275437Srwatson case SIGINT: 113375437Srwatson case SIGTERM: 113475437Srwatson case SIGSTOP: 113575437Srwatson case SIGTTIN: 113675437Srwatson case SIGTTOU: 113775437Srwatson case SIGTSTP: 113875437Srwatson case SIGHUP: 113975437Srwatson case SIGUSR1: 114075437Srwatson case SIGUSR2: 114175437Srwatson break; 114275437Srwatson default: 114375437Srwatson /* Not permitted, try privilege. */ 114475437Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 114575437Srwatson if (error) 114675437Srwatson return (error); 114775437Srwatson } 114865237Srwatson } 114965237Srwatson 115075480Srwatson /* 115175480Srwatson * Generally, the object credential's ruid or svuid must match the 115275480Srwatson * subject credential's ruid or euid. 115375480Srwatson */ 115477183Srwatson if (p1->p_ucred->cr_ruid != p2->p_ucred->cr_ruid && 115577183Srwatson p1->p_ucred->cr_ruid != p2->p_ucred->cr_svuid && 115677183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid && 115777183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid) { 115875480Srwatson /* Not permitted, try privilege. */ 115975480Srwatson error = suser_xxx(NULL, p1, PRISON_ROOT); 116075480Srwatson if (error) 116175480Srwatson return (error); 116275480Srwatson } 116375480Srwatson 116475437Srwatson return (0); 116553518Sphk} 116653518Sphk 116779335Srwatsonint 116879335Srwatsonp_cansched(struct proc *p1, struct proc *p2) 116965237Srwatson{ 117072786Srwatson int error; 117165237Srwatson 117265237Srwatson if (p1 == p2) 117365237Srwatson return (0); 117465237Srwatson 117572786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 117672786Srwatson return (error); 117765237Srwatson 117877183Srwatson if (p1->p_ucred->cr_ruid == p2->p_ucred->cr_ruid) 117965237Srwatson return (0); 118077183Srwatson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_ruid) 118165237Srwatson return (0); 118265237Srwatson 118379335Srwatson if (!suser_xxx(0, p1, PRISON_ROOT)) 118465237Srwatson return (0); 118565237Srwatson 118665237Srwatson#ifdef CAPABILITIES 118779335Srwatson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) 118865237Srwatson return (0); 118965237Srwatson#endif 119065237Srwatson 119165237Srwatson return (EPERM); 119265237Srwatson} 119365237Srwatson 119479335Srwatsonint 119579335Srwatsonp_candebug(struct proc *p1, struct proc *p2) 119665237Srwatson{ 119772786Srwatson int error; 119865237Srwatson 119965237Srwatson if (p1 == p2) 120065237Srwatson return (0); 120165237Srwatson 120272786Srwatson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 120372786Srwatson return (error); 120465237Srwatson 120565237Srwatson /* not owned by you, has done setuid (unless you're root) */ 120665237Srwatson /* add a CAP_SYS_PTRACE here? */ 120777183Srwatson if (p1->p_ucred->cr_uid != p2->p_ucred->cr_uid || 120877183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_svuid || 120977183Srwatson p1->p_ucred->cr_uid != p2->p_ucred->cr_ruid || 121079335Srwatson p2->p_flag & P_SUGID) 121165237Srwatson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 121265237Srwatson return (error); 121365237Srwatson 121465237Srwatson /* can't trace init when securelevel > 0 */ 121565237Srwatson if (securelevel > 0 && p2->p_pid == 1) 121665237Srwatson return (EPERM); 121765237Srwatson 121865237Srwatson return (0); 121965237Srwatson} 122065237Srwatson 122153518Sphk/* 12221541Srgrimes * Allocate a zeroed cred structure. 12231541Srgrimes */ 12241541Srgrimesstruct ucred * 12251541Srgrimescrget() 12261541Srgrimes{ 12271541Srgrimes register struct ucred *cr; 12281541Srgrimes 122969239Salfred MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 12301541Srgrimes cr->cr_ref = 1; 123169239Salfred mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 12321541Srgrimes return (cr); 12331541Srgrimes} 12341541Srgrimes 12351541Srgrimes/* 123672474Srwatson * Claim another reference to a ucred structure 123769401Salfred */ 123869401Salfredvoid 123969401Salfredcrhold(cr) 124069401Salfred struct ucred *cr; 124169401Salfred{ 124269401Salfred 124372200Sbmilekic mtx_lock(&cr->cr_mtx); 124469401Salfred cr->cr_ref++; 124572200Sbmilekic mtx_unlock(&(cr)->cr_mtx); 124669401Salfred} 124769401Salfred 124869401Salfred 124969401Salfred/* 12501541Srgrimes * Free a cred structure. 12511541Srgrimes * Throws away space when ref count gets to 0. 12521541Srgrimes */ 12531549Srgrimesvoid 12541541Srgrimescrfree(cr) 12551541Srgrimes struct ucred *cr; 12561541Srgrimes{ 125769239Salfred 125872200Sbmilekic mtx_lock(&cr->cr_mtx); 125975632Salfred KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 126065495Struckman if (--cr->cr_ref == 0) { 126169239Salfred mtx_destroy(&cr->cr_mtx); 126265495Struckman /* 126365495Struckman * Some callers of crget(), such as nfs_statfs(), 126465495Struckman * allocate a temporary credential, but don't 126565495Struckman * allocate a uidinfo structure. 126665495Struckman */ 126765495Struckman if (cr->cr_uidinfo != NULL) 126865495Struckman uifree(cr->cr_uidinfo); 126977277Srwatson if (cr->cr_ruidinfo != NULL) 127077277Srwatson uifree(cr->cr_ruidinfo); 127172786Srwatson /* 127272786Srwatson * Free a prison, if any. 127372786Srwatson */ 127472786Srwatson if (jailed(cr)) 127572786Srwatson prison_free(cr->cr_prison); 12761541Srgrimes FREE((caddr_t)cr, M_CRED); 127769239Salfred } else { 127872200Sbmilekic mtx_unlock(&cr->cr_mtx); 127965495Struckman } 12801541Srgrimes} 12811541Srgrimes 12821541Srgrimes/* 12831541Srgrimes * Copy cred structure to a new one and free the old one. 12841541Srgrimes */ 12851541Srgrimesstruct ucred * 12861541Srgrimescrcopy(cr) 12871541Srgrimes struct ucred *cr; 12881541Srgrimes{ 12891541Srgrimes struct ucred *newcr; 12901541Srgrimes 129172200Sbmilekic mtx_lock(&cr->cr_mtx); 129269239Salfred if (cr->cr_ref == 1) { 129372200Sbmilekic mtx_unlock(&cr->cr_mtx); 12941541Srgrimes return (cr); 129569239Salfred } 129672200Sbmilekic mtx_unlock(&cr->cr_mtx); 129769239Salfred newcr = crdup(cr); 12981541Srgrimes crfree(cr); 12991541Srgrimes return (newcr); 13001541Srgrimes} 13011541Srgrimes 13021541Srgrimes/* 13031541Srgrimes * Dup cred struct to a new held one. 13041541Srgrimes */ 13051541Srgrimesstruct ucred * 13061541Srgrimescrdup(cr) 13071541Srgrimes struct ucred *cr; 13081541Srgrimes{ 13091541Srgrimes struct ucred *newcr; 13101541Srgrimes 131169239Salfred MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 13121541Srgrimes *newcr = *cr; 131369239Salfred mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 131465495Struckman uihold(newcr->cr_uidinfo); 131577183Srwatson uihold(newcr->cr_ruidinfo); 131672786Srwatson if (jailed(newcr)) 131772786Srwatson prison_hold(newcr->cr_prison); 13181541Srgrimes newcr->cr_ref = 1; 13191541Srgrimes return (newcr); 13201541Srgrimes} 13211541Srgrimes 13221541Srgrimes/* 13231541Srgrimes * Get login name, if available. 13241541Srgrimes */ 132512221Sbde#ifndef _SYS_SYSPROTO_H_ 13261541Srgrimesstruct getlogin_args { 13271541Srgrimes char *namebuf; 13281541Srgrimes u_int namelen; 13291541Srgrimes}; 133012221Sbde#endif 13311541Srgrimes/* ARGSUSED */ 13321549Srgrimesint 133330994Sphkgetlogin(p, uap) 13341541Srgrimes struct proc *p; 13351541Srgrimes struct getlogin_args *uap; 13361541Srgrimes{ 13371541Srgrimes 133823358Sache if (uap->namelen > MAXLOGNAME) 133923359Sache uap->namelen = MAXLOGNAME; 13401541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 13411541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 13421541Srgrimes} 13431541Srgrimes 13441541Srgrimes/* 13451541Srgrimes * Set login name. 13461541Srgrimes */ 134712221Sbde#ifndef _SYS_SYSPROTO_H_ 13481541Srgrimesstruct setlogin_args { 13491541Srgrimes char *namebuf; 13501541Srgrimes}; 135112221Sbde#endif 13521541Srgrimes/* ARGSUSED */ 13531549Srgrimesint 135430994Sphksetlogin(p, uap) 13551541Srgrimes struct proc *p; 13561541Srgrimes struct setlogin_args *uap; 13571541Srgrimes{ 13581541Srgrimes int error; 135923330Sache char logintmp[MAXLOGNAME]; 13601541Srgrimes 136146155Sphk if ((error = suser_xxx(0, p, PRISON_ROOT))) 13621541Srgrimes return (error); 136322522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 136436845Sdfr sizeof(logintmp), (size_t *)0); 13651541Srgrimes if (error == ENAMETOOLONG) 13661541Srgrimes error = EINVAL; 136722522Sdavidn else if (!error) 136822522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 136923330Sache sizeof(logintmp)); 13701541Srgrimes return (error); 13711541Srgrimes} 137231891Ssef 137331891Ssefvoid 137431891Ssefsetsugid(p) 137555338Sphk struct proc *p; 137631891Ssef{ 137731891Ssef p->p_flag |= P_SUGID; 137855707Ssef if (!(p->p_pfsflags & PF_ISUGID)) 137931891Ssef p->p_stops = 0; 138031891Ssef} 138165495Struckman 138265495Struckman/* 138377183Srwatson * change_euid(): Change a process's effective uid. 138477183Srwatson * Side effects: newcred->cr_uid and newcred->cr_uidinfo will be modified. 138577183Srwatson * References: newcred must be an exclusive credential reference for the 138677183Srwatson * duration of the call. 138765495Struckman */ 138865495Struckmanvoid 138977183Srwatsonchange_euid(newcred, euid) 139077183Srwatson struct ucred *newcred; 139177183Srwatson uid_t euid; 139265495Struckman{ 139365495Struckman 139477183Srwatson newcred->cr_uid = euid; 139577183Srwatson uifree(newcred->cr_uidinfo); 139677183Srwatson newcred->cr_uidinfo = uifind(euid); 139765495Struckman} 139865495Struckman 139965495Struckman/* 140077183Srwatson * change_egid(): Change a process's effective gid. 140177183Srwatson * Side effects: newcred->cr_gid will be modified. 140277183Srwatson * References: newcred must be an exclusive credential reference for the 140377183Srwatson * duration of the call. 140465495Struckman */ 140567629Sgallatinvoid 140677183Srwatsonchange_egid(newcred, egid) 140777183Srwatson struct ucred *newcred; 140877183Srwatson gid_t egid; 140965495Struckman{ 141065495Struckman 141177183Srwatson newcred->cr_groups[0] = egid; 141265495Struckman} 141377183Srwatson 141477183Srwatson/* 141577183Srwatson * change_ruid(): Change a process's real uid. 141677183Srwatson * Side effects: newcred->cr_ruid will be updated, newcred->cr_ruidinfo 141777183Srwatson * will be updated, and the old and new cr_ruidinfo proc 141877183Srwatson * counts will be updated. 141977183Srwatson * References: newcred must be an exclusive credential reference for the 142077183Srwatson * duration of the call. 142177183Srwatson */ 142277183Srwatsonvoid 142377183Srwatsonchange_ruid(newcred, ruid) 142477183Srwatson struct ucred *newcred; 142577183Srwatson uid_t ruid; 142677183Srwatson{ 142777183Srwatson 142877183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, -1, 0); 142977183Srwatson newcred->cr_ruid = ruid; 143077183Srwatson uifree(newcred->cr_ruidinfo); 143177183Srwatson newcred->cr_ruidinfo = uifind(ruid); 143277183Srwatson (void)chgproccnt(newcred->cr_ruidinfo, 1, 0); 143377183Srwatson} 143477183Srwatson 143577183Srwatson/* 143677183Srwatson * change_rgid(): Change a process's real gid. 143777183Srwatson * Side effects: newcred->cr_rgid will be updated. 143877183Srwatson * References: newcred must be an exclusive credential reference for the 143977183Srwatson * duration of the call. 144077183Srwatson */ 144177183Srwatsonvoid 144277183Srwatsonchange_rgid(newcred, rgid) 144377183Srwatson struct ucred *newcred; 144477183Srwatson gid_t rgid; 144577183Srwatson{ 144677183Srwatson 144777183Srwatson newcred->cr_rgid = rgid; 144877183Srwatson} 144977183Srwatson 145077183Srwatson/* 145177183Srwatson * change_svuid(): Change a process's saved uid. 145277183Srwatson * Side effects: newcred->cr_svuid will be updated. 145377183Srwatson * References: newcred must be an exclusive credential reference for the 145477183Srwatson * duration of the call. 145577183Srwatson */ 145677183Srwatsonvoid 145777183Srwatsonchange_svuid(newcred, svuid) 145877183Srwatson struct ucred *newcred; 145977183Srwatson uid_t svuid; 146077183Srwatson{ 146177183Srwatson 146277183Srwatson newcred->cr_svuid = svuid; 146377183Srwatson} 146477183Srwatson 146577183Srwatson/* 146677183Srwatson * change_svgid(): Change a process's saved gid. 146777183Srwatson * Side effects: newcred->cr_svgid will be updated. 146877183Srwatson * References: newcred must be an exclusive credential reference for the 146977183Srwatson * duration of the call. 147077183Srwatson */ 147177183Srwatsonvoid 147277183Srwatsonchange_svgid(newcred, svgid) 147377183Srwatson struct ucred *newcred; 147477183Srwatson gid_t svgid; 147577183Srwatson{ 147677183Srwatson 147777183Srwatson newcred->cr_svgid = svgid; 147877183Srwatson} 1479