kern_prot.c revision 24559
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 3924559Speter * $Id: kern_prot.c,v 1.31 1997/03/31 15:13:33 peter Exp $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes/* 431541Srgrimes * System calls related to processes and protection 441541Srgrimes */ 451541Srgrimes 461541Srgrimes#include <sys/param.h> 471541Srgrimes#include <sys/acct.h> 481541Srgrimes#include <sys/systm.h> 4912221Sbde#include <sys/sysproto.h> 501541Srgrimes#include <sys/ucred.h> 511541Srgrimes#include <sys/proc.h> 521541Srgrimes#include <sys/timeb.h> 531541Srgrimes#include <sys/times.h> 541541Srgrimes#include <sys/malloc.h> 5518013Sbde#include <sys/unistd.h> 561541Srgrimes 5712221Sbde#ifndef _SYS_SYSPROTO_H_ 5811332Sswallacestruct getpid_args { 591541Srgrimes int dummy; 601541Srgrimes}; 6112221Sbde#endif 621541Srgrimes 631541Srgrimes/* ARGSUSED */ 641549Srgrimesint 651541Srgrimesgetpid(p, uap, retval) 661541Srgrimes struct proc *p; 6711332Sswallace struct getpid_args *uap; 681541Srgrimes int *retval; 691541Srgrimes{ 701541Srgrimes 711541Srgrimes *retval = p->p_pid; 721541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 731541Srgrimes retval[1] = p->p_pptr->p_pid; 741541Srgrimes#endif 751541Srgrimes return (0); 761541Srgrimes} 771541Srgrimes 7812221Sbde#ifndef _SYS_SYSPROTO_H_ 7911332Sswallacestruct getppid_args { 8011332Sswallace int dummy; 8111332Sswallace}; 8212221Sbde#endif 831541Srgrimes/* ARGSUSED */ 841549Srgrimesint 851541Srgrimesgetppid(p, uap, retval) 861541Srgrimes struct proc *p; 8711332Sswallace struct getppid_args *uap; 881541Srgrimes int *retval; 891541Srgrimes{ 901541Srgrimes 911541Srgrimes *retval = 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 1031541Srgrimesgetpgrp(p, uap, retval) 1041541Srgrimes struct proc *p; 10511332Sswallace struct getpgrp_args *uap; 1061541Srgrimes int *retval; 1071541Srgrimes{ 1081541Srgrimes 1091541Srgrimes *retval = p->p_pgrp->pg_id; 1101541Srgrimes return (0); 1111541Srgrimes} 1121541Srgrimes 11312221Sbde#ifndef _SYS_SYSPROTO_H_ 11411332Sswallacestruct getuid_args { 11511332Sswallace int dummy; 11611332Sswallace}; 11712221Sbde#endif 11811332Sswallace 1191541Srgrimes/* ARGSUSED */ 1201549Srgrimesint 1211541Srgrimesgetuid(p, uap, retval) 1221541Srgrimes struct proc *p; 12311332Sswallace struct getuid_args *uap; 1241541Srgrimes int *retval; 1251541Srgrimes{ 1261541Srgrimes 1271541Srgrimes *retval = p->p_cred->p_ruid; 1281541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1291541Srgrimes retval[1] = p->p_ucred->cr_uid; 1301541Srgrimes#endif 1311541Srgrimes return (0); 1321541Srgrimes} 1331541Srgrimes 13412221Sbde#ifndef _SYS_SYSPROTO_H_ 13511332Sswallacestruct geteuid_args { 13611332Sswallace int dummy; 13711332Sswallace}; 13812221Sbde#endif 13911332Sswallace 1401541Srgrimes/* ARGSUSED */ 1411549Srgrimesint 1421541Srgrimesgeteuid(p, uap, retval) 1431541Srgrimes struct proc *p; 14411332Sswallace struct geteuid_args *uap; 1451541Srgrimes int *retval; 1461541Srgrimes{ 1471541Srgrimes 1481541Srgrimes *retval = p->p_ucred->cr_uid; 1491541Srgrimes return (0); 1501541Srgrimes} 1511541Srgrimes 15212221Sbde#ifndef _SYS_SYSPROTO_H_ 15311332Sswallacestruct getgid_args { 15411332Sswallace int dummy; 15511332Sswallace}; 15612221Sbde#endif 15711332Sswallace 1581541Srgrimes/* ARGSUSED */ 1591549Srgrimesint 1601541Srgrimesgetgid(p, uap, retval) 1611541Srgrimes struct proc *p; 16211332Sswallace struct getgid_args *uap; 1631541Srgrimes int *retval; 1641541Srgrimes{ 1651541Srgrimes 1661541Srgrimes *retval = p->p_cred->p_rgid; 1671541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1681541Srgrimes retval[1] = p->p_ucred->cr_groups[0]; 1691541Srgrimes#endif 1701541Srgrimes return (0); 1711541Srgrimes} 1721541Srgrimes 1731541Srgrimes/* 1741541Srgrimes * Get effective group ID. The "egid" is groups[0], and could be obtained 1751541Srgrimes * via getgroups. This syscall exists because it is somewhat painful to do 1761541Srgrimes * correctly in a library function. 1771541Srgrimes */ 17812221Sbde#ifndef _SYS_SYSPROTO_H_ 17911332Sswallacestruct getegid_args { 18011332Sswallace int dummy; 18111332Sswallace}; 18212221Sbde#endif 18311332Sswallace 1841541Srgrimes/* ARGSUSED */ 1851549Srgrimesint 1861541Srgrimesgetegid(p, uap, retval) 1871541Srgrimes struct proc *p; 18811332Sswallace struct getegid_args *uap; 1891541Srgrimes int *retval; 1901541Srgrimes{ 1911541Srgrimes 1921541Srgrimes *retval = p->p_ucred->cr_groups[0]; 1931541Srgrimes return (0); 1941541Srgrimes} 1951541Srgrimes 19612221Sbde#ifndef _SYS_SYSPROTO_H_ 1971541Srgrimesstruct getgroups_args { 1981541Srgrimes u_int gidsetsize; 1991541Srgrimes gid_t *gidset; 2001541Srgrimes}; 20112221Sbde#endif 2021549Srgrimesint 2031541Srgrimesgetgroups(p, uap, retval) 2041541Srgrimes struct proc *p; 2051541Srgrimes register struct getgroups_args *uap; 2061541Srgrimes int *retval; 2071541Srgrimes{ 2081541Srgrimes register struct pcred *pc = p->p_cred; 2091541Srgrimes register u_int ngrp; 2101541Srgrimes int error; 2111541Srgrimes 2121541Srgrimes if ((ngrp = uap->gidsetsize) == 0) { 2131541Srgrimes *retval = pc->pc_ucred->cr_ngroups; 2141541Srgrimes return (0); 2151541Srgrimes } 2161541Srgrimes if (ngrp < pc->pc_ucred->cr_ngroups) 2171541Srgrimes return (EINVAL); 2181541Srgrimes ngrp = pc->pc_ucred->cr_ngroups; 2193098Sphk if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 2203098Sphk (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 2211541Srgrimes return (error); 2221541Srgrimes *retval = ngrp; 2231541Srgrimes return (0); 2241541Srgrimes} 2251541Srgrimes 22612221Sbde#ifndef _SYS_SYSPROTO_H_ 22712207Sbdestruct setsid_args { 22811332Sswallace int dummy; 22911332Sswallace}; 23012221Sbde#endif 23111332Sswallace 2321541Srgrimes/* ARGSUSED */ 2331549Srgrimesint 2341541Srgrimessetsid(p, uap, retval) 2351541Srgrimes register struct proc *p; 23612207Sbde struct setsid_args *uap; 2371541Srgrimes int *retval; 2381541Srgrimes{ 2391541Srgrimes 2401541Srgrimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 2411541Srgrimes return (EPERM); 2421541Srgrimes } else { 2431541Srgrimes (void)enterpgrp(p, p->p_pid, 1); 2441541Srgrimes *retval = p->p_pid; 2451541Srgrimes return (0); 2461541Srgrimes } 2471541Srgrimes} 2481541Srgrimes 2491541Srgrimes/* 2501541Srgrimes * set process group (setpgid/old setpgrp) 2511541Srgrimes * 2521541Srgrimes * caller does setpgid(targpid, targpgid) 2531541Srgrimes * 2541541Srgrimes * pid must be caller or child of caller (ESRCH) 2551541Srgrimes * if a child 2561541Srgrimes * pid must be in same session (EPERM) 2571541Srgrimes * pid can't have done an exec (EACCES) 2581541Srgrimes * if pgid != pid 2591541Srgrimes * there must exist some pid in same session having pgid (EPERM) 2601541Srgrimes * pid must not be session leader (EPERM) 2611541Srgrimes */ 26212221Sbde#ifndef _SYS_SYSPROTO_H_ 2631541Srgrimesstruct setpgid_args { 2641541Srgrimes int pid; /* target process id */ 2651541Srgrimes int pgid; /* target pgrp id */ 2661541Srgrimes}; 26712221Sbde#endif 2681541Srgrimes/* ARGSUSED */ 2691549Srgrimesint 2701541Srgrimessetpgid(curp, uap, retval) 2711541Srgrimes struct proc *curp; 2721541Srgrimes register struct setpgid_args *uap; 2731541Srgrimes int *retval; 2741541Srgrimes{ 2751541Srgrimes register struct proc *targp; /* target process */ 2761541Srgrimes register struct pgrp *pgrp; /* target pgrp */ 2771541Srgrimes 27820677Sbde if (uap->pgid < 0) 27920677Sbde return (EINVAL); 2801541Srgrimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 2811541Srgrimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 2821541Srgrimes return (ESRCH); 28315985Sdg if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 2841541Srgrimes return (EPERM); 2851541Srgrimes if (targp->p_flag & P_EXEC) 2861541Srgrimes return (EACCES); 2871541Srgrimes } else 2881541Srgrimes targp = curp; 2891541Srgrimes if (SESS_LEADER(targp)) 2901541Srgrimes return (EPERM); 2911541Srgrimes if (uap->pgid == 0) 2921541Srgrimes uap->pgid = targp->p_pid; 2931541Srgrimes else if (uap->pgid != targp->p_pid) 2941541Srgrimes if ((pgrp = pgfind(uap->pgid)) == 0 || 2951541Srgrimes pgrp->pg_session != curp->p_session) 2961541Srgrimes return (EPERM); 2971541Srgrimes return (enterpgrp(targp, uap->pgid, 0)); 2981541Srgrimes} 2991541Srgrimes 30024448Speter/* 30124448Speter * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 30224448Speter * compatable. It says that setting the uid/gid to euid/egid is a special 30324448Speter * case of "appropriate privilege". Once the rules are expanded out, this 30424448Speter * basically means that setuid(nnn) sets all three id's, in all permitted 30524448Speter * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 30624448Speter * does not set the saved id - this is dangerous for traditional BSD 30724448Speter * programs. For this reason, we *really* do not want to set 30824448Speter * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 30924448Speter */ 31024448Speter#define POSIX_APPENDIX_B_4_2_2 31124448Speter 31212221Sbde#ifndef _SYS_SYSPROTO_H_ 3131541Srgrimesstruct setuid_args { 3141541Srgrimes uid_t uid; 3151541Srgrimes}; 31612221Sbde#endif 3171541Srgrimes/* ARGSUSED */ 3181549Srgrimesint 3191541Srgrimessetuid(p, uap, retval) 3201541Srgrimes struct proc *p; 3211541Srgrimes struct setuid_args *uap; 3221541Srgrimes int *retval; 3231541Srgrimes{ 3241541Srgrimes register struct pcred *pc = p->p_cred; 3251541Srgrimes register uid_t uid; 3261541Srgrimes int error; 3271541Srgrimes 32824448Speter /* 32924448Speter * See if we have "permission" by POSIX 1003.1 rules. 33024448Speter * 33124448Speter * Note that setuid(geteuid()) is a special case of 33224448Speter * "appropriate privileges" in appendix B.4.2.2. We need 33324448Speter * to use this clause to be compatable with traditional BSD 33424448Speter * semantics. Basically, it means that "setuid(xx)" sets all 33524448Speter * three id's (assuming you have privs). 33624448Speter * 33724448Speter * Notes on the logic. We do things in three steps. 33824448Speter * 1: We determine if the euid is going to change, and do EPERM 33924448Speter * right away. We unconditionally change the euid later if this 34024448Speter * test is satisfied, simplifying that part of the logic. 34124448Speter * 2: We determine if the real and/or saved uid's are going to 34224448Speter * change. Determined by compile options. 34324448Speter * 3: Change euid last. (after tests in #2 for "appropriate privs") 34424448Speter */ 3451541Srgrimes uid = uap->uid; 34624448Speter if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 34717994Sache#ifdef _POSIX_SAVED_IDS 34824448Speter uid != pc->p_svuid && /* allow setuid(saved gid) */ 34917994Sache#endif 35024448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 35124448Speter uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 35224448Speter#endif 3538162Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 3541541Srgrimes return (error); 35524448Speter 35624448Speter#ifdef _POSIX_SAVED_IDS 3571541Srgrimes /* 35824448Speter * Do we have "appropriate privileges" (are we root or uid == euid) 35924448Speter * If so, we are changing the real uid and/or saved uid. 3601541Srgrimes */ 36117994Sache if ( 36224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 36324448Speter uid == pc->pc_ucred->cr_uid || 36417994Sache#endif 36524448Speter suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 36617994Sache#endif 36724448Speter { 36824448Speter /* 36924448Speter * Transfer proc count to new user. 37024448Speter */ 37124448Speter if (uid != pc->p_ruid) { 37224448Speter (void)chgproccnt(pc->p_ruid, -1); 37324448Speter (void)chgproccnt(uid, 1); 37424448Speter } 37524448Speter /* 37624448Speter * Set real uid 37724448Speter */ 37824448Speter if (uid != pc->p_ruid) { 37924448Speter p->p_flag |= P_SUGID; 38024448Speter pc->p_ruid = uid; 38124448Speter } 38224448Speter /* 38324448Speter * Set saved uid 38424448Speter * 38524448Speter * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 38624448Speter * the security of seteuid() depends on it. B.4.2.2 says it 38724448Speter * is important that we should do this. 38824448Speter */ 38924448Speter if (pc->p_svuid != uid) { 39024448Speter p->p_flag |= P_SUGID; 39124448Speter pc->p_svuid = uid; 39224448Speter } 3938141Sache } 39424448Speter 39524448Speter /* 39624448Speter * In all permitted cases, we are changing the euid. 39724448Speter * Copy credentials so other references do not see our changes. 39824448Speter */ 39924448Speter if (pc->pc_ucred->cr_uid != uid) { 40024448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 40124448Speter pc->pc_ucred->cr_uid = uid; 40224448Speter p->p_flag |= P_SUGID; 40324448Speter } 4041541Srgrimes return (0); 4051541Srgrimes} 4061541Srgrimes 40712221Sbde#ifndef _SYS_SYSPROTO_H_ 4081541Srgrimesstruct seteuid_args { 4091541Srgrimes uid_t euid; 4101541Srgrimes}; 41112221Sbde#endif 4121541Srgrimes/* ARGSUSED */ 4131549Srgrimesint 4141541Srgrimesseteuid(p, uap, retval) 4151541Srgrimes struct proc *p; 4161541Srgrimes struct seteuid_args *uap; 4171541Srgrimes int *retval; 4181541Srgrimes{ 4191541Srgrimes register struct pcred *pc = p->p_cred; 4201541Srgrimes register uid_t euid; 4211541Srgrimes int error; 4221541Srgrimes 4231541Srgrimes euid = uap->euid; 42424449Speter if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 42524449Speter euid != pc->p_svuid && /* allow seteuid(saved uid) */ 4261541Srgrimes (error = suser(pc->pc_ucred, &p->p_acflag))) 4271541Srgrimes return (error); 4281541Srgrimes /* 4291541Srgrimes * Everything's okay, do it. Copy credentials so other references do 4301541Srgrimes * not see our changes. 4311541Srgrimes */ 43224449Speter if (pc->pc_ucred->cr_uid != euid) { 43324449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 43424449Speter pc->pc_ucred->cr_uid = euid; 43524449Speter p->p_flag |= P_SUGID; 43624449Speter } 4371541Srgrimes return (0); 4381541Srgrimes} 4391541Srgrimes 44012221Sbde#ifndef _SYS_SYSPROTO_H_ 4411541Srgrimesstruct setgid_args { 4421541Srgrimes gid_t gid; 4431541Srgrimes}; 44412221Sbde#endif 4451541Srgrimes/* ARGSUSED */ 4461549Srgrimesint 4471541Srgrimessetgid(p, uap, retval) 4481541Srgrimes struct proc *p; 4491541Srgrimes struct setgid_args *uap; 4501541Srgrimes int *retval; 4511541Srgrimes{ 4521541Srgrimes register struct pcred *pc = p->p_cred; 4531541Srgrimes register gid_t gid; 4541541Srgrimes int error; 4551541Srgrimes 45624448Speter /* 45724448Speter * See if we have "permission" by POSIX 1003.1 rules. 45824448Speter * 45924448Speter * Note that setgid(getegid()) is a special case of 46024448Speter * "appropriate privileges" in appendix B.4.2.2. We need 46124448Speter * to use this clause to be compatable with traditional BSD 46224448Speter * semantics. Basically, it means that "setgid(xx)" sets all 46324448Speter * three id's (assuming you have privs). 46424448Speter * 46524448Speter * For notes on the logic here, see setuid() above. 46624448Speter */ 4671541Srgrimes gid = uap->gid; 46824448Speter if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 46917994Sache#ifdef _POSIX_SAVED_IDS 47024448Speter gid != pc->p_svgid && /* allow setgid(saved gid) */ 47117994Sache#endif 47224448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 47324448Speter gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 47424448Speter#endif 4758162Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 4761541Srgrimes return (error); 47724448Speter 47817994Sache#ifdef _POSIX_SAVED_IDS 47924448Speter /* 48024448Speter * Do we have "appropriate privileges" (are we root or gid == egid) 48124448Speter * If so, we are changing the real uid and saved gid. 48224448Speter */ 48324448Speter if ( 48424448Speter#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 48524448Speter gid == pc->pc_ucred->cr_groups[0] || 48617994Sache#endif 48724448Speter suser(pc->pc_ucred, &p->p_acflag) == 0) /* we are using privs */ 48824448Speter#endif 48924448Speter { 49024448Speter /* 49124448Speter * Set real gid 49224448Speter */ 49324448Speter if (pc->p_rgid != gid) { 49424448Speter p->p_flag |= P_SUGID; 49524448Speter pc->p_rgid = gid; 49624448Speter } 49724448Speter /* 49824448Speter * Set saved gid 49924448Speter * 50024448Speter * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 50124448Speter * the security of setegid() depends on it. B.4.2.2 says it 50224448Speter * is important that we should do this. 50324448Speter */ 50424448Speter if (pc->p_svgid != gid) { 50524448Speter p->p_flag |= P_SUGID; 50624448Speter pc->p_svgid = gid; 50724448Speter } 5088141Sache } 50924448Speter /* 51024448Speter * In all cases permitted cases, we are changing the egid. 51124448Speter * Copy credentials so other references do not see our changes. 51224448Speter */ 51324448Speter if (pc->pc_ucred->cr_groups[0] != gid) { 51424448Speter pc->pc_ucred = crcopy(pc->pc_ucred); 51524448Speter pc->pc_ucred->cr_groups[0] = gid; 51624448Speter p->p_flag |= P_SUGID; 51724448Speter } 5181541Srgrimes return (0); 5191541Srgrimes} 5201541Srgrimes 52112221Sbde#ifndef _SYS_SYSPROTO_H_ 5221541Srgrimesstruct setegid_args { 5231541Srgrimes gid_t egid; 5241541Srgrimes}; 52512221Sbde#endif 5261541Srgrimes/* ARGSUSED */ 5271549Srgrimesint 5281541Srgrimessetegid(p, uap, retval) 5291541Srgrimes struct proc *p; 5301541Srgrimes struct setegid_args *uap; 5311541Srgrimes int *retval; 5321541Srgrimes{ 5331541Srgrimes register struct pcred *pc = p->p_cred; 5341541Srgrimes register gid_t egid; 5351541Srgrimes int error; 5361541Srgrimes 5371541Srgrimes egid = uap->egid; 53824449Speter if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 53924449Speter egid != pc->p_svgid && /* allow setegid(saved gid) */ 5401541Srgrimes (error = suser(pc->pc_ucred, &p->p_acflag))) 5411541Srgrimes return (error); 54224449Speter if (pc->pc_ucred->cr_groups[0] != egid) { 54324449Speter pc->pc_ucred = crcopy(pc->pc_ucred); 54424449Speter pc->pc_ucred->cr_groups[0] = egid; 54524449Speter p->p_flag |= P_SUGID; 54624449Speter } 5471541Srgrimes return (0); 5481541Srgrimes} 5491541Srgrimes 55012221Sbde#ifndef _SYS_SYSPROTO_H_ 5511541Srgrimesstruct setgroups_args { 5521541Srgrimes u_int gidsetsize; 5531541Srgrimes gid_t *gidset; 5541541Srgrimes}; 55512221Sbde#endif 5561541Srgrimes/* ARGSUSED */ 5571549Srgrimesint 5581541Srgrimessetgroups(p, uap, retval) 5591541Srgrimes struct proc *p; 5601541Srgrimes struct setgroups_args *uap; 5611541Srgrimes int *retval; 5621541Srgrimes{ 5631541Srgrimes register struct pcred *pc = p->p_cred; 5641541Srgrimes register u_int ngrp; 5651541Srgrimes int error; 5661541Srgrimes 5673098Sphk if ((error = suser(pc->pc_ucred, &p->p_acflag))) 5681541Srgrimes return (error); 56912063Sdg ngrp = uap->gidsetsize; 57024447Speter if (ngrp > NGROUPS) 5711541Srgrimes return (EINVAL); 57224447Speter /* 57324447Speter * XXX A little bit lazy here. We could test if anything has 57424447Speter * changed before crcopy() and setting P_SUGID. 57524447Speter */ 5761541Srgrimes pc->pc_ucred = crcopy(pc->pc_ucred); 57724447Speter if (ngrp < 1) { 57824447Speter /* 57924447Speter * setgroups(0, NULL) is a legitimate way of clearing the 58024447Speter * groups vector on non-BSD systems (which generally do not 58124447Speter * have the egid in the groups[0]). We risk security holes 58224447Speter * when running non-BSD software if we do not do the same. 58324447Speter */ 58424447Speter pc->pc_ucred->cr_ngroups = 1; 58524447Speter } else { 58624447Speter if ((error = copyin((caddr_t)uap->gidset, 58724447Speter (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 58824447Speter return (error); 58924447Speter pc->pc_ucred->cr_ngroups = ngrp; 59024447Speter } 5911541Srgrimes p->p_flag |= P_SUGID; 5921541Srgrimes return (0); 5931541Srgrimes} 5941541Srgrimes 59512221Sbde#ifndef _SYS_SYSPROTO_H_ 5961541Srgrimesstruct setreuid_args { 5979238Sache uid_t ruid; 5989238Sache uid_t euid; 5991541Srgrimes}; 60012221Sbde#endif 6011541Srgrimes/* ARGSUSED */ 6021549Srgrimesint 6038019Sachesetreuid(p, uap, retval) 6041541Srgrimes register struct proc *p; 6051541Srgrimes struct setreuid_args *uap; 6061541Srgrimes int *retval; 6071541Srgrimes{ 6081541Srgrimes register struct pcred *pc = p->p_cred; 6099238Sache register uid_t ruid, euid; 6108135Sache int error; 6111541Srgrimes 6129238Sache ruid = uap->ruid; 6139238Sache euid = uap->euid; 6149238Sache if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid || 61524559Speter euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 61624559Speter euid != pc->p_ruid && euid != pc->p_svuid) && 6178135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6188135Sache return (error); 6199238Sache 62024450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 62124450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6229238Sache pc->pc_ucred->cr_uid = euid; 62324450Speter p->p_flag |= P_SUGID; 62424450Speter } 62524450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 6269238Sache (void)chgproccnt(pc->p_ruid, -1); 6279238Sache (void)chgproccnt(ruid, 1); 6289238Sache pc->p_ruid = ruid; 62924450Speter p->p_flag |= P_SUGID; 6308135Sache } 63124559Speter if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 63224559Speter pc->p_svuid != pc->pc_ucred->cr_uid) { 6338111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 63424450Speter p->p_flag |= P_SUGID; 63524450Speter } 6368135Sache return (0); 6371541Srgrimes} 6381541Srgrimes 63912221Sbde#ifndef _SYS_SYSPROTO_H_ 6401541Srgrimesstruct setregid_args { 6419238Sache gid_t rgid; 6429238Sache gid_t egid; 6431541Srgrimes}; 64412221Sbde#endif 6451541Srgrimes/* ARGSUSED */ 6461549Srgrimesint 6478019Sachesetregid(p, uap, retval) 6481541Srgrimes register struct proc *p; 6491541Srgrimes struct setregid_args *uap; 6501541Srgrimes int *retval; 6511541Srgrimes{ 6521541Srgrimes register struct pcred *pc = p->p_cred; 6539238Sache register gid_t rgid, egid; 6548135Sache int error; 6551541Srgrimes 6569238Sache rgid = uap->rgid; 6579238Sache egid = uap->egid; 6589238Sache if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 65924559Speter egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 66024559Speter egid != pc->p_rgid && egid != pc->p_svgid) && 6618135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6628135Sache return (error); 6639238Sache 66424450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 66524450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6669238Sache pc->pc_ucred->cr_groups[0] = egid; 66724450Speter p->p_flag |= P_SUGID; 66824450Speter } 66924450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 6709238Sache pc->p_rgid = rgid; 67124450Speter p->p_flag |= P_SUGID; 67224450Speter } 67324559Speter if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 67424559Speter pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 6758111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 67624450Speter p->p_flag |= P_SUGID; 67724450Speter } 6788135Sache return (0); 6791541Srgrimes} 6801541Srgrimes 68124453Speter#ifndef _SYS_SYSPROTO_H_ 68224453Speterstruct issetugid_args { 68324453Speter int dummy; 68424453Speter}; 68524453Speter#endif 68624453Speter/* ARGSUSED */ 68724453Speterint 68824453Speterissetugid(p, uap, retval) 68924453Speter register struct proc *p; 69024453Speter struct issetugid_args *uap; 69124453Speter int *retval; 69224453Speter{ 69324453Speter /* 69424453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 69524453Speter * we use P_SUGID because we consider changing the owners as 69624453Speter * "tainting" as well. 69724453Speter * This is significant for procs that start as root and "become" 69824453Speter * a user without an exec - programs cannot know *everything* 69924453Speter * that libc *might* have put in their data segment. 70024453Speter */ 70124453Speter if (p->p_flag & P_SUGID) 70224453Speter return (1); 70324453Speter return (0); 70424453Speter} 70524453Speter 7061541Srgrimes/* 7071541Srgrimes * Check if gid is a member of the group set. 7081541Srgrimes */ 7091549Srgrimesint 7101541Srgrimesgroupmember(gid, cred) 7111541Srgrimes gid_t gid; 7121541Srgrimes register struct ucred *cred; 7131541Srgrimes{ 7141541Srgrimes register gid_t *gp; 7151541Srgrimes gid_t *egp; 7161541Srgrimes 7171541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 7181541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 7191541Srgrimes if (*gp == gid) 7201541Srgrimes return (1); 7211541Srgrimes return (0); 7221541Srgrimes} 7231541Srgrimes 7241541Srgrimes/* 7251541Srgrimes * Test whether the specified credentials imply "super-user" 7261541Srgrimes * privilege; if so, and we have accounting info, set the flag 7271541Srgrimes * indicating use of super-powers. 7281541Srgrimes * Returns 0 or error. 7291541Srgrimes */ 7301549Srgrimesint 7311541Srgrimessuser(cred, acflag) 7321541Srgrimes struct ucred *cred; 7338011Sbde u_short *acflag; 7341541Srgrimes{ 7351541Srgrimes if (cred->cr_uid == 0) { 7361541Srgrimes if (acflag) 7371541Srgrimes *acflag |= ASU; 7381541Srgrimes return (0); 7391541Srgrimes } 7401541Srgrimes return (EPERM); 7411541Srgrimes} 7421541Srgrimes 7431541Srgrimes/* 7441541Srgrimes * Allocate a zeroed cred structure. 7451541Srgrimes */ 7461541Srgrimesstruct ucred * 7471541Srgrimescrget() 7481541Srgrimes{ 7491541Srgrimes register struct ucred *cr; 7501541Srgrimes 7511541Srgrimes MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 7521541Srgrimes bzero((caddr_t)cr, sizeof(*cr)); 7531541Srgrimes cr->cr_ref = 1; 7541541Srgrimes return (cr); 7551541Srgrimes} 7561541Srgrimes 7571541Srgrimes/* 7581541Srgrimes * Free a cred structure. 7591541Srgrimes * Throws away space when ref count gets to 0. 7601541Srgrimes */ 7611549Srgrimesvoid 7621541Srgrimescrfree(cr) 7631541Srgrimes struct ucred *cr; 7641541Srgrimes{ 7651541Srgrimes int s; 7661541Srgrimes 7671541Srgrimes s = splimp(); /* ??? */ 7681541Srgrimes if (--cr->cr_ref == 0) 7691541Srgrimes FREE((caddr_t)cr, M_CRED); 7701541Srgrimes (void) splx(s); 7711541Srgrimes} 7721541Srgrimes 7731541Srgrimes/* 7741541Srgrimes * Copy cred structure to a new one and free the old one. 7751541Srgrimes */ 7761541Srgrimesstruct ucred * 7771541Srgrimescrcopy(cr) 7781541Srgrimes struct ucred *cr; 7791541Srgrimes{ 7801541Srgrimes struct ucred *newcr; 7811541Srgrimes 7821541Srgrimes if (cr->cr_ref == 1) 7831541Srgrimes return (cr); 7841541Srgrimes newcr = crget(); 7851541Srgrimes *newcr = *cr; 7861541Srgrimes crfree(cr); 7871541Srgrimes newcr->cr_ref = 1; 7881541Srgrimes return (newcr); 7891541Srgrimes} 7901541Srgrimes 7911541Srgrimes/* 7921541Srgrimes * Dup cred struct to a new held one. 7931541Srgrimes */ 7941541Srgrimesstruct ucred * 7951541Srgrimescrdup(cr) 7961541Srgrimes struct ucred *cr; 7971541Srgrimes{ 7981541Srgrimes struct ucred *newcr; 7991541Srgrimes 8001541Srgrimes newcr = crget(); 8011541Srgrimes *newcr = *cr; 8021541Srgrimes newcr->cr_ref = 1; 8031541Srgrimes return (newcr); 8041541Srgrimes} 8051541Srgrimes 8061541Srgrimes/* 8071541Srgrimes * Get login name, if available. 8081541Srgrimes */ 80912221Sbde#ifndef _SYS_SYSPROTO_H_ 8101541Srgrimesstruct getlogin_args { 8111541Srgrimes char *namebuf; 8121541Srgrimes u_int namelen; 8131541Srgrimes}; 81412221Sbde#endif 8151541Srgrimes/* ARGSUSED */ 8161549Srgrimesint 8171541Srgrimesgetlogin(p, uap, retval) 8181541Srgrimes struct proc *p; 8191541Srgrimes struct getlogin_args *uap; 8201541Srgrimes int *retval; 8211541Srgrimes{ 8221541Srgrimes 82323358Sache if (uap->namelen > MAXLOGNAME) 82423359Sache uap->namelen = MAXLOGNAME; 8251541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 8261541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 8271541Srgrimes} 8281541Srgrimes 8291541Srgrimes/* 8301541Srgrimes * Set login name. 8311541Srgrimes */ 83212221Sbde#ifndef _SYS_SYSPROTO_H_ 8331541Srgrimesstruct setlogin_args { 8341541Srgrimes char *namebuf; 8351541Srgrimes}; 83612221Sbde#endif 8371541Srgrimes/* ARGSUSED */ 8381549Srgrimesint 8391541Srgrimessetlogin(p, uap, retval) 8401541Srgrimes struct proc *p; 8411541Srgrimes struct setlogin_args *uap; 8421541Srgrimes int *retval; 8431541Srgrimes{ 8441541Srgrimes int error; 84523330Sache char logintmp[MAXLOGNAME]; 8461541Srgrimes 8473098Sphk if ((error = suser(p->p_ucred, &p->p_acflag))) 8481541Srgrimes return (error); 84922522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 85022522Sdavidn sizeof(logintmp), (u_int *)0); 8511541Srgrimes if (error == ENAMETOOLONG) 8521541Srgrimes error = EINVAL; 85322522Sdavidn else if (!error) 85422522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 85523330Sache sizeof(logintmp)); 8561541Srgrimes return (error); 8571541Srgrimes} 858