kern_prot.c revision 31891
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 3931891Ssef * $Id: kern_prot.c,v 1.38 1997/12/16 17:40:16 eivind 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> 521541Srgrimes#include <sys/proc.h> 531541Srgrimes#include <sys/malloc.h> 5418013Sbde#include <sys/unistd.h> 5531891Ssef#include <sys/pioctl.h> 561541Srgrimes 5730354Sphkstatic MALLOC_DEFINE(M_CRED, "cred", "credentials"); 5830354Sphk 5912221Sbde#ifndef _SYS_SYSPROTO_H_ 6011332Sswallacestruct getpid_args { 611541Srgrimes int dummy; 621541Srgrimes}; 6312221Sbde#endif 641541Srgrimes 651541Srgrimes/* ARGSUSED */ 661549Srgrimesint 6730994Sphkgetpid(p, uap) 681541Srgrimes struct proc *p; 6911332Sswallace struct getpid_args *uap; 701541Srgrimes{ 711541Srgrimes 7230994Sphk p->p_retval[0] = p->p_pid; 731541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 7430994Sphk p->p_retval[1] = p->p_pptr->p_pid; 751541Srgrimes#endif 761541Srgrimes return (0); 771541Srgrimes} 781541Srgrimes 7912221Sbde#ifndef _SYS_SYSPROTO_H_ 8011332Sswallacestruct getppid_args { 8111332Sswallace int dummy; 8211332Sswallace}; 8312221Sbde#endif 841541Srgrimes/* ARGSUSED */ 851549Srgrimesint 8630994Sphkgetppid(p, uap) 871541Srgrimes struct proc *p; 8811332Sswallace struct getppid_args *uap; 891541Srgrimes{ 901541Srgrimes 9130994Sphk p->p_retval[0] = p->p_pptr->p_pid; 921541Srgrimes return (0); 931541Srgrimes} 941541Srgrimes 951541Srgrimes/* Get process group ID; note that POSIX getpgrp takes no parameter */ 9612221Sbde#ifndef _SYS_SYSPROTO_H_ 9711332Sswallacestruct getpgrp_args { 9811332Sswallace int dummy; 9911332Sswallace}; 10012221Sbde#endif 10111332Sswallace 1021549Srgrimesint 10330994Sphkgetpgrp(p, uap) 1041541Srgrimes struct proc *p; 10511332Sswallace struct getpgrp_args *uap; 1061541Srgrimes{ 1071541Srgrimes 10830994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 1091541Srgrimes return (0); 1101541Srgrimes} 1111541Srgrimes 11228401Speter/* Get an arbitary pid's process group id */ 11312221Sbde#ifndef _SYS_SYSPROTO_H_ 11428401Speterstruct getpgid_args { 11528401Speter pid_t pid; 11628401Speter}; 11728401Speter#endif 11828401Speter 11928401Speterint 12030994Sphkgetpgid(p, uap) 12128401Speter struct proc *p; 12228401Speter struct getpgid_args *uap; 12328401Speter{ 12428401Speter if (uap->pid == 0) 12528401Speter goto found; 12628401Speter 12728401Speter if ((p == pfind(uap->pid)) == 0) 12828401Speter return ESRCH; 12928401Speterfound: 13030994Sphk p->p_retval[0] = p->p_pgrp->pg_id; 13128401Speter return 0; 13228401Speter} 13328401Speter 13428401Speter/* 13528401Speter * Get an arbitary pid's session id. 13628401Speter */ 13728401Speter#ifndef _SYS_SYSPROTO_H_ 13828401Speterstruct getsid_args { 13928401Speter pid_t pid; 14028401Speter}; 14128401Speter#endif 14228401Speter 14328401Speterint 14430994Sphkgetsid(p, uap) 14528401Speter struct proc *p; 14628401Speter struct getsid_args *uap; 14728401Speter{ 14828401Speter if (uap->pid == 0) 14928401Speter goto found; 15028401Speter 15128401Speter if ((p == pfind(uap->pid)) == 0) 15228401Speter return ESRCH; 15328401Speterfound: 15430994Sphk p->p_retval[0] = p->p_pgrp->pg_session->s_leader->p_pid; 15528401Speter return 0; 15628401Speter} 15728401Speter 15828401Speter 15928401Speter#ifndef _SYS_SYSPROTO_H_ 16011332Sswallacestruct getuid_args { 16111332Sswallace int dummy; 16211332Sswallace}; 16312221Sbde#endif 16411332Sswallace 1651541Srgrimes/* ARGSUSED */ 1661549Srgrimesint 16730994Sphkgetuid(p, uap) 1681541Srgrimes struct proc *p; 16911332Sswallace struct getuid_args *uap; 1701541Srgrimes{ 1711541Srgrimes 17230994Sphk p->p_retval[0] = p->p_cred->p_ruid; 1731541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 17430994Sphk p->p_retval[1] = p->p_ucred->cr_uid; 1751541Srgrimes#endif 1761541Srgrimes return (0); 1771541Srgrimes} 1781541Srgrimes 17912221Sbde#ifndef _SYS_SYSPROTO_H_ 18011332Sswallacestruct geteuid_args { 18111332Sswallace int dummy; 18211332Sswallace}; 18312221Sbde#endif 18411332Sswallace 1851541Srgrimes/* ARGSUSED */ 1861549Srgrimesint 18730994Sphkgeteuid(p, uap) 1881541Srgrimes struct proc *p; 18911332Sswallace struct geteuid_args *uap; 1901541Srgrimes{ 1911541Srgrimes 19230994Sphk p->p_retval[0] = p->p_ucred->cr_uid; 1931541Srgrimes return (0); 1941541Srgrimes} 1951541Srgrimes 19612221Sbde#ifndef _SYS_SYSPROTO_H_ 19711332Sswallacestruct getgid_args { 19811332Sswallace int dummy; 19911332Sswallace}; 20012221Sbde#endif 20111332Sswallace 2021541Srgrimes/* ARGSUSED */ 2031549Srgrimesint 20430994Sphkgetgid(p, uap) 2051541Srgrimes struct proc *p; 20611332Sswallace struct getgid_args *uap; 2071541Srgrimes{ 2081541Srgrimes 20930994Sphk p->p_retval[0] = p->p_cred->p_rgid; 2101541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 21130994Sphk p->p_retval[1] = p->p_ucred->cr_groups[0]; 2121541Srgrimes#endif 2131541Srgrimes return (0); 2141541Srgrimes} 2151541Srgrimes 2161541Srgrimes/* 2171541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 2181541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 2191541Srgrimes * correctly in a library function. 2201541Srgrimes */ 22112221Sbde#ifndef _SYS_SYSPROTO_H_ 22211332Sswallacestruct getegid_args { 22311332Sswallace int dummy; 22411332Sswallace}; 22512221Sbde#endif 22611332Sswallace 2271541Srgrimes/* ARGSUSED */ 2281549Srgrimesint 22930994Sphkgetegid(p, uap) 2301541Srgrimes struct proc *p; 23111332Sswallace struct getegid_args *uap; 2321541Srgrimes{ 2331541Srgrimes 23430994Sphk p->p_retval[0] = p->p_ucred->cr_groups[0]; 2351541Srgrimes return (0); 2361541Srgrimes} 2371541Srgrimes 23812221Sbde#ifndef _SYS_SYSPROTO_H_ 2391541Srgrimesstruct getgroups_args { 2401541Srgrimes u_int gidsetsize; 2411541Srgrimes gid_t *gidset; 2421541Srgrimes}; 24312221Sbde#endif 2441549Srgrimesint 24530994Sphkgetgroups(p, uap) 2461541Srgrimes struct proc *p; 2471541Srgrimes register struct getgroups_args *uap; 2481541Srgrimes{ 2491541Srgrimes register struct pcred *pc = p->p_cred; 2501541Srgrimes register u_int ngrp; 2511541Srgrimes int error; 2521541Srgrimes 2531541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 25430994Sphk p->p_retval[0] = pc->pc_ucred->cr_ngroups; 2551541Srgrimes return (0); 2561541Srgrimes } 2571541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 2581541Srgrimes return (EINVAL); 2591541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 2603098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 2613098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 2621541Srgrimes return (error); 26330994Sphk p->p_retval[0] = ngrp; 2641541Srgrimes return (0); 2651541Srgrimes} 2661541Srgrimes 26712221Sbde#ifndef _SYS_SYSPROTO_H_ 26812207Sbdestruct setsid_args { 26911332Sswallace int dummy; 27011332Sswallace}; 27112221Sbde#endif 27211332Sswallace 2731541Srgrimes/* ARGSUSED */ 2741549Srgrimesint 27530994Sphksetsid(p, uap) 2761541Srgrimes register struct proc *p; 27712207Sbde struct setsid_args *uap; 2781541Srgrimes{ 2791541Srgrimes 2801541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 2811541Srgrimes return (EPERM); 2821541Srgrimes } else { 2831541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 28430994Sphk p->p_retval[0] = p->p_pid; 2851541Srgrimes return (0); 2861541Srgrimes } 2871541Srgrimes} 2881541Srgrimes 2891541Srgrimes/* 2901541Srgrimes * set process group (setpgid/old setpgrp) 2911541Srgrimes * 2921541Srgrimes * caller does setpgid(targpid, targpgid) 2931541Srgrimes * 2941541Srgrimes * pid must be caller or child of caller (ESRCH) 2951541Srgrimes * if a child 2961541Srgrimes * pid must be in same session (EPERM) 2971541Srgrimes * pid can't have done an exec (EACCES) 2981541Srgrimes * if pgid != pid 2991541Srgrimes * there must exist some pid in same session having pgid (EPERM) 3001541Srgrimes * pid must not be session leader (EPERM) 3011541Srgrimes */ 30212221Sbde#ifndef _SYS_SYSPROTO_H_ 3031541Srgrimesstruct setpgid_args { 3041541Srgrimes int pid; /* target process id */ 3051541Srgrimes int pgid; /* target pgrp id */ 3061541Srgrimes}; 30712221Sbde#endif 3081541Srgrimes/* ARGSUSED */ 3091549Srgrimesint 31030994Sphksetpgid(curp, uap) 3111541Srgrimes struct proc *curp; 3121541Srgrimes register struct setpgid_args *uap; 3131541Srgrimes{ 3141541Srgrimes register struct proc *targp; /* target process */ 3151541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 3161541Srgrimes 31720677Sbde if (uap->pgid < 0) 31820677Sbde return (EINVAL); 3191541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 3201541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 3211541Srgrimes return (ESRCH); 32215985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 3231541Srgrimes return (EPERM); 3241541Srgrimes if (targp->p_flag & P_EXEC) 3251541Srgrimes return (EACCES); 3261541Srgrimes } else 3271541Srgrimes targp = curp; 3281541Srgrimes if (SESS_LEADER(targp)) 3291541Srgrimes return (EPERM); 3301541Srgrimes if (uap->pgid == 0) 3311541Srgrimes uap->pgid = targp->p_pid; 3321541Srgrimes else if (uap->pgid != targp->p_pid) 3331541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 3341541Srgrimes pgrp->pg_session != curp->p_session) 3351541Srgrimes return (EPERM); 3361541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 3371541Srgrimes} 3381541Srgrimes 33924448Speter/* 34024448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 34124448Speter * compatable. It says that setting the uid/gid to euid/egid is a special 34224448Speter * case of "appropriate privilege". Once the rules are expanded out, this 34324448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 34424448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 34524448Speter * does not set the saved id - this is dangerous for traditional BSD 34624448Speter * programs. For this reason, we *really* do not want to set 34724448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 34824448Speter */ 34924448Speter#define POSIX_APPENDIX_B_4_2_2 35024448Speter 35112221Sbde#ifndef _SYS_SYSPROTO_H_ 3521541Srgrimesstruct setuid_args { 3531541Srgrimes uid_t uid; 3541541Srgrimes}; 35512221Sbde#endif 3561541Srgrimes/* ARGSUSED */ 3571549Srgrimesint 35830994Sphksetuid(p, uap) 3591541Srgrimes struct proc *p; 3601541Srgrimes struct setuid_args *uap; 3611541Srgrimes{ 3621541Srgrimes register struct pcred *pc = p->p_cred; 3631541Srgrimes register uid_t uid; 3641541Srgrimes int error; 3651541Srgrimes 36624448Speter /* 36724448Speter * See if we have "permission" by POSIX 1003.1 rules. 36824448Speter * 36924448Speter * Note that setuid(geteuid()) is a special case of 37024448Speter * "appropriate privileges" in appendix B.4.2.2. We need 37124448Speter * to use this clause to be compatable with traditional BSD 37224448Speter * semantics. Basically, it means that "setuid(xx)" sets all 37324448Speter * three id's (assuming you have privs). 37424448Speter * 37524448Speter * Notes on the logic. We do things in three steps. 37624448Speter * 1: We determine if the euid is going to change, and do EPERM 37724448Speter * right away. We unconditionally change the euid later if this 37824448Speter * test is satisfied, simplifying that part of the logic. 37924448Speter * 2: We determine if the real and/or saved uid's are going to 38024448Speter * change. Determined by compile options. 38124448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 38224448Speter */ 3831541Srgrimes uid = uap->uid; 38424448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 38517994Sache#ifdef _POSIX_SAVED_IDS 38624448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 38717994Sache#endif 38824448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 38924448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 39024448Speter#endif 3918162Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 3921541Srgrimes return (error); 39324448Speter 39424448Speter#ifdef _POSIX_SAVED_IDS 3951541Srgrimes /* 39624448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 39724448Speter * If so, we are changing the real uid and/or saved uid. 3981541Srgrimes */ 39917994Sache if ( 40024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 40124448Speter uid == pc->pc_ucred->cr_uid || 40217994Sache#endif 40324448Speter suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 40417994Sache#endif 40524448Speter { 40624448Speter /* 40724448Speter * Transfer proc count to new user. 40824448Speter */ 40924448Speter if (uid != pc->p_ruid) { 41024448Speter (void)chgproccnt(pc->p_ruid, -1); 41124448Speter (void)chgproccnt(uid, 1); 41224448Speter } 41324448Speter /* 41424448Speter * Set real uid 41524448Speter */ 41624448Speter if (uid != pc->p_ruid) { 41724448Speter pc->p_ruid = uid; 41831891Ssef setsugid(p); 41924448Speter } 42024448Speter /* 42124448Speter * Set saved uid 42224448Speter * 42324448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 42424448Speter * the security of seteuid() depends on it. B.4.2.2 says it 42524448Speter * is important that we should do this. 42624448Speter */ 42724448Speter if (pc->p_svuid != uid) { 42824448Speter pc->p_svuid = uid; 42931891Ssef setsugid(p); 43024448Speter } 4318141Sache } 43224448Speter 43324448Speter /* 43424448Speter * In all permitted cases, we are changing the euid. 43524448Speter * Copy credentials so other references do not see our changes. 43624448Speter */ 43724448Speter if (pc->pc_ucred->cr_uid != uid) { 43824448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 43924448Speter pc->pc_ucred->cr_uid = uid; 44031891Ssef setsugid(p); 44124448Speter } 4421541Srgrimes return (0); 4431541Srgrimes} 4441541Srgrimes 44512221Sbde#ifndef _SYS_SYSPROTO_H_ 4461541Srgrimesstruct seteuid_args { 4471541Srgrimes uid_t euid; 4481541Srgrimes}; 44912221Sbde#endif 4501541Srgrimes/* ARGSUSED */ 4511549Srgrimesint 45230994Sphkseteuid(p, uap) 4531541Srgrimes struct proc *p; 4541541Srgrimes struct seteuid_args *uap; 4551541Srgrimes{ 4561541Srgrimes register struct pcred *pc = p->p_cred; 4571541Srgrimes register uid_t euid; 4581541Srgrimes int error; 4591541Srgrimes 4601541Srgrimes euid = uap->euid; 46124449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 46224449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 4631541Srgrimes (error = suser(pc->pc_ucred, &p->p_acflag))) 4641541Srgrimes return (error); 4651541Srgrimes /* 4661541Srgrimes * Everything's okay, do it. Copy credentials so other references do 4671541Srgrimes * not see our changes. 4681541Srgrimes */ 46924449Speter if (pc->pc_ucred->cr_uid != euid) { 47024449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 47124449Speter pc->pc_ucred->cr_uid = euid; 47231891Ssef setsugid(p); 47324449Speter } 4741541Srgrimes return (0); 4751541Srgrimes} 4761541Srgrimes 47712221Sbde#ifndef _SYS_SYSPROTO_H_ 4781541Srgrimesstruct setgid_args { 4791541Srgrimes gid_t gid; 4801541Srgrimes}; 48112221Sbde#endif 4821541Srgrimes/* ARGSUSED */ 4831549Srgrimesint 48430994Sphksetgid(p, uap) 4851541Srgrimes struct proc *p; 4861541Srgrimes struct setgid_args *uap; 4871541Srgrimes{ 4881541Srgrimes register struct pcred *pc = p->p_cred; 4891541Srgrimes register gid_t gid; 4901541Srgrimes int error; 4911541Srgrimes 49224448Speter /* 49324448Speter * See if we have "permission" by POSIX 1003.1 rules. 49424448Speter * 49524448Speter * Note that setgid(getegid()) is a special case of 49624448Speter * "appropriate privileges" in appendix B.4.2.2. We need 49724448Speter * to use this clause to be compatable with traditional BSD 49824448Speter * semantics. Basically, it means that "setgid(xx)" sets all 49924448Speter * three id's (assuming you have privs). 50024448Speter * 50124448Speter * For notes on the logic here, see setuid() above. 50224448Speter */ 5031541Srgrimes gid = uap->gid; 50424448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 50517994Sache#ifdef _POSIX_SAVED_IDS 50624448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 50717994Sache#endif 50824448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 50924448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 51024448Speter#endif 5118162Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 5121541Srgrimes return (error); 51324448Speter 51417994Sache#ifdef _POSIX_SAVED_IDS 51524448Speter /* 51624448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 51724448Speter * If so, we are changing the real uid and saved gid. 51824448Speter */ 51924448Speter if ( 52024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 52124448Speter gid == pc->pc_ucred->cr_groups[0] || 52217994Sache#endif 52324448Speter suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 52424448Speter#endif 52524448Speter { 52624448Speter /* 52724448Speter * Set real gid 52824448Speter */ 52924448Speter if (pc->p_rgid != gid) { 53024448Speter pc->p_rgid = gid; 53131891Ssef setsugid(p); 53224448Speter } 53324448Speter /* 53424448Speter * Set saved gid 53524448Speter * 53624448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 53724448Speter * the security of setegid() depends on it. B.4.2.2 says it 53824448Speter * is important that we should do this. 53924448Speter */ 54024448Speter if (pc->p_svgid != gid) { 54124448Speter pc->p_svgid = gid; 54231891Ssef setsugid(p); 54324448Speter } 5448141Sache } 54524448Speter /* 54624448Speter * In all cases permitted cases, we are changing the egid. 54724448Speter * Copy credentials so other references do not see our changes. 54824448Speter */ 54924448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 55024448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 55124448Speter pc->pc_ucred->cr_groups[0] = gid; 55231891Ssef setsugid(p); 55324448Speter } 5541541Srgrimes return (0); 5551541Srgrimes} 5561541Srgrimes 55712221Sbde#ifndef _SYS_SYSPROTO_H_ 5581541Srgrimesstruct setegid_args { 5591541Srgrimes gid_t egid; 5601541Srgrimes}; 56112221Sbde#endif 5621541Srgrimes/* ARGSUSED */ 5631549Srgrimesint 56430994Sphksetegid(p, uap) 5651541Srgrimes struct proc *p; 5661541Srgrimes struct setegid_args *uap; 5671541Srgrimes{ 5681541Srgrimes register struct pcred *pc = p->p_cred; 5691541Srgrimes register gid_t egid; 5701541Srgrimes int error; 5711541Srgrimes 5721541Srgrimes egid = uap->egid; 57324449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 57424449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 5751541Srgrimes (error = suser(pc->pc_ucred, &p->p_acflag))) 5761541Srgrimes return (error); 57724449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 57824449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 57924449Speter pc->pc_ucred->cr_groups[0] = egid; 58031891Ssef setsugid(p); 58124449Speter } 5821541Srgrimes return (0); 5831541Srgrimes} 5841541Srgrimes 58512221Sbde#ifndef _SYS_SYSPROTO_H_ 5861541Srgrimesstruct setgroups_args { 5871541Srgrimes u_int gidsetsize; 5881541Srgrimes gid_t *gidset; 5891541Srgrimes}; 59012221Sbde#endif 5911541Srgrimes/* ARGSUSED */ 5921549Srgrimesint 59330994Sphksetgroups(p, uap) 5941541Srgrimes struct proc *p; 5951541Srgrimes struct setgroups_args *uap; 5961541Srgrimes{ 5971541Srgrimes register struct pcred *pc = p->p_cred; 5981541Srgrimes register u_int ngrp; 5991541Srgrimes int error; 6001541Srgrimes 6013098Sphk if ((error = suser(pc->pc_ucred, &p->p_acflag))) 6021541Srgrimes return (error); 60312063Sdg ngrp = uap->gidsetsize; 60424447Speter if (ngrp > NGROUPS) 6051541Srgrimes return (EINVAL); 60624447Speter /* 60724447Speter * XXX A little bit lazy here. We could test if anything has 60824447Speter * changed before crcopy() and setting P_SUGID. 60924447Speter */ 6101541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 61124447Speter if (ngrp < 1) { 61224447Speter /* 61324447Speter * setgroups(0, NULL) is a legitimate way of clearing the 61424447Speter * groups vector on non-BSD systems (which generally do not 61524447Speter * have the egid in the groups[0]). We risk security holes 61624447Speter * when running non-BSD software if we do not do the same. 61724447Speter */ 61824447Speter pc->pc_ucred->cr_ngroups = 1; 61924447Speter } else { 62024447Speter if ((error = copyin((caddr_t)uap->gidset, 62124447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 62224447Speter return (error); 62324447Speter pc->pc_ucred->cr_ngroups = ngrp; 62424447Speter } 62531891Ssef setsugid(p); 6261541Srgrimes return (0); 6271541Srgrimes} 6281541Srgrimes 62912221Sbde#ifndef _SYS_SYSPROTO_H_ 6301541Srgrimesstruct setreuid_args { 6319238Sache uid_t ruid; 6329238Sache uid_t euid; 6331541Srgrimes}; 63412221Sbde#endif 6351541Srgrimes/* ARGSUSED */ 6361549Srgrimesint 63730994Sphksetreuid(p, uap) 6381541Srgrimes register struct proc *p; 6391541Srgrimes struct setreuid_args *uap; 6401541Srgrimes{ 6411541Srgrimes register struct pcred *pc = p->p_cred; 6429238Sache register uid_t ruid, euid; 6438135Sache int error; 6441541Srgrimes 6459238Sache ruid = uap->ruid; 6469238Sache euid = uap->euid; 6479238Sache if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid || 64824559Speter euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 64924559Speter euid != pc->p_ruid && euid != pc->p_svuid) && 6508135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6518135Sache return (error); 6529238Sache 65324450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 65424450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6559238Sache pc->pc_ucred->cr_uid = euid; 65631891Ssef setsugid(p); 65724450Speter } 65824450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 6599238Sache (void)chgproccnt(pc->p_ruid, -1); 6609238Sache (void)chgproccnt(ruid, 1); 6619238Sache pc->p_ruid = ruid; 66231891Ssef setsugid(p); 6638135Sache } 66424559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 66524559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6668111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 66731891Ssef setsugid(p); 66824450Speter } 6698135Sache return (0); 6701541Srgrimes} 6711541Srgrimes 67212221Sbde#ifndef _SYS_SYSPROTO_H_ 6731541Srgrimesstruct setregid_args { 6749238Sache gid_t rgid; 6759238Sache gid_t egid; 6761541Srgrimes}; 67712221Sbde#endif 6781541Srgrimes/* ARGSUSED */ 6791549Srgrimesint 68030994Sphksetregid(p, uap) 6811541Srgrimes register struct proc *p; 6821541Srgrimes struct setregid_args *uap; 6831541Srgrimes{ 6841541Srgrimes register struct pcred *pc = p->p_cred; 6859238Sache register gid_t rgid, egid; 6868135Sache int error; 6871541Srgrimes 6889238Sache rgid = uap->rgid; 6899238Sache egid = uap->egid; 6909238Sache if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 69124559Speter egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 69224559Speter egid != pc->p_rgid && egid != pc->p_svgid) && 6938135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6948135Sache return (error); 6959238Sache 69624450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 69724450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6989238Sache pc->pc_ucred->cr_groups[0] = egid; 69931891Ssef setsugid(p); 70024450Speter } 70124450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 7029238Sache pc->p_rgid = rgid; 70331891Ssef setsugid(p); 70424450Speter } 70524559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 70624559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7078111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 70831891Ssef setsugid(p); 70924450Speter } 7108135Sache return (0); 7111541Srgrimes} 7121541Srgrimes 71324453Speter#ifndef _SYS_SYSPROTO_H_ 71424453Speterstruct issetugid_args { 71524453Speter int dummy; 71624453Speter}; 71724453Speter#endif 71824453Speter/* ARGSUSED */ 71924453Speterint 72030994Sphkissetugid(p, uap) 72124453Speter register struct proc *p; 72224453Speter struct issetugid_args *uap; 72324453Speter{ 72424453Speter /* 72524453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 72624453Speter * we use P_SUGID because we consider changing the owners as 72724453Speter * "tainting" as well. 72824453Speter * This is significant for procs that start as root and "become" 72924453Speter * a user without an exec - programs cannot know *everything* 73024453Speter * that libc *might* have put in their data segment. 73124453Speter */ 73224453Speter if (p->p_flag & P_SUGID) 73324453Speter return (1); 73424453Speter return (0); 73524453Speter} 73624453Speter 7371541Srgrimes/* 7381541Srgrimes * Check if gid is a member of the group set. 7391541Srgrimes */ 7401549Srgrimesint 7411541Srgrimesgroupmember(gid, cred) 7421541Srgrimes gid_t gid; 7431541Srgrimes register struct ucred *cred; 7441541Srgrimes{ 7451541Srgrimes register gid_t *gp; 7461541Srgrimes gid_t *egp; 7471541Srgrimes 7481541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 7491541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 7501541Srgrimes if (*gp == gid) 7511541Srgrimes return (1); 7521541Srgrimes return (0); 7531541Srgrimes} 7541541Srgrimes 7551541Srgrimes/* 7561541Srgrimes * Test whether the specified credentials imply "super-user" 7571541Srgrimes * privilege; if so, and we have accounting info, set the flag 7581541Srgrimes * indicating use of super-powers. 7591541Srgrimes * Returns 0 or error. 7601541Srgrimes */ 7611549Srgrimesint 7621541Srgrimessuser(cred, acflag) 7631541Srgrimes struct ucred *cred; 7648011Sbde u_short *acflag; 7651541Srgrimes{ 7661541Srgrimes if (cred->cr_uid == 0) { 7671541Srgrimes if (acflag) 7681541Srgrimes *acflag |= ASU; 7691541Srgrimes return (0); 7701541Srgrimes } 7711541Srgrimes return (EPERM); 7721541Srgrimes} 7731541Srgrimes 7741541Srgrimes/* 7751541Srgrimes * Allocate a zeroed cred structure. 7761541Srgrimes */ 7771541Srgrimesstruct ucred * 7781541Srgrimescrget() 7791541Srgrimes{ 7801541Srgrimes register struct ucred *cr; 7811541Srgrimes 7821541Srgrimes MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 7831541Srgrimes bzero((caddr_t)cr, sizeof(*cr)); 7841541Srgrimes cr->cr_ref = 1; 7851541Srgrimes return (cr); 7861541Srgrimes} 7871541Srgrimes 7881541Srgrimes/* 7891541Srgrimes * Free a cred structure. 7901541Srgrimes * Throws away space when ref count gets to 0. 7911541Srgrimes */ 7921549Srgrimesvoid 7931541Srgrimescrfree(cr) 7941541Srgrimes struct ucred *cr; 7951541Srgrimes{ 7961541Srgrimes if (--cr->cr_ref == 0) 7971541Srgrimes FREE((caddr_t)cr, M_CRED); 7981541Srgrimes} 7991541Srgrimes 8001541Srgrimes/* 8011541Srgrimes * Copy cred structure to a new one and free the old one. 8021541Srgrimes */ 8031541Srgrimesstruct ucred * 8041541Srgrimescrcopy(cr) 8051541Srgrimes struct ucred *cr; 8061541Srgrimes{ 8071541Srgrimes struct ucred *newcr; 8081541Srgrimes 8091541Srgrimes if (cr->cr_ref == 1) 8101541Srgrimes return (cr); 8111541Srgrimes newcr = crget(); 8121541Srgrimes *newcr = *cr; 8131541Srgrimes crfree(cr); 8141541Srgrimes newcr->cr_ref = 1; 8151541Srgrimes return (newcr); 8161541Srgrimes} 8171541Srgrimes 8181541Srgrimes/* 8191541Srgrimes * Dup cred struct to a new held one. 8201541Srgrimes */ 8211541Srgrimesstruct ucred * 8221541Srgrimescrdup(cr) 8231541Srgrimes struct ucred *cr; 8241541Srgrimes{ 8251541Srgrimes struct ucred *newcr; 8261541Srgrimes 8271541Srgrimes newcr = crget(); 8281541Srgrimes *newcr = *cr; 8291541Srgrimes newcr->cr_ref = 1; 8301541Srgrimes return (newcr); 8311541Srgrimes} 8321541Srgrimes 8331541Srgrimes/* 8341541Srgrimes * Get login name, if available. 8351541Srgrimes */ 83612221Sbde#ifndef _SYS_SYSPROTO_H_ 8371541Srgrimesstruct getlogin_args { 8381541Srgrimes char *namebuf; 8391541Srgrimes u_int namelen; 8401541Srgrimes}; 84112221Sbde#endif 8421541Srgrimes/* ARGSUSED */ 8431549Srgrimesint 84430994Sphkgetlogin(p, uap) 8451541Srgrimes struct proc *p; 8461541Srgrimes struct getlogin_args *uap; 8471541Srgrimes{ 8481541Srgrimes 84923358Sache if (uap->namelen > MAXLOGNAME) 85023359Sache uap->namelen = MAXLOGNAME; 8511541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 8521541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 8531541Srgrimes} 8541541Srgrimes 8551541Srgrimes/* 8561541Srgrimes * Set login name. 8571541Srgrimes */ 85812221Sbde#ifndef _SYS_SYSPROTO_H_ 8591541Srgrimesstruct setlogin_args { 8601541Srgrimes char *namebuf; 8611541Srgrimes}; 86212221Sbde#endif 8631541Srgrimes/* ARGSUSED */ 8641549Srgrimesint 86530994Sphksetlogin(p, uap) 8661541Srgrimes struct proc *p; 8671541Srgrimes struct setlogin_args *uap; 8681541Srgrimes{ 8691541Srgrimes int error; 87023330Sache char logintmp[MAXLOGNAME]; 8711541Srgrimes 8723098Sphk if ((error = suser(p->p_ucred, &p->p_acflag))) 8731541Srgrimes return (error); 87422522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 87522522Sdavidn sizeof(logintmp), (u_int *)0); 8761541Srgrimes if (error == ENAMETOOLONG) 8771541Srgrimes error = EINVAL; 87822522Sdavidn else if (!error) 87922522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 88023330Sache sizeof(logintmp)); 8811541Srgrimes return (error); 8821541Srgrimes} 88331891Ssef 88431891Ssefvoid 88531891Ssefsetsugid(p) 88631891Ssef struct proc *p; 88731891Ssef{ 88831891Ssef p->p_flag |= P_SUGID; 88931891Ssef if (!(p->p_pfsflags & PF_ISUGID)) 89031891Ssef p->p_stops = 0; 89131891Ssef} 892