kern_prot.c revision 41726
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 3941726Struckman * $Id: kern_prot.c,v 1.42 1998/11/10 09:16:29 peter Exp $ 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> 531541Srgrimes#include <sys/proc.h> 541541Srgrimes#include <sys/malloc.h> 5518013Sbde#include <sys/unistd.h> 5631891Ssef#include <sys/pioctl.h> 571541Srgrimes 5830354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 5930354Sphk 6012221Sbde#ifndef _SYS_SYSPROTO_H_ 6111332Sswallacestruct getpid_args { 621541Srgrimes int dummy; 631541Srgrimes}; 6412221Sbde#endif 651541Srgrimes 661541Srgrimes/* ARGSUSED */ 671549Srgrimesint 6830994Sphkgetpid(p, uap) 691541Srgrimes struct proc *p; 7011332Sswallace struct getpid_args *uap; 711541Srgrimes{ 721541Srgrimes 7330994Sphk p->p_retval[0] = p->p_pid; 741541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 7530994Sphk p->p_retval[1] = p->p_pptr->p_pid; 761541Srgrimes#endif 771541Srgrimes return (0); 781541Srgrimes} 791541Srgrimes 8012221Sbde#ifndef _SYS_SYSPROTO_H_ 8111332Sswallacestruct getppid_args { 8211332Sswallace int dummy; 8311332Sswallace}; 8412221Sbde#endif 851541Srgrimes/* ARGSUSED */ 861549Srgrimesint 8730994Sphkgetppid(p, uap) 881541Srgrimes struct proc *p; 8911332Sswallace struct getppid_args *uap; 901541Srgrimes{ 911541Srgrimes 9230994Sphk p->p_retval[0] = p->p_pptr->p_pid; 931541Srgrimes return (0); 941541Srgrimes} 951541Srgrimes 961541Srgrimes/* Get process group ID; note that POSIX getpgrp takes no parameter */ 9712221Sbde#ifndef _SYS_SYSPROTO_H_ 9811332Sswallacestruct getpgrp_args { 9911332Sswallace int dummy; 10011332Sswallace}; 10112221Sbde#endif 10211332Sswallace 1031549Srgrimesint 10430994Sphkgetpgrp(p, uap) 1051541Srgrimes struct proc *p; 10611332Sswallace struct getpgrp_args *uap; 1071541Srgrimes{ 1081541Srgrimes 10930994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1101541Srgrimes return (0); 1111541Srgrimes} 1121541Srgrimes 11328401Speter/* Get an arbitary pid's process group id */ 11412221Sbde#ifndef _SYS_SYSPROTO_H_ 11528401Speterstruct getpgid_args { 11628401Speter pid_t pid; 11728401Speter}; 11828401Speter#endif 11928401Speter 12028401Speterint 12130994Sphkgetpgid(p, uap) 12228401Speter struct proc *p; 12328401Speter struct getpgid_args *uap; 12428401Speter{ 12541726Struckman struct proc *pt; 12641726Struckman 12741726Struckman pt = p; 12828401Speter if (uap->pid == 0) 12928401Speter goto found; 13028401Speter 13141726Struckman if ((pt = pfind(uap->pid)) == 0) 13228401Speter return ESRCH; 13328401Speterfound: 13441726Struckman p->p_retval[0] = pt->p_pgrp->pg_id; 13528401Speter return 0; 13628401Speter} 13728401Speter 13828401Speter/* 13928401Speter * Get an arbitary pid's session id. 14028401Speter */ 14128401Speter#ifndef _SYS_SYSPROTO_H_ 14228401Speterstruct getsid_args { 14328401Speter pid_t pid; 14428401Speter}; 14528401Speter#endif 14628401Speter 14728401Speterint 14830994Sphkgetsid(p, uap) 14928401Speter struct proc *p; 15028401Speter struct getsid_args *uap; 15128401Speter{ 15241726Struckman struct proc *pt; 15341726Struckman 15441726Struckman pt = p; 15528401Speter if (uap->pid == 0) 15628401Speter goto found; 15728401Speter 15841726Struckman if ((pt == pfind(uap->pid)) == 0) 15928401Speter return ESRCH; 16028401Speterfound: 16141726Struckman p->p_retval[0] = pt->p_session->s_sid; 16228401Speter return 0; 16328401Speter} 16428401Speter 16528401Speter 16628401Speter#ifndef _SYS_SYSPROTO_H_ 16711332Sswallacestruct getuid_args { 16811332Sswallace int dummy; 16911332Sswallace}; 17012221Sbde#endif 17111332Sswallace 1721541Srgrimes/* ARGSUSED */ 1731549Srgrimesint 17430994Sphkgetuid(p, uap) 1751541Srgrimes struct proc *p; 17611332Sswallace struct getuid_args *uap; 1771541Srgrimes{ 1781541Srgrimes 17930994Sphk p->p_retval[0] = p->p_cred->p_ruid; 1801541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 18130994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 1821541Srgrimes#endif 1831541Srgrimes return (0); 1841541Srgrimes} 1851541Srgrimes 18612221Sbde#ifndef _SYS_SYSPROTO_H_ 18711332Sswallacestruct geteuid_args { 18811332Sswallace int dummy; 18911332Sswallace}; 19012221Sbde#endif 19111332Sswallace 1921541Srgrimes/* ARGSUSED */ 1931549Srgrimesint 19430994Sphkgeteuid(p, uap) 1951541Srgrimes struct proc *p; 19611332Sswallace struct geteuid_args *uap; 1971541Srgrimes{ 1981541Srgrimes 19930994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 2001541Srgrimes return (0); 2011541Srgrimes} 2021541Srgrimes 20312221Sbde#ifndef _SYS_SYSPROTO_H_ 20411332Sswallacestruct getgid_args { 20511332Sswallace int dummy; 20611332Sswallace}; 20712221Sbde#endif 20811332Sswallace 2091541Srgrimes/* ARGSUSED */ 2101549Srgrimesint 21130994Sphkgetgid(p, uap) 2121541Srgrimes struct proc *p; 21311332Sswallace struct getgid_args *uap; 2141541Srgrimes{ 2151541Srgrimes 21630994Sphk p->p_retval[0] = p->p_cred->p_rgid; 2171541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 21830994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2191541Srgrimes#endif 2201541Srgrimes return (0); 2211541Srgrimes} 2221541Srgrimes 2231541Srgrimes/* 2241541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2251541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2261541Srgrimes * correctly in a library function. 2271541Srgrimes */ 22812221Sbde#ifndef _SYS_SYSPROTO_H_ 22911332Sswallacestruct getegid_args { 23011332Sswallace int dummy; 23111332Sswallace}; 23212221Sbde#endif 23311332Sswallace 2341541Srgrimes/* ARGSUSED */ 2351549Srgrimesint 23630994Sphkgetegid(p, uap) 2371541Srgrimes struct proc *p; 23811332Sswallace struct getegid_args *uap; 2391541Srgrimes{ 2401541Srgrimes 24130994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2421541Srgrimes return (0); 2431541Srgrimes} 2441541Srgrimes 24512221Sbde#ifndef _SYS_SYSPROTO_H_ 2461541Srgrimesstruct getgroups_args { 2471541Srgrimes u_int gidsetsize; 2481541Srgrimes gid_t *gidset; 2491541Srgrimes}; 25012221Sbde#endif 2511549Srgrimesint 25230994Sphkgetgroups(p, uap) 2531541Srgrimes struct proc *p; 2541541Srgrimes register struct getgroups_args *uap; 2551541Srgrimes{ 2561541Srgrimes register struct pcred *pc = p->p_cred; 2571541Srgrimes register u_int ngrp; 2581541Srgrimes int error; 2591541Srgrimes 2601541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 26130994Sphk p->p_retval[0] = pc->pc_ucred->cr_ngroups; 2621541Srgrimes return (0); 2631541Srgrimes } 2641541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 2651541Srgrimes return (EINVAL); 2661541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 2673098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 2683098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 2691541Srgrimes return (error); 27030994Sphk p->p_retval[0] = ngrp; 2711541Srgrimes return (0); 2721541Srgrimes} 2731541Srgrimes 27412221Sbde#ifndef _SYS_SYSPROTO_H_ 27512207Sbdestruct setsid_args { 27611332Sswallace int dummy; 27711332Sswallace}; 27812221Sbde#endif 27911332Sswallace 2801541Srgrimes/* ARGSUSED */ 2811549Srgrimesint 28230994Sphksetsid(p, uap) 2831541Srgrimes register struct proc *p; 28412207Sbde struct setsid_args *uap; 2851541Srgrimes{ 2861541Srgrimes 2871541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 2881541Srgrimes return (EPERM); 2891541Srgrimes } else { 2901541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 29130994Sphk p->p_retval[0] = p->p_pid; 2921541Srgrimes return (0); 2931541Srgrimes } 2941541Srgrimes} 2951541Srgrimes 2961541Srgrimes/* 2971541Srgrimes * set process group (setpgid/old setpgrp) 2981541Srgrimes * 2991541Srgrimes * caller does setpgid(targpid, targpgid) 3001541Srgrimes * 3011541Srgrimes * pid must be caller or child of caller (ESRCH) 3021541Srgrimes * if a child 3031541Srgrimes * pid must be in same session (EPERM) 3041541Srgrimes * pid can't have done an exec (EACCES) 3051541Srgrimes * if pgid != pid 3061541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3071541Srgrimes * pid must not be session leader (EPERM) 3081541Srgrimes */ 30912221Sbde#ifndef _SYS_SYSPROTO_H_ 3101541Srgrimesstruct setpgid_args { 3111541Srgrimes int pid; /* target process id */ 3121541Srgrimes int pgid; /* target pgrp id */ 3131541Srgrimes}; 31412221Sbde#endif 3151541Srgrimes/* ARGSUSED */ 3161549Srgrimesint 31730994Sphksetpgid(curp, uap) 3181541Srgrimes struct proc *curp; 3191541Srgrimes register struct setpgid_args *uap; 3201541Srgrimes{ 3211541Srgrimes register struct proc *targp; /* target process */ 3221541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 3231541Srgrimes 32420677Sbde if (uap->pgid < 0) 32520677Sbde return (EINVAL); 3261541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 3271541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 3281541Srgrimes return (ESRCH); 32915985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 3301541Srgrimes return (EPERM); 3311541Srgrimes if (targp->p_flag & P_EXEC) 3321541Srgrimes return (EACCES); 3331541Srgrimes } else 3341541Srgrimes targp = curp; 3351541Srgrimes if (SESS_LEADER(targp)) 3361541Srgrimes return (EPERM); 3371541Srgrimes if (uap->pgid == 0) 3381541Srgrimes uap->pgid = targp->p_pid; 3391541Srgrimes else if (uap->pgid != targp->p_pid) 3401541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 3411541Srgrimes pgrp->pg_session != curp->p_session) 3421541Srgrimes return (EPERM); 3431541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 3441541Srgrimes} 3451541Srgrimes 34624448Speter/* 34724448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 34824448Speter * compatable. It says that setting the uid/gid to euid/egid is a special 34924448Speter * case of "appropriate privilege". Once the rules are expanded out, this 35024448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 35124448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 35224448Speter * does not set the saved id - this is dangerous for traditional BSD 35324448Speter * programs. For this reason, we *really* do not want to set 35424448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 35524448Speter */ 35624448Speter#define POSIX_APPENDIX_B_4_2_2 35724448Speter 35812221Sbde#ifndef _SYS_SYSPROTO_H_ 3591541Srgrimesstruct setuid_args { 3601541Srgrimes uid_t uid; 3611541Srgrimes}; 36212221Sbde#endif 3631541Srgrimes/* ARGSUSED */ 3641549Srgrimesint 36530994Sphksetuid(p, uap) 3661541Srgrimes struct proc *p; 3671541Srgrimes struct setuid_args *uap; 3681541Srgrimes{ 3691541Srgrimes register struct pcred *pc = p->p_cred; 3701541Srgrimes register uid_t uid; 3711541Srgrimes int error; 3721541Srgrimes 37324448Speter /* 37424448Speter * See if we have "permission" by POSIX 1003.1 rules. 37524448Speter * 37624448Speter * Note that setuid(geteuid()) is a special case of 37724448Speter * "appropriate privileges" in appendix B.4.2.2. We need 37824448Speter * to use this clause to be compatable with traditional BSD 37924448Speter * semantics. Basically, it means that "setuid(xx)" sets all 38024448Speter * three id's (assuming you have privs). 38124448Speter * 38224448Speter * Notes on the logic. We do things in three steps. 38324448Speter * 1: We determine if the euid is going to change, and do EPERM 38424448Speter * right away. We unconditionally change the euid later if this 38524448Speter * test is satisfied, simplifying that part of the logic. 38624448Speter * 2: We determine if the real and/or saved uid's are going to 38724448Speter * change. Determined by compile options. 38824448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 38924448Speter */ 3901541Srgrimes uid = uap->uid; 39124448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 39217994Sache#ifdef _POSIX_SAVED_IDS 39324448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 39417994Sache#endif 39524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 39624448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 39724448Speter#endif 3988162Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 3991541Srgrimes return (error); 40024448Speter 40124448Speter#ifdef _POSIX_SAVED_IDS 4021541Srgrimes /* 40324448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 40424448Speter * If so, we are changing the real uid and/or saved uid. 4051541Srgrimes */ 40617994Sache if ( 40724448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 40824448Speter uid == pc->pc_ucred->cr_uid || 40917994Sache#endif 41024448Speter suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 41117994Sache#endif 41224448Speter { 41324448Speter /* 41424448Speter * Transfer proc count to new user. 41524448Speter */ 41624448Speter if (uid != pc->p_ruid) { 41724448Speter (void)chgproccnt(pc->p_ruid, -1); 41824448Speter (void)chgproccnt(uid, 1); 41924448Speter } 42024448Speter /* 42124448Speter * Set real uid 42224448Speter */ 42324448Speter if (uid != pc->p_ruid) { 42424448Speter pc->p_ruid = uid; 42531891Ssef setsugid(p); 42624448Speter } 42724448Speter /* 42824448Speter * Set saved uid 42924448Speter * 43024448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 43124448Speter * the security of seteuid() depends on it. B.4.2.2 says it 43224448Speter * is important that we should do this. 43324448Speter */ 43424448Speter if (pc->p_svuid != uid) { 43524448Speter pc->p_svuid = uid; 43631891Ssef setsugid(p); 43724448Speter } 4388141Sache } 43924448Speter 44024448Speter /* 44124448Speter * In all permitted cases, we are changing the euid. 44224448Speter * Copy credentials so other references do not see our changes. 44324448Speter */ 44424448Speter if (pc->pc_ucred->cr_uid != uid) { 44524448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 44624448Speter pc->pc_ucred->cr_uid = uid; 44731891Ssef setsugid(p); 44824448Speter } 4491541Srgrimes return (0); 4501541Srgrimes} 4511541Srgrimes 45212221Sbde#ifndef _SYS_SYSPROTO_H_ 4531541Srgrimesstruct seteuid_args { 4541541Srgrimes uid_t euid; 4551541Srgrimes}; 45612221Sbde#endif 4571541Srgrimes/* ARGSUSED */ 4581549Srgrimesint 45930994Sphkseteuid(p, uap) 4601541Srgrimes struct proc *p; 4611541Srgrimes struct seteuid_args *uap; 4621541Srgrimes{ 4631541Srgrimes register struct pcred *pc = p->p_cred; 4641541Srgrimes register uid_t euid; 4651541Srgrimes int error; 4661541Srgrimes 4671541Srgrimes euid = uap->euid; 46824449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 46924449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 4701541Srgrimes (error = suser(pc->pc_ucred, &p->p_acflag))) 4711541Srgrimes return (error); 4721541Srgrimes /* 4731541Srgrimes * Everything's okay, do it. Copy credentials so other references do 4741541Srgrimes * not see our changes. 4751541Srgrimes */ 47624449Speter if (pc->pc_ucred->cr_uid != euid) { 47724449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 47824449Speter pc->pc_ucred->cr_uid = euid; 47931891Ssef setsugid(p); 48024449Speter } 4811541Srgrimes return (0); 4821541Srgrimes} 4831541Srgrimes 48412221Sbde#ifndef _SYS_SYSPROTO_H_ 4851541Srgrimesstruct setgid_args { 4861541Srgrimes gid_t gid; 4871541Srgrimes}; 48812221Sbde#endif 4891541Srgrimes/* ARGSUSED */ 4901549Srgrimesint 49130994Sphksetgid(p, uap) 4921541Srgrimes struct proc *p; 4931541Srgrimes struct setgid_args *uap; 4941541Srgrimes{ 4951541Srgrimes register struct pcred *pc = p->p_cred; 4961541Srgrimes register gid_t gid; 4971541Srgrimes int error; 4981541Srgrimes 49924448Speter /* 50024448Speter * See if we have "permission" by POSIX 1003.1 rules. 50124448Speter * 50224448Speter * Note that setgid(getegid()) is a special case of 50324448Speter * "appropriate privileges" in appendix B.4.2.2. We need 50424448Speter * to use this clause to be compatable with traditional BSD 50524448Speter * semantics. Basically, it means that "setgid(xx)" sets all 50624448Speter * three id's (assuming you have privs). 50724448Speter * 50824448Speter * For notes on the logic here, see setuid() above. 50924448Speter */ 5101541Srgrimes gid = uap->gid; 51124448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 51217994Sache#ifdef _POSIX_SAVED_IDS 51324448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 51417994Sache#endif 51524448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 51624448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 51724448Speter#endif 5188162Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 5191541Srgrimes return (error); 52024448Speter 52117994Sache#ifdef _POSIX_SAVED_IDS 52224448Speter /* 52324448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 52424448Speter * If so, we are changing the real uid and saved gid. 52524448Speter */ 52624448Speter if ( 52724448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 52824448Speter gid == pc->pc_ucred->cr_groups[0] || 52917994Sache#endif 53024448Speter suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 53124448Speter#endif 53224448Speter { 53324448Speter /* 53424448Speter * Set real gid 53524448Speter */ 53624448Speter if (pc->p_rgid != gid) { 53724448Speter pc->p_rgid = gid; 53831891Ssef setsugid(p); 53924448Speter } 54024448Speter /* 54124448Speter * Set saved gid 54224448Speter * 54324448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 54424448Speter * the security of setegid() depends on it. B.4.2.2 says it 54524448Speter * is important that we should do this. 54624448Speter */ 54724448Speter if (pc->p_svgid != gid) { 54824448Speter pc->p_svgid = gid; 54931891Ssef setsugid(p); 55024448Speter } 5518141Sache } 55224448Speter /* 55324448Speter * In all cases permitted cases, we are changing the egid. 55424448Speter * Copy credentials so other references do not see our changes. 55524448Speter */ 55624448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 55724448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 55824448Speter pc->pc_ucred->cr_groups[0] = gid; 55931891Ssef setsugid(p); 56024448Speter } 5611541Srgrimes return (0); 5621541Srgrimes} 5631541Srgrimes 56412221Sbde#ifndef _SYS_SYSPROTO_H_ 5651541Srgrimesstruct setegid_args { 5661541Srgrimes gid_t egid; 5671541Srgrimes}; 56812221Sbde#endif 5691541Srgrimes/* ARGSUSED */ 5701549Srgrimesint 57130994Sphksetegid(p, uap) 5721541Srgrimes struct proc *p; 5731541Srgrimes struct setegid_args *uap; 5741541Srgrimes{ 5751541Srgrimes register struct pcred *pc = p->p_cred; 5761541Srgrimes register gid_t egid; 5771541Srgrimes int error; 5781541Srgrimes 5791541Srgrimes egid = uap->egid; 58024449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 58124449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 5821541Srgrimes (error = suser(pc->pc_ucred, &p->p_acflag))) 5831541Srgrimes return (error); 58424449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 58524449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 58624449Speter pc->pc_ucred->cr_groups[0] = egid; 58731891Ssef setsugid(p); 58824449Speter } 5891541Srgrimes return (0); 5901541Srgrimes} 5911541Srgrimes 59212221Sbde#ifndef _SYS_SYSPROTO_H_ 5931541Srgrimesstruct setgroups_args { 5941541Srgrimes u_int gidsetsize; 5951541Srgrimes gid_t *gidset; 5961541Srgrimes}; 59712221Sbde#endif 5981541Srgrimes/* ARGSUSED */ 5991549Srgrimesint 60030994Sphksetgroups(p, uap) 6011541Srgrimes struct proc *p; 6021541Srgrimes struct setgroups_args *uap; 6031541Srgrimes{ 6041541Srgrimes register struct pcred *pc = p->p_cred; 6051541Srgrimes register u_int ngrp; 6061541Srgrimes int error; 6071541Srgrimes 6083098Sphk if ((error = suser(pc->pc_ucred, &p->p_acflag))) 6091541Srgrimes return (error); 61012063Sdg ngrp = uap->gidsetsize; 61124447Speter if (ngrp > NGROUPS) 6121541Srgrimes return (EINVAL); 61324447Speter /* 61424447Speter * XXX A little bit lazy here. We could test if anything has 61524447Speter * changed before crcopy() and setting P_SUGID. 61624447Speter */ 6171541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 61824447Speter if (ngrp < 1) { 61924447Speter /* 62024447Speter * setgroups(0, NULL) is a legitimate way of clearing the 62124447Speter * groups vector on non-BSD systems (which generally do not 62224447Speter * have the egid in the groups[0]). We risk security holes 62324447Speter * when running non-BSD software if we do not do the same. 62424447Speter */ 62524447Speter pc->pc_ucred->cr_ngroups = 1; 62624447Speter } else { 62724447Speter if ((error = copyin((caddr_t)uap->gidset, 62824447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 62924447Speter return (error); 63024447Speter pc->pc_ucred->cr_ngroups = ngrp; 63124447Speter } 63231891Ssef setsugid(p); 6331541Srgrimes return (0); 6341541Srgrimes} 6351541Srgrimes 63612221Sbde#ifndef _SYS_SYSPROTO_H_ 6371541Srgrimesstruct setreuid_args { 6389238Sache uid_t ruid; 6399238Sache uid_t euid; 6401541Srgrimes}; 64112221Sbde#endif 6421541Srgrimes/* ARGSUSED */ 6431549Srgrimesint 64430994Sphksetreuid(p, uap) 6451541Srgrimes register struct proc *p; 6461541Srgrimes struct setreuid_args *uap; 6471541Srgrimes{ 6481541Srgrimes register struct pcred *pc = p->p_cred; 6499238Sache register uid_t ruid, euid; 6508135Sache int error; 6511541Srgrimes 6529238Sache ruid = uap->ruid; 6539238Sache euid = uap->euid; 6549238Sache if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid || 65524559Speter euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 65624559Speter euid != pc->p_ruid && euid != pc->p_svuid) && 6578135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6588135Sache return (error); 6599238Sache 66024450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 66124450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6629238Sache pc->pc_ucred->cr_uid = euid; 66331891Ssef setsugid(p); 66424450Speter } 66524450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 6669238Sache (void)chgproccnt(pc->p_ruid, -1); 6679238Sache (void)chgproccnt(ruid, 1); 6689238Sache pc->p_ruid = ruid; 66931891Ssef setsugid(p); 6708135Sache } 67124559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 67224559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6738111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 67431891Ssef setsugid(p); 67524450Speter } 6768135Sache return (0); 6771541Srgrimes} 6781541Srgrimes 67912221Sbde#ifndef _SYS_SYSPROTO_H_ 6801541Srgrimesstruct setregid_args { 6819238Sache gid_t rgid; 6829238Sache gid_t egid; 6831541Srgrimes}; 68412221Sbde#endif 6851541Srgrimes/* ARGSUSED */ 6861549Srgrimesint 68730994Sphksetregid(p, uap) 6881541Srgrimes register struct proc *p; 6891541Srgrimes struct setregid_args *uap; 6901541Srgrimes{ 6911541Srgrimes register struct pcred *pc = p->p_cred; 6929238Sache register gid_t rgid, egid; 6938135Sache int error; 6941541Srgrimes 6959238Sache rgid = uap->rgid; 6969238Sache egid = uap->egid; 6979238Sache if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 69824559Speter egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 69924559Speter egid != pc->p_rgid && egid != pc->p_svgid) && 7008135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 7018135Sache return (error); 7029238Sache 70324450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 70424450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 7059238Sache pc->pc_ucred->cr_groups[0] = egid; 70631891Ssef setsugid(p); 70724450Speter } 70824450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 7099238Sache pc->p_rgid = rgid; 71031891Ssef setsugid(p); 71124450Speter } 71224559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 71324559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7148111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 71531891Ssef setsugid(p); 71624450Speter } 7178135Sache return (0); 7181541Srgrimes} 7191541Srgrimes 72024453Speter#ifndef _SYS_SYSPROTO_H_ 72124453Speterstruct issetugid_args { 72224453Speter int dummy; 72324453Speter}; 72424453Speter#endif 72524453Speter/* ARGSUSED */ 72624453Speterint 72730994Sphkissetugid(p, uap) 72824453Speter register struct proc *p; 72924453Speter struct issetugid_args *uap; 73024453Speter{ 73124453Speter /* 73224453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 73324453Speter * we use P_SUGID because we consider changing the owners as 73424453Speter * "tainting" as well. 73524453Speter * This is significant for procs that start as root and "become" 73624453Speter * a user without an exec - programs cannot know *everything* 73724453Speter * that libc *might* have put in their data segment. 73824453Speter */ 73924453Speter if (p->p_flag & P_SUGID) 74024453Speter return (1); 74124453Speter return (0); 74224453Speter} 74324453Speter 7441541Srgrimes/* 7451541Srgrimes * Check if gid is a member of the group set. 7461541Srgrimes */ 7471549Srgrimesint 7481541Srgrimesgroupmember(gid, cred) 7491541Srgrimes gid_t gid; 7501541Srgrimes register struct ucred *cred; 7511541Srgrimes{ 7521541Srgrimes register gid_t *gp; 7531541Srgrimes gid_t *egp; 7541541Srgrimes 7551541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 7561541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 7571541Srgrimes if (*gp == gid) 7581541Srgrimes return (1); 7591541Srgrimes return (0); 7601541Srgrimes} 7611541Srgrimes 7621541Srgrimes/* 7631541Srgrimes * Test whether the specified credentials imply "super-user" 7641541Srgrimes * privilege; if so, and we have accounting info, set the flag 7651541Srgrimes * indicating use of super-powers. 7661541Srgrimes * Returns 0 or error. 7671541Srgrimes */ 7681549Srgrimesint 7691541Srgrimessuser(cred, acflag) 7701541Srgrimes struct ucred *cred; 7718011Sbde u_short *acflag; 7721541Srgrimes{ 7731541Srgrimes if (cred->cr_uid == 0) { 7741541Srgrimes if (acflag) 7751541Srgrimes *acflag |= ASU; 7761541Srgrimes return (0); 7771541Srgrimes } 7781541Srgrimes return (EPERM); 7791541Srgrimes} 7801541Srgrimes 7811541Srgrimes/* 7821541Srgrimes * Allocate a zeroed cred structure. 7831541Srgrimes */ 7841541Srgrimesstruct ucred * 7851541Srgrimescrget() 7861541Srgrimes{ 7871541Srgrimes register struct ucred *cr; 7881541Srgrimes 7891541Srgrimes MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 7901541Srgrimes bzero((caddr_t)cr, sizeof(*cr)); 7911541Srgrimes cr->cr_ref = 1; 7921541Srgrimes return (cr); 7931541Srgrimes} 7941541Srgrimes 7951541Srgrimes/* 7961541Srgrimes * Free a cred structure. 7971541Srgrimes * Throws away space when ref count gets to 0. 7981541Srgrimes */ 7991549Srgrimesvoid 8001541Srgrimescrfree(cr) 8011541Srgrimes struct ucred *cr; 8021541Srgrimes{ 8031541Srgrimes if (--cr->cr_ref == 0) 8041541Srgrimes FREE((caddr_t)cr, M_CRED); 8051541Srgrimes} 8061541Srgrimes 8071541Srgrimes/* 8081541Srgrimes * Copy cred structure to a new one and free the old one. 8091541Srgrimes */ 8101541Srgrimesstruct ucred * 8111541Srgrimescrcopy(cr) 8121541Srgrimes struct ucred *cr; 8131541Srgrimes{ 8141541Srgrimes struct ucred *newcr; 8151541Srgrimes 8161541Srgrimes if (cr->cr_ref == 1) 8171541Srgrimes return (cr); 8181541Srgrimes newcr = crget(); 8191541Srgrimes *newcr = *cr; 8201541Srgrimes crfree(cr); 8211541Srgrimes newcr->cr_ref = 1; 8221541Srgrimes return (newcr); 8231541Srgrimes} 8241541Srgrimes 8251541Srgrimes/* 8261541Srgrimes * Dup cred struct to a new held one. 8271541Srgrimes */ 8281541Srgrimesstruct ucred * 8291541Srgrimescrdup(cr) 8301541Srgrimes struct ucred *cr; 8311541Srgrimes{ 8321541Srgrimes struct ucred *newcr; 8331541Srgrimes 8341541Srgrimes newcr = crget(); 8351541Srgrimes *newcr = *cr; 8361541Srgrimes newcr->cr_ref = 1; 8371541Srgrimes return (newcr); 8381541Srgrimes} 8391541Srgrimes 8401541Srgrimes/* 8411541Srgrimes * Get login name, if available. 8421541Srgrimes */ 84312221Sbde#ifndef _SYS_SYSPROTO_H_ 8441541Srgrimesstruct getlogin_args { 8451541Srgrimes char *namebuf; 8461541Srgrimes u_int namelen; 8471541Srgrimes}; 84812221Sbde#endif 8491541Srgrimes/* ARGSUSED */ 8501549Srgrimesint 85130994Sphkgetlogin(p, uap) 8521541Srgrimes struct proc *p; 8531541Srgrimes struct getlogin_args *uap; 8541541Srgrimes{ 8551541Srgrimes 85623358Sache if (uap->namelen > MAXLOGNAME) 85723359Sache uap->namelen = MAXLOGNAME; 8581541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 8591541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 8601541Srgrimes} 8611541Srgrimes 8621541Srgrimes/* 8631541Srgrimes * Set login name. 8641541Srgrimes */ 86512221Sbde#ifndef _SYS_SYSPROTO_H_ 8661541Srgrimesstruct setlogin_args { 8671541Srgrimes char *namebuf; 8681541Srgrimes}; 86912221Sbde#endif 8701541Srgrimes/* ARGSUSED */ 8711549Srgrimesint 87230994Sphksetlogin(p, uap) 8731541Srgrimes struct proc *p; 8741541Srgrimes struct setlogin_args *uap; 8751541Srgrimes{ 8761541Srgrimes int error; 87723330Sache char logintmp[MAXLOGNAME]; 8781541Srgrimes 8793098Sphk if ((error = suser(p->p_ucred, &p->p_acflag))) 8801541Srgrimes return (error); 88122522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 88236845Sdfr sizeof(logintmp), (size_t *)0); 8831541Srgrimes if (error == ENAMETOOLONG) 8841541Srgrimes error = EINVAL; 88522522Sdavidn else if (!error) 88622522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 88723330Sache sizeof(logintmp)); 8881541Srgrimes return (error); 8891541Srgrimes} 89031891Ssef 89131891Ssefvoid 89231891Ssefsetsugid(p) 89331891Ssef struct proc *p; 89431891Ssef{ 89531891Ssef p->p_flag |= P_SUGID; 89631891Ssef if (!(p->p_pfsflags & PF_ISUGID)) 89731891Ssef p->p_stops = 0; 89831891Ssef} 899