1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 39c3aac50fSPeter Wemm * $FreeBSD$ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 42df8bae1dSRodney W. Grimes /* 43df8bae1dSRodney W. Grimes * System calls related to processes and protection 44df8bae1dSRodney W. Grimes */ 45df8bae1dSRodney W. Grimes 465591b823SEivind Eklund #include "opt_compat.h" 47130d0157SRobert Watson #include "opt_global.h" 485591b823SEivind Eklund 49df8bae1dSRodney W. Grimes #include <sys/param.h> 50df8bae1dSRodney W. Grimes #include <sys/systm.h> 51fb919e4dSMark Murray #include <sys/acct.h> 521c5bb3eaSPeter Wemm #include <sys/kernel.h> 5398f03f90SJake Burkholder #include <sys/lock.h> 54fb919e4dSMark Murray #include <sys/mutex.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 56fb919e4dSMark Murray #include <sys/sysproto.h> 57df8bae1dSRodney W. Grimes #include <sys/malloc.h> 58d5f81602SSean Eric Fagan #include <sys/pioctl.h> 59f535380cSDon Lewis #include <sys/resourcevar.h> 60579f4eb4SRobert Watson #include <sys/sysctl.h> 6191421ba2SRobert Watson #include <sys/jail.h> 62df8bae1dSRodney W. Grimes 63a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 64a1c995b6SPoul-Henning Kamp 65d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 66ad7507e2SSteven Wallace struct getpid_args { 67df8bae1dSRodney W. Grimes int dummy; 68df8bae1dSRodney W. Grimes }; 69d2d3e875SBruce Evans #endif 70df8bae1dSRodney W. Grimes 7136e9f877SMatthew Dillon /* 7298f03f90SJake Burkholder * getpid - MP SAFE 7336e9f877SMatthew Dillon */ 7498f03f90SJake Burkholder 75df8bae1dSRodney W. Grimes /* ARGSUSED */ 7626f9a767SRodney W. Grimes int 77cb226aaaSPoul-Henning Kamp getpid(p, uap) 78df8bae1dSRodney W. Grimes struct proc *p; 79ad7507e2SSteven Wallace struct getpid_args *uap; 80df8bae1dSRodney W. Grimes { 81df8bae1dSRodney W. Grimes 82cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pid; 83df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 84bae3a80bSJohn Baldwin PROC_LOCK(p); 85cb226aaaSPoul-Henning Kamp p->p_retval[1] = p->p_pptr->p_pid; 86bae3a80bSJohn Baldwin PROC_UNLOCK(p); 87df8bae1dSRodney W. Grimes #endif 88df8bae1dSRodney W. Grimes return (0); 89df8bae1dSRodney W. Grimes } 90df8bae1dSRodney W. Grimes 9198f03f90SJake Burkholder /* 9298f03f90SJake Burkholder * getppid - MP SAFE 9398f03f90SJake Burkholder */ 9498f03f90SJake Burkholder 95d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 96ad7507e2SSteven Wallace struct getppid_args { 97ad7507e2SSteven Wallace int dummy; 98ad7507e2SSteven Wallace }; 99d2d3e875SBruce Evans #endif 100df8bae1dSRodney W. Grimes /* ARGSUSED */ 10126f9a767SRodney W. Grimes int 102cb226aaaSPoul-Henning Kamp getppid(p, uap) 103df8bae1dSRodney W. Grimes struct proc *p; 104ad7507e2SSteven Wallace struct getppid_args *uap; 105df8bae1dSRodney W. Grimes { 106df8bae1dSRodney W. Grimes 107bae3a80bSJohn Baldwin PROC_LOCK(p); 108cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pptr->p_pid; 109bae3a80bSJohn Baldwin PROC_UNLOCK(p); 110df8bae1dSRodney W. Grimes return (0); 111df8bae1dSRodney W. Grimes } 112df8bae1dSRodney W. Grimes 11336e9f877SMatthew Dillon /* 11436e9f877SMatthew Dillon * Get process group ID; note that POSIX getpgrp takes no parameter 11536e9f877SMatthew Dillon * 11636e9f877SMatthew Dillon * MP SAFE 11736e9f877SMatthew Dillon */ 118d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 119ad7507e2SSteven Wallace struct getpgrp_args { 120ad7507e2SSteven Wallace int dummy; 121ad7507e2SSteven Wallace }; 122d2d3e875SBruce Evans #endif 123ad7507e2SSteven Wallace 12426f9a767SRodney W. Grimes int 125cb226aaaSPoul-Henning Kamp getpgrp(p, uap) 126df8bae1dSRodney W. Grimes struct proc *p; 127ad7507e2SSteven Wallace struct getpgrp_args *uap; 128df8bae1dSRodney W. Grimes { 129df8bae1dSRodney W. Grimes 130cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pgrp->pg_id; 131df8bae1dSRodney W. Grimes return (0); 132df8bae1dSRodney W. Grimes } 133df8bae1dSRodney W. Grimes 1341a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1351a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1361a5018a0SPeter Wemm struct getpgid_args { 1371a5018a0SPeter Wemm pid_t pid; 1381a5018a0SPeter Wemm }; 1391a5018a0SPeter Wemm #endif 1401a5018a0SPeter Wemm 1411a5018a0SPeter Wemm int 142cb226aaaSPoul-Henning Kamp getpgid(p, uap) 1431a5018a0SPeter Wemm struct proc *p; 1441a5018a0SPeter Wemm struct getpgid_args *uap; 1451a5018a0SPeter Wemm { 14665de0c7aSDon Lewis struct proc *pt; 147eb9e5c1dSRobert Watson int error; 14865de0c7aSDon Lewis 1491a5018a0SPeter Wemm if (uap->pid == 0) 15033a9ed9dSJohn Baldwin p->p_retval[0] = p->p_pgrp->pg_id; 15133a9ed9dSJohn Baldwin else { 15233a9ed9dSJohn Baldwin if ((pt = pfind(uap->pid)) == NULL) 1531a5018a0SPeter Wemm return ESRCH; 15433a9ed9dSJohn Baldwin if ((error = p_can(p, pt, P_CAN_SEE, NULL))) { 15533a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 156eb9e5c1dSRobert Watson return (error); 15733a9ed9dSJohn Baldwin } 15865de0c7aSDon Lewis p->p_retval[0] = pt->p_pgrp->pg_id; 15933a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 16033a9ed9dSJohn Baldwin } 1611a5018a0SPeter Wemm return 0; 1621a5018a0SPeter Wemm } 1631a5018a0SPeter Wemm 1641a5018a0SPeter Wemm /* 1651a5018a0SPeter Wemm * Get an arbitary pid's session id. 1661a5018a0SPeter Wemm */ 1671a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1681a5018a0SPeter Wemm struct getsid_args { 1691a5018a0SPeter Wemm pid_t pid; 1701a5018a0SPeter Wemm }; 1711a5018a0SPeter Wemm #endif 1721a5018a0SPeter Wemm 1731a5018a0SPeter Wemm int 174cb226aaaSPoul-Henning Kamp getsid(p, uap) 1751a5018a0SPeter Wemm struct proc *p; 1761a5018a0SPeter Wemm struct getsid_args *uap; 1771a5018a0SPeter Wemm { 17865de0c7aSDon Lewis struct proc *pt; 179eb9e5c1dSRobert Watson int error; 18065de0c7aSDon Lewis 1811a5018a0SPeter Wemm if (uap->pid == 0) 18233a9ed9dSJohn Baldwin p->p_retval[0] = p->p_session->s_sid; 18333a9ed9dSJohn Baldwin else { 18433a9ed9dSJohn Baldwin if ((pt = pfind(uap->pid)) == NULL) 1851a5018a0SPeter Wemm return ESRCH; 18633a9ed9dSJohn Baldwin if ((error = p_can(p, pt, P_CAN_SEE, NULL))) { 18733a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 188eb9e5c1dSRobert Watson return (error); 18933a9ed9dSJohn Baldwin } 19065de0c7aSDon Lewis p->p_retval[0] = pt->p_session->s_sid; 19133a9ed9dSJohn Baldwin PROC_UNLOCK(pt); 19233a9ed9dSJohn Baldwin } 1931a5018a0SPeter Wemm return 0; 1941a5018a0SPeter Wemm } 1951a5018a0SPeter Wemm 1961a5018a0SPeter Wemm 1977c8fdcbdSMatthew Dillon /* 1987c8fdcbdSMatthew Dillon * getuid() - MP SAFE 1997c8fdcbdSMatthew Dillon */ 200d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 201ad7507e2SSteven Wallace struct getuid_args { 202ad7507e2SSteven Wallace int dummy; 203ad7507e2SSteven Wallace }; 204d2d3e875SBruce Evans #endif 205ad7507e2SSteven Wallace 206df8bae1dSRodney W. Grimes /* ARGSUSED */ 20726f9a767SRodney W. Grimes int 208cb226aaaSPoul-Henning Kamp getuid(p, uap) 209df8bae1dSRodney W. Grimes struct proc *p; 210ad7507e2SSteven Wallace struct getuid_args *uap; 211df8bae1dSRodney W. Grimes { 212df8bae1dSRodney W. Grimes 213cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_cred->p_ruid; 214df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 215cb226aaaSPoul-Henning Kamp p->p_retval[1] = p->p_ucred->cr_uid; 216df8bae1dSRodney W. Grimes #endif 217df8bae1dSRodney W. Grimes return (0); 218df8bae1dSRodney W. Grimes } 219df8bae1dSRodney W. Grimes 2207c8fdcbdSMatthew Dillon /* 2217c8fdcbdSMatthew Dillon * geteuid() - MP SAFE 2227c8fdcbdSMatthew Dillon */ 223d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 224ad7507e2SSteven Wallace struct geteuid_args { 225ad7507e2SSteven Wallace int dummy; 226ad7507e2SSteven Wallace }; 227d2d3e875SBruce Evans #endif 228ad7507e2SSteven Wallace 229df8bae1dSRodney W. Grimes /* ARGSUSED */ 23026f9a767SRodney W. Grimes int 231cb226aaaSPoul-Henning Kamp geteuid(p, uap) 232df8bae1dSRodney W. Grimes struct proc *p; 233ad7507e2SSteven Wallace struct geteuid_args *uap; 234df8bae1dSRodney W. Grimes { 235df8bae1dSRodney W. Grimes 236cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_ucred->cr_uid; 237df8bae1dSRodney W. Grimes return (0); 238df8bae1dSRodney W. Grimes } 239df8bae1dSRodney W. Grimes 2407c8fdcbdSMatthew Dillon /* 2417c8fdcbdSMatthew Dillon * getgid() - MP SAFE 2427c8fdcbdSMatthew Dillon */ 243d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 244ad7507e2SSteven Wallace struct getgid_args { 245ad7507e2SSteven Wallace int dummy; 246ad7507e2SSteven Wallace }; 247d2d3e875SBruce Evans #endif 248ad7507e2SSteven Wallace 249df8bae1dSRodney W. Grimes /* ARGSUSED */ 25026f9a767SRodney W. Grimes int 251cb226aaaSPoul-Henning Kamp getgid(p, uap) 252df8bae1dSRodney W. Grimes struct proc *p; 253ad7507e2SSteven Wallace struct getgid_args *uap; 254df8bae1dSRodney W. Grimes { 255df8bae1dSRodney W. Grimes 256cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_cred->p_rgid; 257df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 258cb226aaaSPoul-Henning Kamp p->p_retval[1] = p->p_ucred->cr_groups[0]; 259df8bae1dSRodney W. Grimes #endif 260df8bae1dSRodney W. Grimes return (0); 261df8bae1dSRodney W. Grimes } 262df8bae1dSRodney W. Grimes 263df8bae1dSRodney W. Grimes /* 264df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 265df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 266df8bae1dSRodney W. Grimes * correctly in a library function. 267df8bae1dSRodney W. Grimes */ 268d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 269ad7507e2SSteven Wallace struct getegid_args { 270ad7507e2SSteven Wallace int dummy; 271ad7507e2SSteven Wallace }; 272d2d3e875SBruce Evans #endif 273ad7507e2SSteven Wallace 274df8bae1dSRodney W. Grimes /* ARGSUSED */ 27526f9a767SRodney W. Grimes int 276cb226aaaSPoul-Henning Kamp getegid(p, uap) 277df8bae1dSRodney W. Grimes struct proc *p; 278ad7507e2SSteven Wallace struct getegid_args *uap; 279df8bae1dSRodney W. Grimes { 280df8bae1dSRodney W. Grimes 281cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_ucred->cr_groups[0]; 282df8bae1dSRodney W. Grimes return (0); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes 285d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 286df8bae1dSRodney W. Grimes struct getgroups_args { 287df8bae1dSRodney W. Grimes u_int gidsetsize; 288df8bae1dSRodney W. Grimes gid_t *gidset; 289df8bae1dSRodney W. Grimes }; 290d2d3e875SBruce Evans #endif 29126f9a767SRodney W. Grimes int 292cb226aaaSPoul-Henning Kamp getgroups(p, uap) 293df8bae1dSRodney W. Grimes struct proc *p; 294df8bae1dSRodney W. Grimes register struct getgroups_args *uap; 295df8bae1dSRodney W. Grimes { 296df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 297df8bae1dSRodney W. Grimes register u_int ngrp; 298df8bae1dSRodney W. Grimes int error; 299df8bae1dSRodney W. Grimes 300df8bae1dSRodney W. Grimes if ((ngrp = uap->gidsetsize) == 0) { 301cb226aaaSPoul-Henning Kamp p->p_retval[0] = pc->pc_ucred->cr_ngroups; 302df8bae1dSRodney W. Grimes return (0); 303df8bae1dSRodney W. Grimes } 304df8bae1dSRodney W. Grimes if (ngrp < pc->pc_ucred->cr_ngroups) 305df8bae1dSRodney W. Grimes return (EINVAL); 306df8bae1dSRodney W. Grimes ngrp = pc->pc_ucred->cr_ngroups; 307bb56ec4aSPoul-Henning Kamp if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 308bb56ec4aSPoul-Henning Kamp (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 309df8bae1dSRodney W. Grimes return (error); 310cb226aaaSPoul-Henning Kamp p->p_retval[0] = ngrp; 311df8bae1dSRodney W. Grimes return (0); 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes 314d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 31582970b81SBruce Evans struct setsid_args { 316ad7507e2SSteven Wallace int dummy; 317ad7507e2SSteven Wallace }; 318d2d3e875SBruce Evans #endif 319ad7507e2SSteven Wallace 320df8bae1dSRodney W. Grimes /* ARGSUSED */ 32126f9a767SRodney W. Grimes int 322cb226aaaSPoul-Henning Kamp setsid(p, uap) 323df8bae1dSRodney W. Grimes register struct proc *p; 32482970b81SBruce Evans struct setsid_args *uap; 325df8bae1dSRodney W. Grimes { 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 328df8bae1dSRodney W. Grimes return (EPERM); 329df8bae1dSRodney W. Grimes } else { 330df8bae1dSRodney W. Grimes (void)enterpgrp(p, p->p_pid, 1); 331cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pid; 332df8bae1dSRodney W. Grimes return (0); 333df8bae1dSRodney W. Grimes } 334df8bae1dSRodney W. Grimes } 335df8bae1dSRodney W. Grimes 336df8bae1dSRodney W. Grimes /* 337df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 338df8bae1dSRodney W. Grimes * 339df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 340df8bae1dSRodney W. Grimes * 341df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 342df8bae1dSRodney W. Grimes * if a child 343df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 344df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 345df8bae1dSRodney W. Grimes * if pgid != pid 346df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 347df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 348df8bae1dSRodney W. Grimes */ 349d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 350df8bae1dSRodney W. Grimes struct setpgid_args { 351df8bae1dSRodney W. Grimes int pid; /* target process id */ 352df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 353df8bae1dSRodney W. Grimes }; 354d2d3e875SBruce Evans #endif 355df8bae1dSRodney W. Grimes /* ARGSUSED */ 35626f9a767SRodney W. Grimes int 357cb226aaaSPoul-Henning Kamp setpgid(curp, uap) 358df8bae1dSRodney W. Grimes struct proc *curp; 359df8bae1dSRodney W. Grimes register struct setpgid_args *uap; 360df8bae1dSRodney W. Grimes { 361df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 362df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 363eb9e5c1dSRobert Watson int error; 364df8bae1dSRodney W. Grimes 36578f64bccSBruce Evans if (uap->pgid < 0) 36678f64bccSBruce Evans return (EINVAL); 367df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 36833a9ed9dSJohn Baldwin if ((targp = pfind(uap->pid)) == NULL || !inferior(targp)) { 36933a9ed9dSJohn Baldwin if (targp) 37033a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 371df8bae1dSRodney W. Grimes return (ESRCH); 37233a9ed9dSJohn Baldwin } 37333a9ed9dSJohn Baldwin if ((error = p_can(curproc, targp, P_CAN_SEE, NULL))) { 37433a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 375eb9e5c1dSRobert Watson return (error); 37633a9ed9dSJohn Baldwin } 37733a9ed9dSJohn Baldwin if (targp->p_pgrp == NULL || 37833a9ed9dSJohn Baldwin targp->p_session != curp->p_session) { 37933a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 380df8bae1dSRodney W. Grimes return (EPERM); 38133a9ed9dSJohn Baldwin } 38233a9ed9dSJohn Baldwin if (targp->p_flag & P_EXEC) { 38333a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 384df8bae1dSRodney W. Grimes return (EACCES); 38533a9ed9dSJohn Baldwin } 38633a9ed9dSJohn Baldwin } else { 387df8bae1dSRodney W. Grimes targp = curp; 38833a9ed9dSJohn Baldwin PROC_LOCK(curp); /* XXX: not needed */ 38933a9ed9dSJohn Baldwin } 39033a9ed9dSJohn Baldwin if (SESS_LEADER(targp)) { 39133a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 392df8bae1dSRodney W. Grimes return (EPERM); 39333a9ed9dSJohn Baldwin } 394df8bae1dSRodney W. Grimes if (uap->pgid == 0) 395df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 396df8bae1dSRodney W. Grimes else if (uap->pgid != targp->p_pid) 397df8bae1dSRodney W. Grimes if ((pgrp = pgfind(uap->pgid)) == 0 || 39833a9ed9dSJohn Baldwin pgrp->pg_session != curp->p_session) { 39933a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 400df8bae1dSRodney W. Grimes return (EPERM); 40133a9ed9dSJohn Baldwin } 40233a9ed9dSJohn Baldwin /* XXX: We should probably hold the lock across enterpgrp. */ 40333a9ed9dSJohn Baldwin PROC_UNLOCK(targp); 404df8bae1dSRodney W. Grimes return (enterpgrp(targp, uap->pgid, 0)); 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes 407a08f4bf6SPeter Wemm /* 408a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 4092fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 410a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 411a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 412a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 413a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 414a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 415a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 416a08f4bf6SPeter Wemm */ 417a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 418a08f4bf6SPeter Wemm 419d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 420df8bae1dSRodney W. Grimes struct setuid_args { 421df8bae1dSRodney W. Grimes uid_t uid; 422df8bae1dSRodney W. Grimes }; 423d2d3e875SBruce Evans #endif 424df8bae1dSRodney W. Grimes /* ARGSUSED */ 42526f9a767SRodney W. Grimes int 426cb226aaaSPoul-Henning Kamp setuid(p, uap) 427df8bae1dSRodney W. Grimes struct proc *p; 428df8bae1dSRodney W. Grimes struct setuid_args *uap; 429df8bae1dSRodney W. Grimes { 430df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 431df8bae1dSRodney W. Grimes register uid_t uid; 432df8bae1dSRodney W. Grimes int error; 433df8bae1dSRodney W. Grimes 434a08f4bf6SPeter Wemm /* 435a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 436a08f4bf6SPeter Wemm * 437a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 438a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 4392fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 440a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 441a08f4bf6SPeter Wemm * three id's (assuming you have privs). 442a08f4bf6SPeter Wemm * 443a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 444a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 445a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 446a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 447a08f4bf6SPeter Wemm * 2: We determine if the real and/or saved uid's are going to 448a08f4bf6SPeter Wemm * change. Determined by compile options. 449a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 450a08f4bf6SPeter Wemm */ 451df8bae1dSRodney W. Grimes uid = uap->uid; 452a08f4bf6SPeter Wemm if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 4533f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 454a08f4bf6SPeter Wemm uid != pc->p_svuid && /* allow setuid(saved gid) */ 455a08f4bf6SPeter Wemm #endif 456a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 457a08f4bf6SPeter Wemm uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 4583f246666SAndrey A. Chernov #endif 45975c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 460df8bae1dSRodney W. Grimes return (error); 461a08f4bf6SPeter Wemm 462a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 463df8bae1dSRodney W. Grimes /* 464a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 465a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 466df8bae1dSRodney W. Grimes */ 4673f246666SAndrey A. Chernov if ( 468a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 469a08f4bf6SPeter Wemm uid == pc->pc_ucred->cr_uid || 4703f246666SAndrey A. Chernov #endif 47175c13541SPoul-Henning Kamp suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 472a08f4bf6SPeter Wemm #endif 473a08f4bf6SPeter Wemm { 474a08f4bf6SPeter Wemm /* 475f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 476a08f4bf6SPeter Wemm */ 477a08f4bf6SPeter Wemm if (uid != pc->p_ruid) { 478f535380cSDon Lewis change_ruid(p, uid); 479f535380cSDon Lewis setsugid(p); 480d3cdb93dSAndrey A. Chernov } 481a08f4bf6SPeter Wemm /* 482a08f4bf6SPeter Wemm * Set saved uid 483a08f4bf6SPeter Wemm * 484a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 485a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 486a08f4bf6SPeter Wemm * is important that we should do this. 487a08f4bf6SPeter Wemm */ 488a08f4bf6SPeter Wemm if (pc->p_svuid != uid) { 489a08f4bf6SPeter Wemm pc->p_svuid = uid; 490d5f81602SSean Eric Fagan setsugid(p); 491a08f4bf6SPeter Wemm } 492a08f4bf6SPeter Wemm } 493a08f4bf6SPeter Wemm 494a08f4bf6SPeter Wemm /* 495a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 496a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 497a08f4bf6SPeter Wemm */ 498a08f4bf6SPeter Wemm if (pc->pc_ucred->cr_uid != uid) { 499f535380cSDon Lewis change_euid(p, uid); 500d5f81602SSean Eric Fagan setsugid(p); 501a08f4bf6SPeter Wemm } 502df8bae1dSRodney W. Grimes return (0); 503df8bae1dSRodney W. Grimes } 504df8bae1dSRodney W. Grimes 505d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 506df8bae1dSRodney W. Grimes struct seteuid_args { 507df8bae1dSRodney W. Grimes uid_t euid; 508df8bae1dSRodney W. Grimes }; 509d2d3e875SBruce Evans #endif 510df8bae1dSRodney W. Grimes /* ARGSUSED */ 51126f9a767SRodney W. Grimes int 512cb226aaaSPoul-Henning Kamp seteuid(p, uap) 513df8bae1dSRodney W. Grimes struct proc *p; 514df8bae1dSRodney W. Grimes struct seteuid_args *uap; 515df8bae1dSRodney W. Grimes { 516df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 517df8bae1dSRodney W. Grimes register uid_t euid; 518df8bae1dSRodney W. Grimes int error; 519df8bae1dSRodney W. Grimes 520df8bae1dSRodney W. Grimes euid = uap->euid; 521229a15f0SPeter Wemm if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 522229a15f0SPeter Wemm euid != pc->p_svuid && /* allow seteuid(saved uid) */ 52375c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 524df8bae1dSRodney W. Grimes return (error); 525df8bae1dSRodney W. Grimes /* 526df8bae1dSRodney W. Grimes * Everything's okay, do it. Copy credentials so other references do 527df8bae1dSRodney W. Grimes * not see our changes. 528df8bae1dSRodney W. Grimes */ 529229a15f0SPeter Wemm if (pc->pc_ucred->cr_uid != euid) { 530f535380cSDon Lewis change_euid(p, euid); 531d5f81602SSean Eric Fagan setsugid(p); 532229a15f0SPeter Wemm } 533df8bae1dSRodney W. Grimes return (0); 534df8bae1dSRodney W. Grimes } 535df8bae1dSRodney W. Grimes 536d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 537df8bae1dSRodney W. Grimes struct setgid_args { 538df8bae1dSRodney W. Grimes gid_t gid; 539df8bae1dSRodney W. Grimes }; 540d2d3e875SBruce Evans #endif 541df8bae1dSRodney W. Grimes /* ARGSUSED */ 54226f9a767SRodney W. Grimes int 543cb226aaaSPoul-Henning Kamp setgid(p, uap) 544df8bae1dSRodney W. Grimes struct proc *p; 545df8bae1dSRodney W. Grimes struct setgid_args *uap; 546df8bae1dSRodney W. Grimes { 547df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 548df8bae1dSRodney W. Grimes register gid_t gid; 549df8bae1dSRodney W. Grimes int error; 550df8bae1dSRodney W. Grimes 551a08f4bf6SPeter Wemm /* 552a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 553a08f4bf6SPeter Wemm * 554a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 555a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5562fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 557a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 558a08f4bf6SPeter Wemm * three id's (assuming you have privs). 559a08f4bf6SPeter Wemm * 560a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 561a08f4bf6SPeter Wemm */ 562df8bae1dSRodney W. Grimes gid = uap->gid; 563a08f4bf6SPeter Wemm if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 5643f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 565a08f4bf6SPeter Wemm gid != pc->p_svgid && /* allow setgid(saved gid) */ 566a08f4bf6SPeter Wemm #endif 567a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 568a08f4bf6SPeter Wemm gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 5693f246666SAndrey A. Chernov #endif 57075c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 571df8bae1dSRodney W. Grimes return (error); 572a08f4bf6SPeter Wemm 573a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 574a08f4bf6SPeter Wemm /* 575a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 576a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 577a08f4bf6SPeter Wemm */ 578a08f4bf6SPeter Wemm if ( 579a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 580a08f4bf6SPeter Wemm gid == pc->pc_ucred->cr_groups[0] || 581a08f4bf6SPeter Wemm #endif 58275c13541SPoul-Henning Kamp suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 583a08f4bf6SPeter Wemm #endif 584a08f4bf6SPeter Wemm { 585a08f4bf6SPeter Wemm /* 586a08f4bf6SPeter Wemm * Set real gid 587a08f4bf6SPeter Wemm */ 588a08f4bf6SPeter Wemm if (pc->p_rgid != gid) { 589a08f4bf6SPeter Wemm pc->p_rgid = gid; 590d5f81602SSean Eric Fagan setsugid(p); 591a08f4bf6SPeter Wemm } 592a08f4bf6SPeter Wemm /* 593a08f4bf6SPeter Wemm * Set saved gid 594a08f4bf6SPeter Wemm * 595a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 596a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 597a08f4bf6SPeter Wemm * is important that we should do this. 598a08f4bf6SPeter Wemm */ 599a08f4bf6SPeter Wemm if (pc->p_svgid != gid) { 600a08f4bf6SPeter Wemm pc->p_svgid = gid; 601d5f81602SSean Eric Fagan setsugid(p); 602a08f4bf6SPeter Wemm } 603a08f4bf6SPeter Wemm } 604a08f4bf6SPeter Wemm /* 605a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 606a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 607a08f4bf6SPeter Wemm */ 608a08f4bf6SPeter Wemm if (pc->pc_ucred->cr_groups[0] != gid) { 609df8bae1dSRodney W. Grimes pc->pc_ucred = crcopy(pc->pc_ucred); 610df8bae1dSRodney W. Grimes pc->pc_ucred->cr_groups[0] = gid; 611d5f81602SSean Eric Fagan setsugid(p); 612a08f4bf6SPeter Wemm } 613df8bae1dSRodney W. Grimes return (0); 614df8bae1dSRodney W. Grimes } 615df8bae1dSRodney W. Grimes 616d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 617df8bae1dSRodney W. Grimes struct setegid_args { 618df8bae1dSRodney W. Grimes gid_t egid; 619df8bae1dSRodney W. Grimes }; 620d2d3e875SBruce Evans #endif 621df8bae1dSRodney W. Grimes /* ARGSUSED */ 62226f9a767SRodney W. Grimes int 623cb226aaaSPoul-Henning Kamp setegid(p, uap) 624df8bae1dSRodney W. Grimes struct proc *p; 625df8bae1dSRodney W. Grimes struct setegid_args *uap; 626df8bae1dSRodney W. Grimes { 627df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 628df8bae1dSRodney W. Grimes register gid_t egid; 629df8bae1dSRodney W. Grimes int error; 630df8bae1dSRodney W. Grimes 631df8bae1dSRodney W. Grimes egid = uap->egid; 632229a15f0SPeter Wemm if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 633229a15f0SPeter Wemm egid != pc->p_svgid && /* allow setegid(saved gid) */ 63475c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 635df8bae1dSRodney W. Grimes return (error); 636229a15f0SPeter Wemm if (pc->pc_ucred->cr_groups[0] != egid) { 637df8bae1dSRodney W. Grimes pc->pc_ucred = crcopy(pc->pc_ucred); 638df8bae1dSRodney W. Grimes pc->pc_ucred->cr_groups[0] = egid; 639d5f81602SSean Eric Fagan setsugid(p); 640229a15f0SPeter Wemm } 641df8bae1dSRodney W. Grimes return (0); 642df8bae1dSRodney W. Grimes } 643df8bae1dSRodney W. Grimes 644d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 645df8bae1dSRodney W. Grimes struct setgroups_args { 646df8bae1dSRodney W. Grimes u_int gidsetsize; 647df8bae1dSRodney W. Grimes gid_t *gidset; 648df8bae1dSRodney W. Grimes }; 649d2d3e875SBruce Evans #endif 650df8bae1dSRodney W. Grimes /* ARGSUSED */ 65126f9a767SRodney W. Grimes int 652cb226aaaSPoul-Henning Kamp setgroups(p, uap) 653df8bae1dSRodney W. Grimes struct proc *p; 654df8bae1dSRodney W. Grimes struct setgroups_args *uap; 655df8bae1dSRodney W. Grimes { 656df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 657df8bae1dSRodney W. Grimes register u_int ngrp; 658df8bae1dSRodney W. Grimes int error; 659df8bae1dSRodney W. Grimes 66075c13541SPoul-Henning Kamp if ((error = suser_xxx(0, p, PRISON_ROOT))) 661df8bae1dSRodney W. Grimes return (error); 6623956a170SDavid Greenman ngrp = uap->gidsetsize; 6638a5d815aSPeter Wemm if (ngrp > NGROUPS) 664df8bae1dSRodney W. Grimes return (EINVAL); 6658a5d815aSPeter Wemm /* 6668a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 6678a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 6688a5d815aSPeter Wemm */ 669df8bae1dSRodney W. Grimes pc->pc_ucred = crcopy(pc->pc_ucred); 6708a5d815aSPeter Wemm if (ngrp < 1) { 6718a5d815aSPeter Wemm /* 6728a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 6738a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 6748a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 6758a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 6768a5d815aSPeter Wemm */ 6778a5d815aSPeter Wemm pc->pc_ucred->cr_ngroups = 1; 6788a5d815aSPeter Wemm } else { 679bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 680bb56ec4aSPoul-Henning Kamp (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 681df8bae1dSRodney W. Grimes return (error); 682df8bae1dSRodney W. Grimes pc->pc_ucred->cr_ngroups = ngrp; 6838a5d815aSPeter Wemm } 684d5f81602SSean Eric Fagan setsugid(p); 685df8bae1dSRodney W. Grimes return (0); 686df8bae1dSRodney W. Grimes } 687df8bae1dSRodney W. Grimes 688d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 689df8bae1dSRodney W. Grimes struct setreuid_args { 69000999cd6SAndrey A. Chernov uid_t ruid; 69100999cd6SAndrey A. Chernov uid_t euid; 692df8bae1dSRodney W. Grimes }; 693d2d3e875SBruce Evans #endif 694df8bae1dSRodney W. Grimes /* ARGSUSED */ 69526f9a767SRodney W. Grimes int 696cb226aaaSPoul-Henning Kamp setreuid(p, uap) 697df8bae1dSRodney W. Grimes register struct proc *p; 698df8bae1dSRodney W. Grimes struct setreuid_args *uap; 699df8bae1dSRodney W. Grimes { 700df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 70100999cd6SAndrey A. Chernov register uid_t ruid, euid; 702611d721eSAndrey A. Chernov int error; 703df8bae1dSRodney W. Grimes 70400999cd6SAndrey A. Chernov ruid = uap->ruid; 70500999cd6SAndrey A. Chernov euid = uap->euid; 7068aef1712SMatthew Dillon if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || 7078aef1712SMatthew Dillon (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 7088aef1712SMatthew Dillon euid != pc->p_ruid && euid != pc->p_svuid)) && 70975c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 710611d721eSAndrey A. Chernov return (error); 71100999cd6SAndrey A. Chernov 712a89a5370SPeter Wemm if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 713f535380cSDon Lewis change_euid(p, euid); 714d5f81602SSean Eric Fagan setsugid(p); 715a89a5370SPeter Wemm } 716a89a5370SPeter Wemm if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 717f535380cSDon Lewis change_ruid(p, ruid); 718d5f81602SSean Eric Fagan setsugid(p); 71900999cd6SAndrey A. Chernov } 720b79c6a86SPeter Wemm if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 721b79c6a86SPeter Wemm pc->p_svuid != pc->pc_ucred->cr_uid) { 7224bc8f31fSAndrey A. Chernov pc->p_svuid = pc->pc_ucred->cr_uid; 723d5f81602SSean Eric Fagan setsugid(p); 724a89a5370SPeter Wemm } 725611d721eSAndrey A. Chernov return (0); 726df8bae1dSRodney W. Grimes } 727df8bae1dSRodney W. Grimes 728d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 729df8bae1dSRodney W. Grimes struct setregid_args { 73000999cd6SAndrey A. Chernov gid_t rgid; 73100999cd6SAndrey A. Chernov gid_t egid; 732df8bae1dSRodney W. Grimes }; 733d2d3e875SBruce Evans #endif 734df8bae1dSRodney W. Grimes /* ARGSUSED */ 73526f9a767SRodney W. Grimes int 736cb226aaaSPoul-Henning Kamp setregid(p, uap) 737df8bae1dSRodney W. Grimes register struct proc *p; 738df8bae1dSRodney W. Grimes struct setregid_args *uap; 739df8bae1dSRodney W. Grimes { 740df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 74100999cd6SAndrey A. Chernov register gid_t rgid, egid; 742611d721eSAndrey A. Chernov int error; 743df8bae1dSRodney W. Grimes 74400999cd6SAndrey A. Chernov rgid = uap->rgid; 74500999cd6SAndrey A. Chernov egid = uap->egid; 7468aef1712SMatthew Dillon if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || 7478aef1712SMatthew Dillon (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 7488aef1712SMatthew Dillon egid != pc->p_rgid && egid != pc->p_svgid)) && 74975c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 750611d721eSAndrey A. Chernov return (error); 75100999cd6SAndrey A. Chernov 752a89a5370SPeter Wemm if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 75300999cd6SAndrey A. Chernov pc->pc_ucred = crcopy(pc->pc_ucred); 75400999cd6SAndrey A. Chernov pc->pc_ucred->cr_groups[0] = egid; 755d5f81602SSean Eric Fagan setsugid(p); 756a89a5370SPeter Wemm } 757a89a5370SPeter Wemm if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 75800999cd6SAndrey A. Chernov pc->p_rgid = rgid; 759d5f81602SSean Eric Fagan setsugid(p); 760a89a5370SPeter Wemm } 761b79c6a86SPeter Wemm if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 762b79c6a86SPeter Wemm pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7634bc8f31fSAndrey A. Chernov pc->p_svgid = pc->pc_ucred->cr_groups[0]; 764d5f81602SSean Eric Fagan setsugid(p); 765a89a5370SPeter Wemm } 766611d721eSAndrey A. Chernov return (0); 767df8bae1dSRodney W. Grimes } 768df8bae1dSRodney W. Grimes 7698ccd6334SPeter Wemm /* 7708ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 7718ccd6334SPeter Wemm * saved uid is explicit. 7728ccd6334SPeter Wemm */ 7738ccd6334SPeter Wemm 7748ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 7758ccd6334SPeter Wemm struct setresuid_args { 7768ccd6334SPeter Wemm uid_t ruid; 7778ccd6334SPeter Wemm uid_t euid; 7788ccd6334SPeter Wemm uid_t suid; 7798ccd6334SPeter Wemm }; 7808ccd6334SPeter Wemm #endif 7818ccd6334SPeter Wemm /* ARGSUSED */ 7828ccd6334SPeter Wemm int 7838ccd6334SPeter Wemm setresuid(p, uap) 7848ccd6334SPeter Wemm register struct proc *p; 7858ccd6334SPeter Wemm struct setresuid_args *uap; 7868ccd6334SPeter Wemm { 7878ccd6334SPeter Wemm register struct pcred *pc = p->p_cred; 7888ccd6334SPeter Wemm register uid_t ruid, euid, suid; 7898ccd6334SPeter Wemm int error; 7908ccd6334SPeter Wemm 7918ccd6334SPeter Wemm ruid = uap->ruid; 7928ccd6334SPeter Wemm euid = uap->euid; 7938ccd6334SPeter Wemm suid = uap->suid; 7948ccd6334SPeter Wemm if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid && 7958ccd6334SPeter Wemm ruid != pc->pc_ucred->cr_uid) || 7968ccd6334SPeter Wemm (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid && 7978ccd6334SPeter Wemm euid != pc->pc_ucred->cr_uid) || 7988ccd6334SPeter Wemm (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid && 7998ccd6334SPeter Wemm suid != pc->pc_ucred->cr_uid)) && 8008ccd6334SPeter Wemm (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 8018ccd6334SPeter Wemm return (error); 8028ccd6334SPeter Wemm if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 803f535380cSDon Lewis change_euid(p, euid); 8048ccd6334SPeter Wemm setsugid(p); 8058ccd6334SPeter Wemm } 8068ccd6334SPeter Wemm if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 807f535380cSDon Lewis change_ruid(p, ruid); 8088ccd6334SPeter Wemm setsugid(p); 8098ccd6334SPeter Wemm } 8108ccd6334SPeter Wemm if (suid != (uid_t)-1 && pc->p_svuid != suid) { 8118ccd6334SPeter Wemm pc->p_svuid = suid; 8128ccd6334SPeter Wemm setsugid(p); 8138ccd6334SPeter Wemm } 8148ccd6334SPeter Wemm return (0); 8158ccd6334SPeter Wemm } 8168ccd6334SPeter Wemm 8178ccd6334SPeter Wemm /* 8188ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 8198ccd6334SPeter Wemm * saved gid is explicit. 8208ccd6334SPeter Wemm */ 8218ccd6334SPeter Wemm 8228ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 8238ccd6334SPeter Wemm struct setresgid_args { 8248ccd6334SPeter Wemm gid_t rgid; 8258ccd6334SPeter Wemm gid_t egid; 8268ccd6334SPeter Wemm gid_t sgid; 8278ccd6334SPeter Wemm }; 8288ccd6334SPeter Wemm #endif 8298ccd6334SPeter Wemm /* ARGSUSED */ 8308ccd6334SPeter Wemm int 8318ccd6334SPeter Wemm setresgid(p, uap) 8328ccd6334SPeter Wemm register struct proc *p; 8338ccd6334SPeter Wemm struct setresgid_args *uap; 8348ccd6334SPeter Wemm { 8358ccd6334SPeter Wemm register struct pcred *pc = p->p_cred; 8368ccd6334SPeter Wemm register gid_t rgid, egid, sgid; 8378ccd6334SPeter Wemm int error; 8388ccd6334SPeter Wemm 8398ccd6334SPeter Wemm rgid = uap->rgid; 8408ccd6334SPeter Wemm egid = uap->egid; 8418ccd6334SPeter Wemm sgid = uap->sgid; 8428ccd6334SPeter Wemm if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid && 8438ccd6334SPeter Wemm rgid != pc->pc_ucred->cr_groups[0]) || 8448ccd6334SPeter Wemm (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid && 8458ccd6334SPeter Wemm egid != pc->pc_ucred->cr_groups[0]) || 8468ccd6334SPeter Wemm (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && 8478ccd6334SPeter Wemm sgid != pc->pc_ucred->cr_groups[0])) && 8488ccd6334SPeter Wemm (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 8498ccd6334SPeter Wemm return (error); 8508ccd6334SPeter Wemm 8518ccd6334SPeter Wemm if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 8528ccd6334SPeter Wemm pc->pc_ucred = crcopy(pc->pc_ucred); 8538ccd6334SPeter Wemm pc->pc_ucred->cr_groups[0] = egid; 8548ccd6334SPeter Wemm setsugid(p); 8558ccd6334SPeter Wemm } 8568ccd6334SPeter Wemm if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 8578ccd6334SPeter Wemm pc->p_rgid = rgid; 8588ccd6334SPeter Wemm setsugid(p); 8598ccd6334SPeter Wemm } 8608ccd6334SPeter Wemm if (sgid != (gid_t)-1 && pc->p_svgid != sgid) { 8618ccd6334SPeter Wemm pc->p_svgid = sgid; 8628ccd6334SPeter Wemm setsugid(p); 8638ccd6334SPeter Wemm } 8648ccd6334SPeter Wemm return (0); 8658ccd6334SPeter Wemm } 8668ccd6334SPeter Wemm 8678ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 8688ccd6334SPeter Wemm struct getresuid_args { 8698ccd6334SPeter Wemm uid_t *ruid; 8708ccd6334SPeter Wemm uid_t *euid; 8718ccd6334SPeter Wemm uid_t *suid; 8728ccd6334SPeter Wemm }; 8738ccd6334SPeter Wemm #endif 8748ccd6334SPeter Wemm /* ARGSUSED */ 8758ccd6334SPeter Wemm int 8768ccd6334SPeter Wemm getresuid(p, uap) 8778ccd6334SPeter Wemm register struct proc *p; 8788ccd6334SPeter Wemm struct getresuid_args *uap; 8798ccd6334SPeter Wemm { 8808ccd6334SPeter Wemm struct pcred *pc = p->p_cred; 8818ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 8828ccd6334SPeter Wemm 8838ccd6334SPeter Wemm if (uap->ruid) 8848ccd6334SPeter Wemm error1 = copyout((caddr_t)&pc->p_ruid, 8858ccd6334SPeter Wemm (caddr_t)uap->ruid, sizeof(pc->p_ruid)); 8868ccd6334SPeter Wemm if (uap->euid) 8878ccd6334SPeter Wemm error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid, 8888ccd6334SPeter Wemm (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid)); 8898ccd6334SPeter Wemm if (uap->suid) 8908ccd6334SPeter Wemm error3 = copyout((caddr_t)&pc->p_svuid, 8918ccd6334SPeter Wemm (caddr_t)uap->suid, sizeof(pc->p_svuid)); 8928ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 8938ccd6334SPeter Wemm } 8948ccd6334SPeter Wemm 8958ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 8968ccd6334SPeter Wemm struct getresgid_args { 8978ccd6334SPeter Wemm gid_t *rgid; 8988ccd6334SPeter Wemm gid_t *egid; 8998ccd6334SPeter Wemm gid_t *sgid; 9008ccd6334SPeter Wemm }; 9018ccd6334SPeter Wemm #endif 9028ccd6334SPeter Wemm /* ARGSUSED */ 9038ccd6334SPeter Wemm int 9048ccd6334SPeter Wemm getresgid(p, uap) 9058ccd6334SPeter Wemm register struct proc *p; 9068ccd6334SPeter Wemm struct getresgid_args *uap; 9078ccd6334SPeter Wemm { 9088ccd6334SPeter Wemm struct pcred *pc = p->p_cred; 9098ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 9108ccd6334SPeter Wemm 9118ccd6334SPeter Wemm if (uap->rgid) 9128ccd6334SPeter Wemm error1 = copyout((caddr_t)&pc->p_rgid, 9138ccd6334SPeter Wemm (caddr_t)uap->rgid, sizeof(pc->p_rgid)); 9148ccd6334SPeter Wemm if (uap->egid) 9158ccd6334SPeter Wemm error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0], 9168ccd6334SPeter Wemm (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0])); 9178ccd6334SPeter Wemm if (uap->sgid) 9188ccd6334SPeter Wemm error3 = copyout((caddr_t)&pc->p_svgid, 9198ccd6334SPeter Wemm (caddr_t)uap->sgid, sizeof(pc->p_svgid)); 9208ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 9218ccd6334SPeter Wemm } 9228ccd6334SPeter Wemm 9238ccd6334SPeter Wemm 924b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 925b67cbc65SPeter Wemm struct issetugid_args { 926b67cbc65SPeter Wemm int dummy; 927b67cbc65SPeter Wemm }; 928b67cbc65SPeter Wemm #endif 929b67cbc65SPeter Wemm /* ARGSUSED */ 930b67cbc65SPeter Wemm int 931cb226aaaSPoul-Henning Kamp issetugid(p, uap) 932b67cbc65SPeter Wemm register struct proc *p; 933b67cbc65SPeter Wemm struct issetugid_args *uap; 934b67cbc65SPeter Wemm { 935b67cbc65SPeter Wemm /* 936b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 937b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 938b67cbc65SPeter Wemm * "tainting" as well. 939b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 940b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 941b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 942b67cbc65SPeter Wemm */ 9430e59fec6SPeter Wemm p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 944b67cbc65SPeter Wemm return (0); 945b67cbc65SPeter Wemm } 946b67cbc65SPeter Wemm 947130d0157SRobert Watson int 948130d0157SRobert Watson __setugid(p, uap) 949130d0157SRobert Watson struct proc *p; 950130d0157SRobert Watson struct __setugid_args *uap; 951130d0157SRobert Watson { 952130d0157SRobert Watson 953130d0157SRobert Watson #ifdef REGRESSION 954130d0157SRobert Watson switch (uap->flag) { 955130d0157SRobert Watson case 0: 956130d0157SRobert Watson p->p_flag &= ~P_SUGID; 957130d0157SRobert Watson return (0); 958130d0157SRobert Watson case 1: 959130d0157SRobert Watson p->p_flag |= P_SUGID; 960130d0157SRobert Watson return (0); 961130d0157SRobert Watson default: 962130d0157SRobert Watson return (EINVAL); 963130d0157SRobert Watson } 964130d0157SRobert Watson #else /* !REGRESSION */ 965130d0157SRobert Watson return (ENOSYS); 966130d0157SRobert Watson #endif /* !REGRESSION */ 967130d0157SRobert Watson } 968130d0157SRobert Watson 969df8bae1dSRodney W. Grimes /* 970df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 971df8bae1dSRodney W. Grimes */ 97226f9a767SRodney W. Grimes int 973df8bae1dSRodney W. Grimes groupmember(gid, cred) 974df8bae1dSRodney W. Grimes gid_t gid; 975df8bae1dSRodney W. Grimes register struct ucred *cred; 976df8bae1dSRodney W. Grimes { 977df8bae1dSRodney W. Grimes register gid_t *gp; 978df8bae1dSRodney W. Grimes gid_t *egp; 979df8bae1dSRodney W. Grimes 980df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 981df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 982df8bae1dSRodney W. Grimes if (*gp == gid) 983df8bae1dSRodney W. Grimes return (1); 984df8bae1dSRodney W. Grimes return (0); 985df8bae1dSRodney W. Grimes } 986df8bae1dSRodney W. Grimes 987579f4eb4SRobert Watson static int suser_permitted = 1; 988579f4eb4SRobert Watson 989579f4eb4SRobert Watson SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 990579f4eb4SRobert Watson "processes with uid 0 have privilege"); 991579f4eb4SRobert Watson 992df8bae1dSRodney W. Grimes /* 993df8bae1dSRodney W. Grimes * Test whether the specified credentials imply "super-user" 994df8bae1dSRodney W. Grimes * privilege; if so, and we have accounting info, set the flag 995df8bae1dSRodney W. Grimes * indicating use of super-powers. 996df8bae1dSRodney W. Grimes * Returns 0 or error. 997df8bae1dSRodney W. Grimes */ 99826f9a767SRodney W. Grimes int 999f711d546SPoul-Henning Kamp suser(p) 100091421ba2SRobert Watson struct proc *p; 1001f711d546SPoul-Henning Kamp { 100275c13541SPoul-Henning Kamp return suser_xxx(0, p, 0); 1003f711d546SPoul-Henning Kamp } 1004f711d546SPoul-Henning Kamp 1005f711d546SPoul-Henning Kamp int 100675c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 100791421ba2SRobert Watson struct ucred *cred; 100891421ba2SRobert Watson struct proc *proc; 100975c13541SPoul-Henning Kamp int flag; 1010df8bae1dSRodney W. Grimes { 101103095547SRobert Watson if (!suser_permitted) 101203095547SRobert Watson return (EPERM); 101375c13541SPoul-Henning Kamp if (!cred && !proc) { 101475c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 1015df8bae1dSRodney W. Grimes return (EPERM); 1016df8bae1dSRodney W. Grimes } 101775c13541SPoul-Henning Kamp if (!cred) 101875c13541SPoul-Henning Kamp cred = proc->p_ucred; 101975c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 102075c13541SPoul-Henning Kamp return (EPERM); 102191421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 102275c13541SPoul-Henning Kamp return (EPERM); 102375c13541SPoul-Henning Kamp return (0); 102475c13541SPoul-Henning Kamp } 1025df8bae1dSRodney W. Grimes 1026ed639720SRobert Watson /* 1027ed639720SRobert Watson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2 1028ed639720SRobert Watson * Arguments: imutable credentials u1, u2 1029ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 1030ed639720SRobert Watson * Locks: none 1031ed639720SRobert Watson * References: u1 and u2 must be valid for the lifetime of the call 1032ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1033ed639720SRobert Watson */ 1034ed639720SRobert Watson int 1035ed639720SRobert Watson u_cansee(struct ucred *u1, struct ucred *u2) 1036a9e0361bSPoul-Henning Kamp { 103791421ba2SRobert Watson int error; 1038a9e0361bSPoul-Henning Kamp 1039ed639720SRobert Watson if ((error = prison_check(u1, u2))) 104091421ba2SRobert Watson return (error); 1041ed639720SRobert Watson if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) { 1042f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1043387d2c03SRobert Watson return (ESRCH); 1044c52396e3SRobert Watson } 1045387d2c03SRobert Watson return (0); 1046387d2c03SRobert Watson } 1047387d2c03SRobert Watson 1048387d2c03SRobert Watson static int 1049ed639720SRobert Watson p_cansee(struct proc *p1, struct proc *p2, int *privused) 1050ed639720SRobert Watson { 1051ed639720SRobert Watson 1052ed639720SRobert Watson /* XXX: privused is going away, so don't do that here. */ 1053ed639720SRobert Watson if (privused != NULL) 1054ed639720SRobert Watson *privused = 0; 1055ed639720SRobert Watson /* Wrap u_cansee() for all functionality. */ 1056ed639720SRobert Watson return (u_cansee(p1->p_ucred, p2->p_ucred)); 1057ed639720SRobert Watson } 1058ed639720SRobert Watson 10594c5eb9c3SRobert Watson /* 10604c5eb9c3SRobert Watson * Can process p1 send the signal signum to process p2? 10614c5eb9c3SRobert Watson */ 10624c5eb9c3SRobert Watson int 10634c5eb9c3SRobert Watson p_cansignal(struct proc *p1, struct proc *p2, int signum) 1064387d2c03SRobert Watson { 106591421ba2SRobert Watson int error; 1066387d2c03SRobert Watson 1067a9e0361bSPoul-Henning Kamp if (p1 == p2) 1068a9e0361bSPoul-Henning Kamp return (0); 1069387d2c03SRobert Watson 10704c5eb9c3SRobert Watson /* 10714c5eb9c3SRobert Watson * Jail semantics limit the scope of signalling to p2 in the same 10724c5eb9c3SRobert Watson * jail as p1, if p1 is in jail. 10734c5eb9c3SRobert Watson */ 107491421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 107591421ba2SRobert Watson return (error); 1076387d2c03SRobert Watson 1077387d2c03SRobert Watson /* 10784c5eb9c3SRobert Watson * UNIX signalling semantics require that processes in the same 10794c5eb9c3SRobert Watson * session always be able to deliver SIGCONT to one another, 10804c5eb9c3SRobert Watson * overriding the remaining protections. 1081387d2c03SRobert Watson */ 10824c5eb9c3SRobert Watson if (signum == SIGCONT && p1->p_session == p2->p_session) 1083a9e0361bSPoul-Henning Kamp return (0); 1084387d2c03SRobert Watson 10854c5eb9c3SRobert Watson /* 10864c5eb9c3SRobert Watson * UNIX uid semantics depend on the status of the P_SUGID 10874c5eb9c3SRobert Watson * bit on the target process. If the bit is set, then more 10884c5eb9c3SRobert Watson * restricted signal sets are permitted. 10894c5eb9c3SRobert Watson */ 10904c5eb9c3SRobert Watson if (p2->p_flag & P_SUGID) { 10914c5eb9c3SRobert Watson switch (signum) { 10924c5eb9c3SRobert Watson case 0: 10934c5eb9c3SRobert Watson case SIGKILL: 10944c5eb9c3SRobert Watson case SIGINT: 10954c5eb9c3SRobert Watson case SIGTERM: 10964c5eb9c3SRobert Watson case SIGSTOP: 10974c5eb9c3SRobert Watson case SIGTTIN: 10984c5eb9c3SRobert Watson case SIGTTOU: 10994c5eb9c3SRobert Watson case SIGTSTP: 11004c5eb9c3SRobert Watson case SIGHUP: 11014c5eb9c3SRobert Watson case SIGUSR1: 11024c5eb9c3SRobert Watson case SIGUSR2: 11034c5eb9c3SRobert Watson break; 11044c5eb9c3SRobert Watson default: 11054c5eb9c3SRobert Watson /* Not permitted, try privilege. */ 11064c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 11074c5eb9c3SRobert Watson if (error) 11084c5eb9c3SRobert Watson return (error); 11094c5eb9c3SRobert Watson } 1110e9e7ff5bSRobert Watson } 1111e9e7ff5bSRobert Watson 11124c5eb9c3SRobert Watson /* 1113e9e7ff5bSRobert Watson * Generally, the object credential's ruid or svuid must match the 1114e9e7ff5bSRobert Watson * subject credential's ruid or euid. 11154c5eb9c3SRobert Watson */ 11164c5eb9c3SRobert Watson if (p1->p_cred->p_ruid != p2->p_cred->p_ruid && 11174c5eb9c3SRobert Watson p1->p_cred->p_ruid != p2->p_cred->p_svuid && 11184c5eb9c3SRobert Watson p1->p_ucred->cr_uid != p2->p_cred->p_ruid && 111944c3e09cSRobert Watson p1->p_ucred->cr_uid != p2->p_cred->p_svuid) { 11204c5eb9c3SRobert Watson /* Not permitted, try privilege. */ 11214c5eb9c3SRobert Watson error = suser_xxx(NULL, p1, PRISON_ROOT); 11224c5eb9c3SRobert Watson if (error) 11234c5eb9c3SRobert Watson return (error); 11244c5eb9c3SRobert Watson } 1125387d2c03SRobert Watson 1126387d2c03SRobert Watson return (0); 1127387d2c03SRobert Watson } 1128a9e0361bSPoul-Henning Kamp 1129387d2c03SRobert Watson static int 113091421ba2SRobert Watson p_cansched(struct proc *p1, struct proc *p2, int *privused) 1131387d2c03SRobert Watson { 113291421ba2SRobert Watson int error; 1133387d2c03SRobert Watson 1134387d2c03SRobert Watson if (privused != NULL) 1135387d2c03SRobert Watson *privused = 0; 1136387d2c03SRobert Watson 1137387d2c03SRobert Watson if (p1 == p2) 1138387d2c03SRobert Watson return (0); 1139387d2c03SRobert Watson 114091421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 114191421ba2SRobert Watson return (error); 1142387d2c03SRobert Watson 1143387d2c03SRobert Watson if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 1144387d2c03SRobert Watson return (0); 1145387d2c03SRobert Watson if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 1146387d2c03SRobert Watson return (0); 1147387d2c03SRobert Watson 1148387d2c03SRobert Watson if (!suser_xxx(0, p1, PRISON_ROOT)) { 1149387d2c03SRobert Watson if (privused != NULL) 1150387d2c03SRobert Watson *privused = 1; 1151387d2c03SRobert Watson return (0); 1152387d2c03SRobert Watson } 1153387d2c03SRobert Watson 1154387d2c03SRobert Watson #ifdef CAPABILITIES 1155387d2c03SRobert Watson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { 1156387d2c03SRobert Watson if (privused != NULL) 1157387d2c03SRobert Watson *privused = 1; 1158387d2c03SRobert Watson return (0); 1159387d2c03SRobert Watson } 1160387d2c03SRobert Watson #endif 1161387d2c03SRobert Watson 1162387d2c03SRobert Watson return (EPERM); 1163387d2c03SRobert Watson } 1164387d2c03SRobert Watson 1165387d2c03SRobert Watson static int 116691421ba2SRobert Watson p_candebug(struct proc *p1, struct proc *p2, int *privused) 1167387d2c03SRobert Watson { 1168387d2c03SRobert Watson int error; 1169387d2c03SRobert Watson 1170387d2c03SRobert Watson if (privused != NULL) 1171387d2c03SRobert Watson *privused = 0; 1172387d2c03SRobert Watson 1173387d2c03SRobert Watson if (p1 == p2) 1174387d2c03SRobert Watson return (0); 1175387d2c03SRobert Watson 117691421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 117791421ba2SRobert Watson return (error); 1178387d2c03SRobert Watson 1179387d2c03SRobert Watson /* not owned by you, has done setuid (unless you're root) */ 1180387d2c03SRobert Watson /* add a CAP_SYS_PTRACE here? */ 1181c087a04fSRobert Watson if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid || 1182c087a04fSRobert Watson p1->p_cred->p_ruid != p2->p_cred->p_ruid || 11837f73938eSRobert Watson p1->p_cred->p_svuid != p2->p_cred->p_ruid || 1184c087a04fSRobert Watson p2->p_flag & P_SUGID) { 1185387d2c03SRobert Watson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 1186387d2c03SRobert Watson return (error); 1187387d2c03SRobert Watson if (privused != NULL) 1188387d2c03SRobert Watson *privused = 1; 1189387d2c03SRobert Watson } 1190387d2c03SRobert Watson 1191387d2c03SRobert Watson /* can't trace init when securelevel > 0 */ 1192387d2c03SRobert Watson if (securelevel > 0 && p2->p_pid == 1) 1193387d2c03SRobert Watson return (EPERM); 1194387d2c03SRobert Watson 1195387d2c03SRobert Watson return (0); 1196387d2c03SRobert Watson } 1197387d2c03SRobert Watson 1198387d2c03SRobert Watson int 119991421ba2SRobert Watson p_can(struct proc *p1, struct proc *p2, int operation, 1200387d2c03SRobert Watson int *privused) 1201387d2c03SRobert Watson { 1202387d2c03SRobert Watson 1203387d2c03SRobert Watson switch(operation) { 1204387d2c03SRobert Watson case P_CAN_SEE: 1205387d2c03SRobert Watson return (p_cansee(p1, p2, privused)); 1206387d2c03SRobert Watson 1207387d2c03SRobert Watson case P_CAN_SCHED: 1208387d2c03SRobert Watson return (p_cansched(p1, p2, privused)); 1209387d2c03SRobert Watson 1210387d2c03SRobert Watson case P_CAN_DEBUG: 1211387d2c03SRobert Watson return (p_candebug(p1, p2, privused)); 1212387d2c03SRobert Watson 1213387d2c03SRobert Watson default: 1214387d2c03SRobert Watson panic("p_can: invalid operation"); 1215387d2c03SRobert Watson } 1216387d2c03SRobert Watson } 1217387d2c03SRobert Watson 1218387d2c03SRobert Watson 1219a9e0361bSPoul-Henning Kamp /* 1220df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1221df8bae1dSRodney W. Grimes */ 1222df8bae1dSRodney W. Grimes struct ucred * 1223df8bae1dSRodney W. Grimes crget() 1224df8bae1dSRodney W. Grimes { 1225df8bae1dSRodney W. Grimes register struct ucred *cr; 1226df8bae1dSRodney W. Grimes 12271e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 1228df8bae1dSRodney W. Grimes cr->cr_ref = 1; 12291e5d626aSAlfred Perlstein mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 1230df8bae1dSRodney W. Grimes return (cr); 1231df8bae1dSRodney W. Grimes } 1232df8bae1dSRodney W. Grimes 1233df8bae1dSRodney W. Grimes /* 1234661702abSRobert Watson * Claim another reference to a ucred structure 12355c3f70d7SAlfred Perlstein */ 12365c3f70d7SAlfred Perlstein void 12375c3f70d7SAlfred Perlstein crhold(cr) 12385c3f70d7SAlfred Perlstein struct ucred *cr; 12395c3f70d7SAlfred Perlstein { 12405c3f70d7SAlfred Perlstein 12419ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 12425c3f70d7SAlfred Perlstein cr->cr_ref++; 12439ed346baSBosko Milekic mtx_unlock(&(cr)->cr_mtx); 12445c3f70d7SAlfred Perlstein } 12455c3f70d7SAlfred Perlstein 12465c3f70d7SAlfred Perlstein 12475c3f70d7SAlfred Perlstein /* 1248df8bae1dSRodney W. Grimes * Free a cred structure. 1249df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1250df8bae1dSRodney W. Grimes */ 125126f9a767SRodney W. Grimes void 1252df8bae1dSRodney W. Grimes crfree(cr) 1253df8bae1dSRodney W. Grimes struct ucred *cr; 1254df8bae1dSRodney W. Grimes { 12551e5d626aSAlfred Perlstein 12569ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1257e04670b7SAlfred Perlstein KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); 1258f535380cSDon Lewis if (--cr->cr_ref == 0) { 12591e5d626aSAlfred Perlstein mtx_destroy(&cr->cr_mtx); 1260f535380cSDon Lewis /* 1261f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1262f535380cSDon Lewis * allocate a temporary credential, but don't 1263f535380cSDon Lewis * allocate a uidinfo structure. 1264f535380cSDon Lewis */ 1265f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1266f535380cSDon Lewis uifree(cr->cr_uidinfo); 126791421ba2SRobert Watson /* 126891421ba2SRobert Watson * Free a prison, if any. 126991421ba2SRobert Watson */ 127091421ba2SRobert Watson if (jailed(cr)) 127191421ba2SRobert Watson prison_free(cr->cr_prison); 1272df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 12731e5d626aSAlfred Perlstein } else { 12749ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1275df8bae1dSRodney W. Grimes } 1276f535380cSDon Lewis } 1277df8bae1dSRodney W. Grimes 1278df8bae1dSRodney W. Grimes /* 1279df8bae1dSRodney W. Grimes * Copy cred structure to a new one and free the old one. 1280df8bae1dSRodney W. Grimes */ 1281df8bae1dSRodney W. Grimes struct ucred * 1282df8bae1dSRodney W. Grimes crcopy(cr) 1283df8bae1dSRodney W. Grimes struct ucred *cr; 1284df8bae1dSRodney W. Grimes { 1285df8bae1dSRodney W. Grimes struct ucred *newcr; 1286df8bae1dSRodney W. Grimes 12879ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 12881e5d626aSAlfred Perlstein if (cr->cr_ref == 1) { 12899ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1290df8bae1dSRodney W. Grimes return (cr); 12911e5d626aSAlfred Perlstein } 12929ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 12931e5d626aSAlfred Perlstein newcr = crdup(cr); 1294df8bae1dSRodney W. Grimes crfree(cr); 1295df8bae1dSRodney W. Grimes return (newcr); 1296df8bae1dSRodney W. Grimes } 1297df8bae1dSRodney W. Grimes 1298df8bae1dSRodney W. Grimes /* 1299df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1300df8bae1dSRodney W. Grimes */ 1301df8bae1dSRodney W. Grimes struct ucred * 1302df8bae1dSRodney W. Grimes crdup(cr) 1303df8bae1dSRodney W. Grimes struct ucred *cr; 1304df8bae1dSRodney W. Grimes { 1305df8bae1dSRodney W. Grimes struct ucred *newcr; 1306df8bae1dSRodney W. Grimes 13071e5d626aSAlfred Perlstein MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 1308df8bae1dSRodney W. Grimes *newcr = *cr; 13091e5d626aSAlfred Perlstein mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 1310f535380cSDon Lewis uihold(newcr->cr_uidinfo); 131191421ba2SRobert Watson if (jailed(newcr)) 131291421ba2SRobert Watson prison_hold(newcr->cr_prison); 1313df8bae1dSRodney W. Grimes newcr->cr_ref = 1; 1314df8bae1dSRodney W. Grimes return (newcr); 1315df8bae1dSRodney W. Grimes } 1316df8bae1dSRodney W. Grimes 1317df8bae1dSRodney W. Grimes /* 1318df8bae1dSRodney W. Grimes * Get login name, if available. 1319df8bae1dSRodney W. Grimes */ 1320d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1321df8bae1dSRodney W. Grimes struct getlogin_args { 1322df8bae1dSRodney W. Grimes char *namebuf; 1323df8bae1dSRodney W. Grimes u_int namelen; 1324df8bae1dSRodney W. Grimes }; 1325d2d3e875SBruce Evans #endif 1326df8bae1dSRodney W. Grimes /* ARGSUSED */ 132726f9a767SRodney W. Grimes int 1328cb226aaaSPoul-Henning Kamp getlogin(p, uap) 1329df8bae1dSRodney W. Grimes struct proc *p; 1330df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1331df8bae1dSRodney W. Grimes { 1332df8bae1dSRodney W. Grimes 133330cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 133453490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1335df8bae1dSRodney W. Grimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1336df8bae1dSRodney W. Grimes (caddr_t) uap->namebuf, uap->namelen)); 1337df8bae1dSRodney W. Grimes } 1338df8bae1dSRodney W. Grimes 1339df8bae1dSRodney W. Grimes /* 1340df8bae1dSRodney W. Grimes * Set login name. 1341df8bae1dSRodney W. Grimes */ 1342d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1343df8bae1dSRodney W. Grimes struct setlogin_args { 1344df8bae1dSRodney W. Grimes char *namebuf; 1345df8bae1dSRodney W. Grimes }; 1346d2d3e875SBruce Evans #endif 1347df8bae1dSRodney W. Grimes /* ARGSUSED */ 134826f9a767SRodney W. Grimes int 1349cb226aaaSPoul-Henning Kamp setlogin(p, uap) 1350df8bae1dSRodney W. Grimes struct proc *p; 1351df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1352df8bae1dSRodney W. Grimes { 1353df8bae1dSRodney W. Grimes int error; 1354964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1355df8bae1dSRodney W. Grimes 135675c13541SPoul-Henning Kamp if ((error = suser_xxx(0, p, PRISON_ROOT))) 1357df8bae1dSRodney W. Grimes return (error); 1358184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 135910d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1360df8bae1dSRodney W. Grimes if (error == ENAMETOOLONG) 1361df8bae1dSRodney W. Grimes error = EINVAL; 1362184989c2SDavid Nugent else if (!error) 1363184989c2SDavid Nugent (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1364964ca0caSAndrey A. Chernov sizeof(logintmp)); 1365df8bae1dSRodney W. Grimes return (error); 1366df8bae1dSRodney W. Grimes } 1367d5f81602SSean Eric Fagan 1368d5f81602SSean Eric Fagan void 1369d5f81602SSean Eric Fagan setsugid(p) 1370d5f81602SSean Eric Fagan struct proc *p; 1371d5f81602SSean Eric Fagan { 1372d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 137389361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1374d5f81602SSean Eric Fagan p->p_stops = 0; 1375d5f81602SSean Eric Fagan } 1376f535380cSDon Lewis 1377f535380cSDon Lewis /* 1378f535380cSDon Lewis * Helper function to change the effective uid of a process 1379f535380cSDon Lewis */ 1380f535380cSDon Lewis void 1381f535380cSDon Lewis change_euid(p, euid) 1382f535380cSDon Lewis struct proc *p; 1383f535380cSDon Lewis uid_t euid; 1384f535380cSDon Lewis { 1385f535380cSDon Lewis struct pcred *pc; 1386f535380cSDon Lewis struct uidinfo *uip; 1387f535380cSDon Lewis 1388f535380cSDon Lewis pc = p->p_cred; 1389f535380cSDon Lewis /* 1390f535380cSDon Lewis * crcopy is essentially a NOP if ucred has a reference count 1391f535380cSDon Lewis * of 1, which is true if it has already been copied. 1392f535380cSDon Lewis */ 1393f535380cSDon Lewis pc->pc_ucred = crcopy(pc->pc_ucred); 1394f535380cSDon Lewis uip = pc->pc_ucred->cr_uidinfo; 1395f535380cSDon Lewis pc->pc_ucred->cr_uid = euid; 1396f535380cSDon Lewis pc->pc_ucred->cr_uidinfo = uifind(euid); 1397f535380cSDon Lewis uifree(uip); 1398f535380cSDon Lewis } 1399f535380cSDon Lewis 1400f535380cSDon Lewis /* 1401f535380cSDon Lewis * Helper function to change the real uid of a process 1402f535380cSDon Lewis * 1403f535380cSDon Lewis * The per-uid process count for this process is transfered from 1404f535380cSDon Lewis * the old uid to the new uid. 1405f535380cSDon Lewis */ 1406810bfc8eSAndrew Gallatin void 1407f535380cSDon Lewis change_ruid(p, ruid) 1408f535380cSDon Lewis struct proc *p; 1409f535380cSDon Lewis uid_t ruid; 1410f535380cSDon Lewis { 1411f535380cSDon Lewis struct pcred *pc; 1412f535380cSDon Lewis struct uidinfo *uip; 1413f535380cSDon Lewis 1414f535380cSDon Lewis pc = p->p_cred; 1415f535380cSDon Lewis (void)chgproccnt(pc->p_uidinfo, -1, 0); 1416f535380cSDon Lewis uip = pc->p_uidinfo; 1417f535380cSDon Lewis /* It is assumed that pcred is not shared between processes */ 1418f535380cSDon Lewis pc->p_ruid = ruid; 1419f535380cSDon Lewis pc->p_uidinfo = uifind(ruid); 1420f535380cSDon Lewis (void)chgproccnt(pc->p_uidinfo, 1, 0); 1421f535380cSDon Lewis uifree(uip); 1422f535380cSDon Lewis } 1423