kern_prot.c revision 24453
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 3924453Speter * $Id: kern_prot.c,v 1.30 1997/03/31 13:47:00 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 || 6159238Sache euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) && 6168135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6178135Sache return (error); 6189238Sache 61924450Speter if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 62024450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6219238Sache pc->pc_ucred->cr_uid = euid; 62224450Speter p->p_flag |= P_SUGID; 62324450Speter } 62424450Speter if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 6259238Sache (void)chgproccnt(pc->p_ruid, -1); 6269238Sache (void)chgproccnt(ruid, 1); 6279238Sache pc->p_ruid = ruid; 62824450Speter p->p_flag |= P_SUGID; 6298135Sache } 63024450Speter if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) { 6318111Sache pc->p_svuid = pc->pc_ucred->cr_uid; 63224450Speter p->p_flag |= P_SUGID; 63324450Speter } 6348135Sache return (0); 6351541Srgrimes} 6361541Srgrimes 63712221Sbde#ifndef _SYS_SYSPROTO_H_ 6381541Srgrimesstruct setregid_args { 6399238Sache gid_t rgid; 6409238Sache gid_t egid; 6411541Srgrimes}; 64212221Sbde#endif 6431541Srgrimes/* ARGSUSED */ 6441549Srgrimesint 6458019Sachesetregid(p, uap, retval) 6461541Srgrimes register struct proc *p; 6471541Srgrimes struct setregid_args *uap; 6481541Srgrimes int *retval; 6491541Srgrimes{ 6501541Srgrimes register struct pcred *pc = p->p_cred; 6519238Sache register gid_t rgid, egid; 6528135Sache int error; 6531541Srgrimes 6549238Sache rgid = uap->rgid; 6559238Sache egid = uap->egid; 6569238Sache if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid || 6579238Sache egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) && 6588135Sache (error = suser(pc->pc_ucred, &p->p_acflag))) 6598135Sache return (error); 6609238Sache 66124450Speter if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 66224450Speter pc->pc_ucred = crcopy(pc->pc_ucred); 6639238Sache pc->pc_ucred->cr_groups[0] = egid; 66424450Speter p->p_flag |= P_SUGID; 66524450Speter } 66624450Speter if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 6679238Sache pc->p_rgid = rgid; 66824450Speter p->p_flag |= P_SUGID; 66924450Speter } 67024450Speter if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) { 6718111Sache pc->p_svgid = pc->pc_ucred->cr_groups[0]; 67224450Speter p->p_flag |= P_SUGID; 67324450Speter } 6748135Sache return (0); 6751541Srgrimes} 6761541Srgrimes 67724453Speter#ifndef _SYS_SYSPROTO_H_ 67824453Speterstruct issetugid_args { 67924453Speter int dummy; 68024453Speter}; 68124453Speter#endif 68224453Speter/* ARGSUSED */ 68324453Speterint 68424453Speterissetugid(p, uap, retval) 68524453Speter register struct proc *p; 68624453Speter struct issetugid_args *uap; 68724453Speter int *retval; 68824453Speter{ 68924453Speter /* 69024453Speter * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 69124453Speter * we use P_SUGID because we consider changing the owners as 69224453Speter * "tainting" as well. 69324453Speter * This is significant for procs that start as root and "become" 69424453Speter * a user without an exec - programs cannot know *everything* 69524453Speter * that libc *might* have put in their data segment. 69624453Speter */ 69724453Speter if (p->p_flag & P_SUGID) 69824453Speter return (1); 69924453Speter return (0); 70024453Speter} 70124453Speter 7021541Srgrimes/* 7031541Srgrimes * Check if gid is a member of the group set. 7041541Srgrimes */ 7051549Srgrimesint 7061541Srgrimesgroupmember(gid, cred) 7071541Srgrimes gid_t gid; 7081541Srgrimes register struct ucred *cred; 7091541Srgrimes{ 7101541Srgrimes register gid_t *gp; 7111541Srgrimes gid_t *egp; 7121541Srgrimes 7131541Srgrimes egp = &(cred->cr_groups[cred->cr_ngroups]); 7141541Srgrimes for (gp = cred->cr_groups; gp < egp; gp++) 7151541Srgrimes if (*gp == gid) 7161541Srgrimes return (1); 7171541Srgrimes return (0); 7181541Srgrimes} 7191541Srgrimes 7201541Srgrimes/* 7211541Srgrimes * Test whether the specified credentials imply "super-user" 7221541Srgrimes * privilege; if so, and we have accounting info, set the flag 7231541Srgrimes * indicating use of super-powers. 7241541Srgrimes * Returns 0 or error. 7251541Srgrimes */ 7261549Srgrimesint 7271541Srgrimessuser(cred, acflag) 7281541Srgrimes struct ucred *cred; 7298011Sbde u_short *acflag; 7301541Srgrimes{ 7311541Srgrimes if (cred->cr_uid == 0) { 7321541Srgrimes if (acflag) 7331541Srgrimes *acflag |= ASU; 7341541Srgrimes return (0); 7351541Srgrimes } 7361541Srgrimes return (EPERM); 7371541Srgrimes} 7381541Srgrimes 7391541Srgrimes/* 7401541Srgrimes * Allocate a zeroed cred structure. 7411541Srgrimes */ 7421541Srgrimesstruct ucred * 7431541Srgrimescrget() 7441541Srgrimes{ 7451541Srgrimes register struct ucred *cr; 7461541Srgrimes 7471541Srgrimes MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 7481541Srgrimes bzero((caddr_t)cr, sizeof(*cr)); 7491541Srgrimes cr->cr_ref = 1; 7501541Srgrimes return (cr); 7511541Srgrimes} 7521541Srgrimes 7531541Srgrimes/* 7541541Srgrimes * Free a cred structure. 7551541Srgrimes * Throws away space when ref count gets to 0. 7561541Srgrimes */ 7571549Srgrimesvoid 7581541Srgrimescrfree(cr) 7591541Srgrimes struct ucred *cr; 7601541Srgrimes{ 7611541Srgrimes int s; 7621541Srgrimes 7631541Srgrimes s = splimp(); /* ??? */ 7641541Srgrimes if (--cr->cr_ref == 0) 7651541Srgrimes FREE((caddr_t)cr, M_CRED); 7661541Srgrimes (void) splx(s); 7671541Srgrimes} 7681541Srgrimes 7691541Srgrimes/* 7701541Srgrimes * Copy cred structure to a new one and free the old one. 7711541Srgrimes */ 7721541Srgrimesstruct ucred * 7731541Srgrimescrcopy(cr) 7741541Srgrimes struct ucred *cr; 7751541Srgrimes{ 7761541Srgrimes struct ucred *newcr; 7771541Srgrimes 7781541Srgrimes if (cr->cr_ref == 1) 7791541Srgrimes return (cr); 7801541Srgrimes newcr = crget(); 7811541Srgrimes *newcr = *cr; 7821541Srgrimes crfree(cr); 7831541Srgrimes newcr->cr_ref = 1; 7841541Srgrimes return (newcr); 7851541Srgrimes} 7861541Srgrimes 7871541Srgrimes/* 7881541Srgrimes * Dup cred struct to a new held one. 7891541Srgrimes */ 7901541Srgrimesstruct ucred * 7911541Srgrimescrdup(cr) 7921541Srgrimes struct ucred *cr; 7931541Srgrimes{ 7941541Srgrimes struct ucred *newcr; 7951541Srgrimes 7961541Srgrimes newcr = crget(); 7971541Srgrimes *newcr = *cr; 7981541Srgrimes newcr->cr_ref = 1; 7991541Srgrimes return (newcr); 8001541Srgrimes} 8011541Srgrimes 8021541Srgrimes/* 8031541Srgrimes * Get login name, if available. 8041541Srgrimes */ 80512221Sbde#ifndef _SYS_SYSPROTO_H_ 8061541Srgrimesstruct getlogin_args { 8071541Srgrimes char *namebuf; 8081541Srgrimes u_int namelen; 8091541Srgrimes}; 81012221Sbde#endif 8111541Srgrimes/* ARGSUSED */ 8121549Srgrimesint 8131541Srgrimesgetlogin(p, uap, retval) 8141541Srgrimes struct proc *p; 8151541Srgrimes struct getlogin_args *uap; 8161541Srgrimes int *retval; 8171541Srgrimes{ 8181541Srgrimes 81923358Sache if (uap->namelen > MAXLOGNAME) 82023359Sache uap->namelen = MAXLOGNAME; 8211541Srgrimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 8221541Srgrimes (caddr_t) uap->namebuf, uap->namelen)); 8231541Srgrimes} 8241541Srgrimes 8251541Srgrimes/* 8261541Srgrimes * Set login name. 8271541Srgrimes */ 82812221Sbde#ifndef _SYS_SYSPROTO_H_ 8291541Srgrimesstruct setlogin_args { 8301541Srgrimes char *namebuf; 8311541Srgrimes}; 83212221Sbde#endif 8331541Srgrimes/* ARGSUSED */ 8341549Srgrimesint 8351541Srgrimessetlogin(p, uap, retval) 8361541Srgrimes struct proc *p; 8371541Srgrimes struct setlogin_args *uap; 8381541Srgrimes int *retval; 8391541Srgrimes{ 8401541Srgrimes int error; 84123330Sache char logintmp[MAXLOGNAME]; 8421541Srgrimes 8433098Sphk if ((error = suser(p->p_ucred, &p->p_acflag))) 8441541Srgrimes return (error); 84522522Sdavidn error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 84622522Sdavidn sizeof(logintmp), (u_int *)0); 8471541Srgrimes if (error == ENAMETOOLONG) 8481541Srgrimes error = EINVAL; 84922522Sdavidn else if (!error) 85022522Sdavidn (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 85123330Sache sizeof(logintmp)); 8521541Srgrimes return (error); 8531541Srgrimes} 854