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/acct.h> 51df8bae1dSRodney W. Grimes #include <sys/systm.h> 52d2d3e875SBruce Evans #include <sys/sysproto.h> 531c5bb3eaSPeter Wemm #include <sys/kernel.h> 5498f03f90SJake Burkholder #include <sys/lock.h> 55df8bae1dSRodney W. Grimes #include <sys/proc.h> 56df8bae1dSRodney W. Grimes #include <sys/malloc.h> 57d5f81602SSean Eric Fagan #include <sys/pioctl.h> 58f535380cSDon Lewis #include <sys/resourcevar.h> 59579f4eb4SRobert Watson #include <sys/sysctl.h> 6091421ba2SRobert Watson #include <sys/jail.h> 61df8bae1dSRodney W. Grimes 62a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_CRED, "cred", "credentials"); 63a1c995b6SPoul-Henning Kamp 64d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 65ad7507e2SSteven Wallace struct getpid_args { 66df8bae1dSRodney W. Grimes int dummy; 67df8bae1dSRodney W. Grimes }; 68d2d3e875SBruce Evans #endif 69df8bae1dSRodney W. Grimes 7036e9f877SMatthew Dillon /* 7198f03f90SJake Burkholder * getpid - MP SAFE 7236e9f877SMatthew Dillon */ 7398f03f90SJake Burkholder 74df8bae1dSRodney W. Grimes /* ARGSUSED */ 7526f9a767SRodney W. Grimes int 76cb226aaaSPoul-Henning Kamp getpid(p, uap) 77df8bae1dSRodney W. Grimes struct proc *p; 78ad7507e2SSteven Wallace struct getpid_args *uap; 79df8bae1dSRodney W. Grimes { 80df8bae1dSRodney W. Grimes 81cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pid; 82df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 83bae3a80bSJohn Baldwin PROC_LOCK(p); 84cb226aaaSPoul-Henning Kamp p->p_retval[1] = p->p_pptr->p_pid; 85bae3a80bSJohn Baldwin PROC_UNLOCK(p); 86df8bae1dSRodney W. Grimes #endif 87df8bae1dSRodney W. Grimes return (0); 88df8bae1dSRodney W. Grimes } 89df8bae1dSRodney W. Grimes 9098f03f90SJake Burkholder /* 9198f03f90SJake Burkholder * getppid - MP SAFE 9298f03f90SJake Burkholder */ 9398f03f90SJake Burkholder 94d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 95ad7507e2SSteven Wallace struct getppid_args { 96ad7507e2SSteven Wallace int dummy; 97ad7507e2SSteven Wallace }; 98d2d3e875SBruce Evans #endif 99df8bae1dSRodney W. Grimes /* ARGSUSED */ 10026f9a767SRodney W. Grimes int 101cb226aaaSPoul-Henning Kamp getppid(p, uap) 102df8bae1dSRodney W. Grimes struct proc *p; 103ad7507e2SSteven Wallace struct getppid_args *uap; 104df8bae1dSRodney W. Grimes { 105df8bae1dSRodney W. Grimes 106bae3a80bSJohn Baldwin PROC_LOCK(p); 107cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pptr->p_pid; 108bae3a80bSJohn Baldwin PROC_UNLOCK(p); 109df8bae1dSRodney W. Grimes return (0); 110df8bae1dSRodney W. Grimes } 111df8bae1dSRodney W. Grimes 11236e9f877SMatthew Dillon /* 11336e9f877SMatthew Dillon * Get process group ID; note that POSIX getpgrp takes no parameter 11436e9f877SMatthew Dillon * 11536e9f877SMatthew Dillon * MP SAFE 11636e9f877SMatthew Dillon */ 117d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 118ad7507e2SSteven Wallace struct getpgrp_args { 119ad7507e2SSteven Wallace int dummy; 120ad7507e2SSteven Wallace }; 121d2d3e875SBruce Evans #endif 122ad7507e2SSteven Wallace 12326f9a767SRodney W. Grimes int 124cb226aaaSPoul-Henning Kamp getpgrp(p, uap) 125df8bae1dSRodney W. Grimes struct proc *p; 126ad7507e2SSteven Wallace struct getpgrp_args *uap; 127df8bae1dSRodney W. Grimes { 128df8bae1dSRodney W. Grimes 129cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pgrp->pg_id; 130df8bae1dSRodney W. Grimes return (0); 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes 1331a5018a0SPeter Wemm /* Get an arbitary pid's process group id */ 1341a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1351a5018a0SPeter Wemm struct getpgid_args { 1361a5018a0SPeter Wemm pid_t pid; 1371a5018a0SPeter Wemm }; 1381a5018a0SPeter Wemm #endif 1391a5018a0SPeter Wemm 1401a5018a0SPeter Wemm int 141cb226aaaSPoul-Henning Kamp getpgid(p, uap) 1421a5018a0SPeter Wemm struct proc *p; 1431a5018a0SPeter Wemm struct getpgid_args *uap; 1441a5018a0SPeter Wemm { 14565de0c7aSDon Lewis struct proc *pt; 14665de0c7aSDon Lewis 14765de0c7aSDon Lewis pt = p; 1481a5018a0SPeter Wemm if (uap->pid == 0) 1491a5018a0SPeter Wemm goto found; 1501a5018a0SPeter Wemm 15165de0c7aSDon Lewis if ((pt = pfind(uap->pid)) == 0) 1521a5018a0SPeter Wemm return ESRCH; 1531a5018a0SPeter Wemm found: 15465de0c7aSDon Lewis p->p_retval[0] = pt->p_pgrp->pg_id; 1551a5018a0SPeter Wemm return 0; 1561a5018a0SPeter Wemm } 1571a5018a0SPeter Wemm 1581a5018a0SPeter Wemm /* 1591a5018a0SPeter Wemm * Get an arbitary pid's session id. 1601a5018a0SPeter Wemm */ 1611a5018a0SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 1621a5018a0SPeter Wemm struct getsid_args { 1631a5018a0SPeter Wemm pid_t pid; 1641a5018a0SPeter Wemm }; 1651a5018a0SPeter Wemm #endif 1661a5018a0SPeter Wemm 1671a5018a0SPeter Wemm int 168cb226aaaSPoul-Henning Kamp getsid(p, uap) 1691a5018a0SPeter Wemm struct proc *p; 1701a5018a0SPeter Wemm struct getsid_args *uap; 1711a5018a0SPeter Wemm { 17265de0c7aSDon Lewis struct proc *pt; 17365de0c7aSDon Lewis 17465de0c7aSDon Lewis pt = p; 1751a5018a0SPeter Wemm if (uap->pid == 0) 1761a5018a0SPeter Wemm goto found; 1771a5018a0SPeter Wemm 1784c061a9dSBen Smithurst if ((pt = pfind(uap->pid)) == 0) 1791a5018a0SPeter Wemm return ESRCH; 1801a5018a0SPeter Wemm found: 18165de0c7aSDon Lewis p->p_retval[0] = pt->p_session->s_sid; 1821a5018a0SPeter Wemm return 0; 1831a5018a0SPeter Wemm } 1841a5018a0SPeter Wemm 1851a5018a0SPeter Wemm 1867c8fdcbdSMatthew Dillon /* 1877c8fdcbdSMatthew Dillon * getuid() - MP SAFE 1887c8fdcbdSMatthew Dillon */ 189d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 190ad7507e2SSteven Wallace struct getuid_args { 191ad7507e2SSteven Wallace int dummy; 192ad7507e2SSteven Wallace }; 193d2d3e875SBruce Evans #endif 194ad7507e2SSteven Wallace 195df8bae1dSRodney W. Grimes /* ARGSUSED */ 19626f9a767SRodney W. Grimes int 197cb226aaaSPoul-Henning Kamp getuid(p, uap) 198df8bae1dSRodney W. Grimes struct proc *p; 199ad7507e2SSteven Wallace struct getuid_args *uap; 200df8bae1dSRodney W. Grimes { 201df8bae1dSRodney W. Grimes 202cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_cred->p_ruid; 203df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 204cb226aaaSPoul-Henning Kamp p->p_retval[1] = p->p_ucred->cr_uid; 205df8bae1dSRodney W. Grimes #endif 206df8bae1dSRodney W. Grimes return (0); 207df8bae1dSRodney W. Grimes } 208df8bae1dSRodney W. Grimes 2097c8fdcbdSMatthew Dillon /* 2107c8fdcbdSMatthew Dillon * geteuid() - MP SAFE 2117c8fdcbdSMatthew Dillon */ 212d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 213ad7507e2SSteven Wallace struct geteuid_args { 214ad7507e2SSteven Wallace int dummy; 215ad7507e2SSteven Wallace }; 216d2d3e875SBruce Evans #endif 217ad7507e2SSteven Wallace 218df8bae1dSRodney W. Grimes /* ARGSUSED */ 21926f9a767SRodney W. Grimes int 220cb226aaaSPoul-Henning Kamp geteuid(p, uap) 221df8bae1dSRodney W. Grimes struct proc *p; 222ad7507e2SSteven Wallace struct geteuid_args *uap; 223df8bae1dSRodney W. Grimes { 224df8bae1dSRodney W. Grimes 225cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_ucred->cr_uid; 226df8bae1dSRodney W. Grimes return (0); 227df8bae1dSRodney W. Grimes } 228df8bae1dSRodney W. Grimes 2297c8fdcbdSMatthew Dillon /* 2307c8fdcbdSMatthew Dillon * getgid() - MP SAFE 2317c8fdcbdSMatthew Dillon */ 232d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 233ad7507e2SSteven Wallace struct getgid_args { 234ad7507e2SSteven Wallace int dummy; 235ad7507e2SSteven Wallace }; 236d2d3e875SBruce Evans #endif 237ad7507e2SSteven Wallace 238df8bae1dSRodney W. Grimes /* ARGSUSED */ 23926f9a767SRodney W. Grimes int 240cb226aaaSPoul-Henning Kamp getgid(p, uap) 241df8bae1dSRodney W. Grimes struct proc *p; 242ad7507e2SSteven Wallace struct getgid_args *uap; 243df8bae1dSRodney W. Grimes { 244df8bae1dSRodney W. Grimes 245cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_cred->p_rgid; 246df8bae1dSRodney W. Grimes #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 247cb226aaaSPoul-Henning Kamp p->p_retval[1] = p->p_ucred->cr_groups[0]; 248df8bae1dSRodney W. Grimes #endif 249df8bae1dSRodney W. Grimes return (0); 250df8bae1dSRodney W. Grimes } 251df8bae1dSRodney W. Grimes 252df8bae1dSRodney W. Grimes /* 253df8bae1dSRodney W. Grimes * Get effective group ID. The "egid" is groups[0], and could be obtained 254df8bae1dSRodney W. Grimes * via getgroups. This syscall exists because it is somewhat painful to do 255df8bae1dSRodney W. Grimes * correctly in a library function. 256df8bae1dSRodney W. Grimes */ 257d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 258ad7507e2SSteven Wallace struct getegid_args { 259ad7507e2SSteven Wallace int dummy; 260ad7507e2SSteven Wallace }; 261d2d3e875SBruce Evans #endif 262ad7507e2SSteven Wallace 263df8bae1dSRodney W. Grimes /* ARGSUSED */ 26426f9a767SRodney W. Grimes int 265cb226aaaSPoul-Henning Kamp getegid(p, uap) 266df8bae1dSRodney W. Grimes struct proc *p; 267ad7507e2SSteven Wallace struct getegid_args *uap; 268df8bae1dSRodney W. Grimes { 269df8bae1dSRodney W. Grimes 270cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_ucred->cr_groups[0]; 271df8bae1dSRodney W. Grimes return (0); 272df8bae1dSRodney W. Grimes } 273df8bae1dSRodney W. Grimes 274d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 275df8bae1dSRodney W. Grimes struct getgroups_args { 276df8bae1dSRodney W. Grimes u_int gidsetsize; 277df8bae1dSRodney W. Grimes gid_t *gidset; 278df8bae1dSRodney W. Grimes }; 279d2d3e875SBruce Evans #endif 28026f9a767SRodney W. Grimes int 281cb226aaaSPoul-Henning Kamp getgroups(p, uap) 282df8bae1dSRodney W. Grimes struct proc *p; 283df8bae1dSRodney W. Grimes register struct getgroups_args *uap; 284df8bae1dSRodney W. Grimes { 285df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 286df8bae1dSRodney W. Grimes register u_int ngrp; 287df8bae1dSRodney W. Grimes int error; 288df8bae1dSRodney W. Grimes 289df8bae1dSRodney W. Grimes if ((ngrp = uap->gidsetsize) == 0) { 290cb226aaaSPoul-Henning Kamp p->p_retval[0] = pc->pc_ucred->cr_ngroups; 291df8bae1dSRodney W. Grimes return (0); 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes if (ngrp < pc->pc_ucred->cr_ngroups) 294df8bae1dSRodney W. Grimes return (EINVAL); 295df8bae1dSRodney W. Grimes ngrp = pc->pc_ucred->cr_ngroups; 296bb56ec4aSPoul-Henning Kamp if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups, 297bb56ec4aSPoul-Henning Kamp (caddr_t)uap->gidset, ngrp * sizeof(gid_t)))) 298df8bae1dSRodney W. Grimes return (error); 299cb226aaaSPoul-Henning Kamp p->p_retval[0] = ngrp; 300df8bae1dSRodney W. Grimes return (0); 301df8bae1dSRodney W. Grimes } 302df8bae1dSRodney W. Grimes 303d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 30482970b81SBruce Evans struct setsid_args { 305ad7507e2SSteven Wallace int dummy; 306ad7507e2SSteven Wallace }; 307d2d3e875SBruce Evans #endif 308ad7507e2SSteven Wallace 309df8bae1dSRodney W. Grimes /* ARGSUSED */ 31026f9a767SRodney W. Grimes int 311cb226aaaSPoul-Henning Kamp setsid(p, uap) 312df8bae1dSRodney W. Grimes register struct proc *p; 31382970b81SBruce Evans struct setsid_args *uap; 314df8bae1dSRodney W. Grimes { 315df8bae1dSRodney W. Grimes 316df8bae1dSRodney W. Grimes if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 317df8bae1dSRodney W. Grimes return (EPERM); 318df8bae1dSRodney W. Grimes } else { 319df8bae1dSRodney W. Grimes (void)enterpgrp(p, p->p_pid, 1); 320cb226aaaSPoul-Henning Kamp p->p_retval[0] = p->p_pid; 321df8bae1dSRodney W. Grimes return (0); 322df8bae1dSRodney W. Grimes } 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes /* 326df8bae1dSRodney W. Grimes * set process group (setpgid/old setpgrp) 327df8bae1dSRodney W. Grimes * 328df8bae1dSRodney W. Grimes * caller does setpgid(targpid, targpgid) 329df8bae1dSRodney W. Grimes * 330df8bae1dSRodney W. Grimes * pid must be caller or child of caller (ESRCH) 331df8bae1dSRodney W. Grimes * if a child 332df8bae1dSRodney W. Grimes * pid must be in same session (EPERM) 333df8bae1dSRodney W. Grimes * pid can't have done an exec (EACCES) 334df8bae1dSRodney W. Grimes * if pgid != pid 335df8bae1dSRodney W. Grimes * there must exist some pid in same session having pgid (EPERM) 336df8bae1dSRodney W. Grimes * pid must not be session leader (EPERM) 337df8bae1dSRodney W. Grimes */ 338d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 339df8bae1dSRodney W. Grimes struct setpgid_args { 340df8bae1dSRodney W. Grimes int pid; /* target process id */ 341df8bae1dSRodney W. Grimes int pgid; /* target pgrp id */ 342df8bae1dSRodney W. Grimes }; 343d2d3e875SBruce Evans #endif 344df8bae1dSRodney W. Grimes /* ARGSUSED */ 34526f9a767SRodney W. Grimes int 346cb226aaaSPoul-Henning Kamp setpgid(curp, uap) 347df8bae1dSRodney W. Grimes struct proc *curp; 348df8bae1dSRodney W. Grimes register struct setpgid_args *uap; 349df8bae1dSRodney W. Grimes { 350df8bae1dSRodney W. Grimes register struct proc *targp; /* target process */ 351df8bae1dSRodney W. Grimes register struct pgrp *pgrp; /* target pgrp */ 352df8bae1dSRodney W. Grimes 35378f64bccSBruce Evans if (uap->pgid < 0) 35478f64bccSBruce Evans return (EINVAL); 355df8bae1dSRodney W. Grimes if (uap->pid != 0 && uap->pid != curp->p_pid) { 356df8bae1dSRodney W. Grimes if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 357df8bae1dSRodney W. Grimes return (ESRCH); 358cd73303cSDavid Greenman if (targp->p_pgrp == NULL || targp->p_session != curp->p_session) 359df8bae1dSRodney W. Grimes return (EPERM); 360df8bae1dSRodney W. Grimes if (targp->p_flag & P_EXEC) 361df8bae1dSRodney W. Grimes return (EACCES); 362df8bae1dSRodney W. Grimes } else 363df8bae1dSRodney W. Grimes targp = curp; 364df8bae1dSRodney W. Grimes if (SESS_LEADER(targp)) 365df8bae1dSRodney W. Grimes return (EPERM); 366df8bae1dSRodney W. Grimes if (uap->pgid == 0) 367df8bae1dSRodney W. Grimes uap->pgid = targp->p_pid; 368df8bae1dSRodney W. Grimes else if (uap->pgid != targp->p_pid) 369df8bae1dSRodney W. Grimes if ((pgrp = pgfind(uap->pgid)) == 0 || 370df8bae1dSRodney W. Grimes pgrp->pg_session != curp->p_session) 371df8bae1dSRodney W. Grimes return (EPERM); 372df8bae1dSRodney W. Grimes return (enterpgrp(targp, uap->pgid, 0)); 373df8bae1dSRodney W. Grimes } 374df8bae1dSRodney W. Grimes 375a08f4bf6SPeter Wemm /* 376a08f4bf6SPeter Wemm * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD 3772fa72ea7SJeroen Ruigrok van der Werven * compatible. It says that setting the uid/gid to euid/egid is a special 378a08f4bf6SPeter Wemm * case of "appropriate privilege". Once the rules are expanded out, this 379a08f4bf6SPeter Wemm * basically means that setuid(nnn) sets all three id's, in all permitted 380a08f4bf6SPeter Wemm * cases unless _POSIX_SAVED_IDS is enabled. In that case, setuid(getuid()) 381a08f4bf6SPeter Wemm * does not set the saved id - this is dangerous for traditional BSD 382a08f4bf6SPeter Wemm * programs. For this reason, we *really* do not want to set 383a08f4bf6SPeter Wemm * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2. 384a08f4bf6SPeter Wemm */ 385a08f4bf6SPeter Wemm #define POSIX_APPENDIX_B_4_2_2 386a08f4bf6SPeter Wemm 387d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 388df8bae1dSRodney W. Grimes struct setuid_args { 389df8bae1dSRodney W. Grimes uid_t uid; 390df8bae1dSRodney W. Grimes }; 391d2d3e875SBruce Evans #endif 392df8bae1dSRodney W. Grimes /* ARGSUSED */ 39326f9a767SRodney W. Grimes int 394cb226aaaSPoul-Henning Kamp setuid(p, uap) 395df8bae1dSRodney W. Grimes struct proc *p; 396df8bae1dSRodney W. Grimes struct setuid_args *uap; 397df8bae1dSRodney W. Grimes { 398df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 399df8bae1dSRodney W. Grimes register uid_t uid; 400df8bae1dSRodney W. Grimes int error; 401df8bae1dSRodney W. Grimes 402a08f4bf6SPeter Wemm /* 403a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 404a08f4bf6SPeter Wemm * 405a08f4bf6SPeter Wemm * Note that setuid(geteuid()) is a special case of 406a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 4072fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 408a08f4bf6SPeter Wemm * semantics. Basically, it means that "setuid(xx)" sets all 409a08f4bf6SPeter Wemm * three id's (assuming you have privs). 410a08f4bf6SPeter Wemm * 411a08f4bf6SPeter Wemm * Notes on the logic. We do things in three steps. 412a08f4bf6SPeter Wemm * 1: We determine if the euid is going to change, and do EPERM 413a08f4bf6SPeter Wemm * right away. We unconditionally change the euid later if this 414a08f4bf6SPeter Wemm * test is satisfied, simplifying that part of the logic. 415a08f4bf6SPeter Wemm * 2: We determine if the real and/or saved uid's are going to 416a08f4bf6SPeter Wemm * change. Determined by compile options. 417a08f4bf6SPeter Wemm * 3: Change euid last. (after tests in #2 for "appropriate privs") 418a08f4bf6SPeter Wemm */ 419df8bae1dSRodney W. Grimes uid = uap->uid; 420a08f4bf6SPeter Wemm if (uid != pc->p_ruid && /* allow setuid(getuid()) */ 4213f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 422a08f4bf6SPeter Wemm uid != pc->p_svuid && /* allow setuid(saved gid) */ 423a08f4bf6SPeter Wemm #endif 424a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 425a08f4bf6SPeter Wemm uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ 4263f246666SAndrey A. Chernov #endif 42775c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 428df8bae1dSRodney W. Grimes return (error); 429a08f4bf6SPeter Wemm 430a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 431df8bae1dSRodney W. Grimes /* 432a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or uid == euid) 433a08f4bf6SPeter Wemm * If so, we are changing the real uid and/or saved uid. 434df8bae1dSRodney W. Grimes */ 4353f246666SAndrey A. Chernov if ( 436a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ 437a08f4bf6SPeter Wemm uid == pc->pc_ucred->cr_uid || 4383f246666SAndrey A. Chernov #endif 43975c13541SPoul-Henning Kamp suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 440a08f4bf6SPeter Wemm #endif 441a08f4bf6SPeter Wemm { 442a08f4bf6SPeter Wemm /* 443f535380cSDon Lewis * Set the real uid and transfer proc count to new user. 444a08f4bf6SPeter Wemm */ 445a08f4bf6SPeter Wemm if (uid != pc->p_ruid) { 446f535380cSDon Lewis change_ruid(p, uid); 447f535380cSDon Lewis setsugid(p); 448d3cdb93dSAndrey A. Chernov } 449a08f4bf6SPeter Wemm /* 450a08f4bf6SPeter Wemm * Set saved uid 451a08f4bf6SPeter Wemm * 452a08f4bf6SPeter Wemm * XXX always set saved uid even if not _POSIX_SAVED_IDS, as 453a08f4bf6SPeter Wemm * the security of seteuid() depends on it. B.4.2.2 says it 454a08f4bf6SPeter Wemm * is important that we should do this. 455a08f4bf6SPeter Wemm */ 456a08f4bf6SPeter Wemm if (pc->p_svuid != uid) { 457a08f4bf6SPeter Wemm pc->p_svuid = uid; 458d5f81602SSean Eric Fagan setsugid(p); 459a08f4bf6SPeter Wemm } 460a08f4bf6SPeter Wemm } 461a08f4bf6SPeter Wemm 462a08f4bf6SPeter Wemm /* 463a08f4bf6SPeter Wemm * In all permitted cases, we are changing the euid. 464a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 465a08f4bf6SPeter Wemm */ 466a08f4bf6SPeter Wemm if (pc->pc_ucred->cr_uid != uid) { 467f535380cSDon Lewis change_euid(p, uid); 468d5f81602SSean Eric Fagan setsugid(p); 469a08f4bf6SPeter Wemm } 470df8bae1dSRodney W. Grimes return (0); 471df8bae1dSRodney W. Grimes } 472df8bae1dSRodney W. Grimes 473d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 474df8bae1dSRodney W. Grimes struct seteuid_args { 475df8bae1dSRodney W. Grimes uid_t euid; 476df8bae1dSRodney W. Grimes }; 477d2d3e875SBruce Evans #endif 478df8bae1dSRodney W. Grimes /* ARGSUSED */ 47926f9a767SRodney W. Grimes int 480cb226aaaSPoul-Henning Kamp seteuid(p, uap) 481df8bae1dSRodney W. Grimes struct proc *p; 482df8bae1dSRodney W. Grimes struct seteuid_args *uap; 483df8bae1dSRodney W. Grimes { 484df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 485df8bae1dSRodney W. Grimes register uid_t euid; 486df8bae1dSRodney W. Grimes int error; 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes euid = uap->euid; 489229a15f0SPeter Wemm if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ 490229a15f0SPeter Wemm euid != pc->p_svuid && /* allow seteuid(saved uid) */ 49175c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 492df8bae1dSRodney W. Grimes return (error); 493df8bae1dSRodney W. Grimes /* 494df8bae1dSRodney W. Grimes * Everything's okay, do it. Copy credentials so other references do 495df8bae1dSRodney W. Grimes * not see our changes. 496df8bae1dSRodney W. Grimes */ 497229a15f0SPeter Wemm if (pc->pc_ucred->cr_uid != euid) { 498f535380cSDon Lewis change_euid(p, euid); 499d5f81602SSean Eric Fagan setsugid(p); 500229a15f0SPeter Wemm } 501df8bae1dSRodney W. Grimes return (0); 502df8bae1dSRodney W. Grimes } 503df8bae1dSRodney W. Grimes 504d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 505df8bae1dSRodney W. Grimes struct setgid_args { 506df8bae1dSRodney W. Grimes gid_t gid; 507df8bae1dSRodney W. Grimes }; 508d2d3e875SBruce Evans #endif 509df8bae1dSRodney W. Grimes /* ARGSUSED */ 51026f9a767SRodney W. Grimes int 511cb226aaaSPoul-Henning Kamp setgid(p, uap) 512df8bae1dSRodney W. Grimes struct proc *p; 513df8bae1dSRodney W. Grimes struct setgid_args *uap; 514df8bae1dSRodney W. Grimes { 515df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 516df8bae1dSRodney W. Grimes register gid_t gid; 517df8bae1dSRodney W. Grimes int error; 518df8bae1dSRodney W. Grimes 519a08f4bf6SPeter Wemm /* 520a08f4bf6SPeter Wemm * See if we have "permission" by POSIX 1003.1 rules. 521a08f4bf6SPeter Wemm * 522a08f4bf6SPeter Wemm * Note that setgid(getegid()) is a special case of 523a08f4bf6SPeter Wemm * "appropriate privileges" in appendix B.4.2.2. We need 5242fa72ea7SJeroen Ruigrok van der Werven * to use this clause to be compatible with traditional BSD 525a08f4bf6SPeter Wemm * semantics. Basically, it means that "setgid(xx)" sets all 526a08f4bf6SPeter Wemm * three id's (assuming you have privs). 527a08f4bf6SPeter Wemm * 528a08f4bf6SPeter Wemm * For notes on the logic here, see setuid() above. 529a08f4bf6SPeter Wemm */ 530df8bae1dSRodney W. Grimes gid = uap->gid; 531a08f4bf6SPeter Wemm if (gid != pc->p_rgid && /* allow setgid(getgid()) */ 5323f246666SAndrey A. Chernov #ifdef _POSIX_SAVED_IDS 533a08f4bf6SPeter Wemm gid != pc->p_svgid && /* allow setgid(saved gid) */ 534a08f4bf6SPeter Wemm #endif 535a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ 536a08f4bf6SPeter Wemm gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ 5373f246666SAndrey A. Chernov #endif 53875c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 539df8bae1dSRodney W. Grimes return (error); 540a08f4bf6SPeter Wemm 541a08f4bf6SPeter Wemm #ifdef _POSIX_SAVED_IDS 542a08f4bf6SPeter Wemm /* 543a08f4bf6SPeter Wemm * Do we have "appropriate privileges" (are we root or gid == egid) 544a08f4bf6SPeter Wemm * If so, we are changing the real uid and saved gid. 545a08f4bf6SPeter Wemm */ 546a08f4bf6SPeter Wemm if ( 547a08f4bf6SPeter Wemm #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ 548a08f4bf6SPeter Wemm gid == pc->pc_ucred->cr_groups[0] || 549a08f4bf6SPeter Wemm #endif 55075c13541SPoul-Henning Kamp suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ 551a08f4bf6SPeter Wemm #endif 552a08f4bf6SPeter Wemm { 553a08f4bf6SPeter Wemm /* 554a08f4bf6SPeter Wemm * Set real gid 555a08f4bf6SPeter Wemm */ 556a08f4bf6SPeter Wemm if (pc->p_rgid != gid) { 557a08f4bf6SPeter Wemm pc->p_rgid = gid; 558d5f81602SSean Eric Fagan setsugid(p); 559a08f4bf6SPeter Wemm } 560a08f4bf6SPeter Wemm /* 561a08f4bf6SPeter Wemm * Set saved gid 562a08f4bf6SPeter Wemm * 563a08f4bf6SPeter Wemm * XXX always set saved gid even if not _POSIX_SAVED_IDS, as 564a08f4bf6SPeter Wemm * the security of setegid() depends on it. B.4.2.2 says it 565a08f4bf6SPeter Wemm * is important that we should do this. 566a08f4bf6SPeter Wemm */ 567a08f4bf6SPeter Wemm if (pc->p_svgid != gid) { 568a08f4bf6SPeter Wemm pc->p_svgid = gid; 569d5f81602SSean Eric Fagan setsugid(p); 570a08f4bf6SPeter Wemm } 571a08f4bf6SPeter Wemm } 572a08f4bf6SPeter Wemm /* 573a08f4bf6SPeter Wemm * In all cases permitted cases, we are changing the egid. 574a08f4bf6SPeter Wemm * Copy credentials so other references do not see our changes. 575a08f4bf6SPeter Wemm */ 576a08f4bf6SPeter Wemm if (pc->pc_ucred->cr_groups[0] != gid) { 577df8bae1dSRodney W. Grimes pc->pc_ucred = crcopy(pc->pc_ucred); 578df8bae1dSRodney W. Grimes pc->pc_ucred->cr_groups[0] = gid; 579d5f81602SSean Eric Fagan setsugid(p); 580a08f4bf6SPeter Wemm } 581df8bae1dSRodney W. Grimes return (0); 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes 584d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 585df8bae1dSRodney W. Grimes struct setegid_args { 586df8bae1dSRodney W. Grimes gid_t egid; 587df8bae1dSRodney W. Grimes }; 588d2d3e875SBruce Evans #endif 589df8bae1dSRodney W. Grimes /* ARGSUSED */ 59026f9a767SRodney W. Grimes int 591cb226aaaSPoul-Henning Kamp setegid(p, uap) 592df8bae1dSRodney W. Grimes struct proc *p; 593df8bae1dSRodney W. Grimes struct setegid_args *uap; 594df8bae1dSRodney W. Grimes { 595df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 596df8bae1dSRodney W. Grimes register gid_t egid; 597df8bae1dSRodney W. Grimes int error; 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes egid = uap->egid; 600229a15f0SPeter Wemm if (egid != pc->p_rgid && /* allow setegid(getgid()) */ 601229a15f0SPeter Wemm egid != pc->p_svgid && /* allow setegid(saved gid) */ 60275c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT))) 603df8bae1dSRodney W. Grimes return (error); 604229a15f0SPeter Wemm if (pc->pc_ucred->cr_groups[0] != egid) { 605df8bae1dSRodney W. Grimes pc->pc_ucred = crcopy(pc->pc_ucred); 606df8bae1dSRodney W. Grimes pc->pc_ucred->cr_groups[0] = egid; 607d5f81602SSean Eric Fagan setsugid(p); 608229a15f0SPeter Wemm } 609df8bae1dSRodney W. Grimes return (0); 610df8bae1dSRodney W. Grimes } 611df8bae1dSRodney W. Grimes 612d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 613df8bae1dSRodney W. Grimes struct setgroups_args { 614df8bae1dSRodney W. Grimes u_int gidsetsize; 615df8bae1dSRodney W. Grimes gid_t *gidset; 616df8bae1dSRodney W. Grimes }; 617d2d3e875SBruce Evans #endif 618df8bae1dSRodney W. Grimes /* ARGSUSED */ 61926f9a767SRodney W. Grimes int 620cb226aaaSPoul-Henning Kamp setgroups(p, uap) 621df8bae1dSRodney W. Grimes struct proc *p; 622df8bae1dSRodney W. Grimes struct setgroups_args *uap; 623df8bae1dSRodney W. Grimes { 624df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 625df8bae1dSRodney W. Grimes register u_int ngrp; 626df8bae1dSRodney W. Grimes int error; 627df8bae1dSRodney W. Grimes 62875c13541SPoul-Henning Kamp if ((error = suser_xxx(0, p, PRISON_ROOT))) 629df8bae1dSRodney W. Grimes return (error); 6303956a170SDavid Greenman ngrp = uap->gidsetsize; 6318a5d815aSPeter Wemm if (ngrp > NGROUPS) 632df8bae1dSRodney W. Grimes return (EINVAL); 6338a5d815aSPeter Wemm /* 6348a5d815aSPeter Wemm * XXX A little bit lazy here. We could test if anything has 6358a5d815aSPeter Wemm * changed before crcopy() and setting P_SUGID. 6368a5d815aSPeter Wemm */ 637df8bae1dSRodney W. Grimes pc->pc_ucred = crcopy(pc->pc_ucred); 6388a5d815aSPeter Wemm if (ngrp < 1) { 6398a5d815aSPeter Wemm /* 6408a5d815aSPeter Wemm * setgroups(0, NULL) is a legitimate way of clearing the 6418a5d815aSPeter Wemm * groups vector on non-BSD systems (which generally do not 6428a5d815aSPeter Wemm * have the egid in the groups[0]). We risk security holes 6438a5d815aSPeter Wemm * when running non-BSD software if we do not do the same. 6448a5d815aSPeter Wemm */ 6458a5d815aSPeter Wemm pc->pc_ucred->cr_ngroups = 1; 6468a5d815aSPeter Wemm } else { 647bb56ec4aSPoul-Henning Kamp if ((error = copyin((caddr_t)uap->gidset, 648bb56ec4aSPoul-Henning Kamp (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))) 649df8bae1dSRodney W. Grimes return (error); 650df8bae1dSRodney W. Grimes pc->pc_ucred->cr_ngroups = ngrp; 6518a5d815aSPeter Wemm } 652d5f81602SSean Eric Fagan setsugid(p); 653df8bae1dSRodney W. Grimes return (0); 654df8bae1dSRodney W. Grimes } 655df8bae1dSRodney W. Grimes 656d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 657df8bae1dSRodney W. Grimes struct setreuid_args { 65800999cd6SAndrey A. Chernov uid_t ruid; 65900999cd6SAndrey A. Chernov uid_t euid; 660df8bae1dSRodney W. Grimes }; 661d2d3e875SBruce Evans #endif 662df8bae1dSRodney W. Grimes /* ARGSUSED */ 66326f9a767SRodney W. Grimes int 664cb226aaaSPoul-Henning Kamp setreuid(p, uap) 665df8bae1dSRodney W. Grimes register struct proc *p; 666df8bae1dSRodney W. Grimes struct setreuid_args *uap; 667df8bae1dSRodney W. Grimes { 668df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 66900999cd6SAndrey A. Chernov register uid_t ruid, euid; 670611d721eSAndrey A. Chernov int error; 671df8bae1dSRodney W. Grimes 67200999cd6SAndrey A. Chernov ruid = uap->ruid; 67300999cd6SAndrey A. Chernov euid = uap->euid; 6748aef1712SMatthew Dillon if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || 6758aef1712SMatthew Dillon (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && 6768aef1712SMatthew Dillon euid != pc->p_ruid && euid != pc->p_svuid)) && 67775c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 678611d721eSAndrey A. Chernov return (error); 67900999cd6SAndrey A. Chernov 680a89a5370SPeter Wemm if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 681f535380cSDon Lewis change_euid(p, euid); 682d5f81602SSean Eric Fagan setsugid(p); 683a89a5370SPeter Wemm } 684a89a5370SPeter Wemm if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 685f535380cSDon Lewis change_ruid(p, ruid); 686d5f81602SSean Eric Fagan setsugid(p); 68700999cd6SAndrey A. Chernov } 688b79c6a86SPeter Wemm if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) && 689b79c6a86SPeter Wemm pc->p_svuid != pc->pc_ucred->cr_uid) { 6904bc8f31fSAndrey A. Chernov pc->p_svuid = pc->pc_ucred->cr_uid; 691d5f81602SSean Eric Fagan setsugid(p); 692a89a5370SPeter Wemm } 693611d721eSAndrey A. Chernov return (0); 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes 696d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 697df8bae1dSRodney W. Grimes struct setregid_args { 69800999cd6SAndrey A. Chernov gid_t rgid; 69900999cd6SAndrey A. Chernov gid_t egid; 700df8bae1dSRodney W. Grimes }; 701d2d3e875SBruce Evans #endif 702df8bae1dSRodney W. Grimes /* ARGSUSED */ 70326f9a767SRodney W. Grimes int 704cb226aaaSPoul-Henning Kamp setregid(p, uap) 705df8bae1dSRodney W. Grimes register struct proc *p; 706df8bae1dSRodney W. Grimes struct setregid_args *uap; 707df8bae1dSRodney W. Grimes { 708df8bae1dSRodney W. Grimes register struct pcred *pc = p->p_cred; 70900999cd6SAndrey A. Chernov register gid_t rgid, egid; 710611d721eSAndrey A. Chernov int error; 711df8bae1dSRodney W. Grimes 71200999cd6SAndrey A. Chernov rgid = uap->rgid; 71300999cd6SAndrey A. Chernov egid = uap->egid; 7148aef1712SMatthew Dillon if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || 7158aef1712SMatthew Dillon (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && 7168aef1712SMatthew Dillon egid != pc->p_rgid && egid != pc->p_svgid)) && 71775c13541SPoul-Henning Kamp (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 718611d721eSAndrey A. Chernov return (error); 71900999cd6SAndrey A. Chernov 720a89a5370SPeter Wemm if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 72100999cd6SAndrey A. Chernov pc->pc_ucred = crcopy(pc->pc_ucred); 72200999cd6SAndrey A. Chernov pc->pc_ucred->cr_groups[0] = egid; 723d5f81602SSean Eric Fagan setsugid(p); 724a89a5370SPeter Wemm } 725a89a5370SPeter Wemm if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 72600999cd6SAndrey A. Chernov pc->p_rgid = rgid; 727d5f81602SSean Eric Fagan setsugid(p); 728a89a5370SPeter Wemm } 729b79c6a86SPeter Wemm if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) && 730b79c6a86SPeter Wemm pc->p_svgid != pc->pc_ucred->cr_groups[0]) { 7314bc8f31fSAndrey A. Chernov pc->p_svgid = pc->pc_ucred->cr_groups[0]; 732d5f81602SSean Eric Fagan setsugid(p); 733a89a5370SPeter Wemm } 734611d721eSAndrey A. Chernov return (0); 735df8bae1dSRodney W. Grimes } 736df8bae1dSRodney W. Grimes 7378ccd6334SPeter Wemm /* 7388ccd6334SPeter Wemm * setresuid(ruid, euid, suid) is like setreuid except control over the 7398ccd6334SPeter Wemm * saved uid is explicit. 7408ccd6334SPeter Wemm */ 7418ccd6334SPeter Wemm 7428ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 7438ccd6334SPeter Wemm struct setresuid_args { 7448ccd6334SPeter Wemm uid_t ruid; 7458ccd6334SPeter Wemm uid_t euid; 7468ccd6334SPeter Wemm uid_t suid; 7478ccd6334SPeter Wemm }; 7488ccd6334SPeter Wemm #endif 7498ccd6334SPeter Wemm /* ARGSUSED */ 7508ccd6334SPeter Wemm int 7518ccd6334SPeter Wemm setresuid(p, uap) 7528ccd6334SPeter Wemm register struct proc *p; 7538ccd6334SPeter Wemm struct setresuid_args *uap; 7548ccd6334SPeter Wemm { 7558ccd6334SPeter Wemm register struct pcred *pc = p->p_cred; 7568ccd6334SPeter Wemm register uid_t ruid, euid, suid; 7578ccd6334SPeter Wemm int error; 7588ccd6334SPeter Wemm 7598ccd6334SPeter Wemm ruid = uap->ruid; 7608ccd6334SPeter Wemm euid = uap->euid; 7618ccd6334SPeter Wemm suid = uap->suid; 7628ccd6334SPeter Wemm if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid && 7638ccd6334SPeter Wemm ruid != pc->pc_ucred->cr_uid) || 7648ccd6334SPeter Wemm (euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid && 7658ccd6334SPeter Wemm euid != pc->pc_ucred->cr_uid) || 7668ccd6334SPeter Wemm (suid != (uid_t)-1 && suid != pc->p_ruid && suid != pc->p_svuid && 7678ccd6334SPeter Wemm suid != pc->pc_ucred->cr_uid)) && 7688ccd6334SPeter Wemm (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 7698ccd6334SPeter Wemm return (error); 7708ccd6334SPeter Wemm if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { 771f535380cSDon Lewis change_euid(p, euid); 7728ccd6334SPeter Wemm setsugid(p); 7738ccd6334SPeter Wemm } 7748ccd6334SPeter Wemm if (ruid != (uid_t)-1 && pc->p_ruid != ruid) { 775f535380cSDon Lewis change_ruid(p, ruid); 7768ccd6334SPeter Wemm setsugid(p); 7778ccd6334SPeter Wemm } 7788ccd6334SPeter Wemm if (suid != (uid_t)-1 && pc->p_svuid != suid) { 7798ccd6334SPeter Wemm pc->p_svuid = suid; 7808ccd6334SPeter Wemm setsugid(p); 7818ccd6334SPeter Wemm } 7828ccd6334SPeter Wemm return (0); 7838ccd6334SPeter Wemm } 7848ccd6334SPeter Wemm 7858ccd6334SPeter Wemm /* 7868ccd6334SPeter Wemm * setresgid(rgid, egid, sgid) is like setregid except control over the 7878ccd6334SPeter Wemm * saved gid is explicit. 7888ccd6334SPeter Wemm */ 7898ccd6334SPeter Wemm 7908ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 7918ccd6334SPeter Wemm struct setresgid_args { 7928ccd6334SPeter Wemm gid_t rgid; 7938ccd6334SPeter Wemm gid_t egid; 7948ccd6334SPeter Wemm gid_t sgid; 7958ccd6334SPeter Wemm }; 7968ccd6334SPeter Wemm #endif 7978ccd6334SPeter Wemm /* ARGSUSED */ 7988ccd6334SPeter Wemm int 7998ccd6334SPeter Wemm setresgid(p, uap) 8008ccd6334SPeter Wemm register struct proc *p; 8018ccd6334SPeter Wemm struct setresgid_args *uap; 8028ccd6334SPeter Wemm { 8038ccd6334SPeter Wemm register struct pcred *pc = p->p_cred; 8048ccd6334SPeter Wemm register gid_t rgid, egid, sgid; 8058ccd6334SPeter Wemm int error; 8068ccd6334SPeter Wemm 8078ccd6334SPeter Wemm rgid = uap->rgid; 8088ccd6334SPeter Wemm egid = uap->egid; 8098ccd6334SPeter Wemm sgid = uap->sgid; 8108ccd6334SPeter Wemm if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid && 8118ccd6334SPeter Wemm rgid != pc->pc_ucred->cr_groups[0]) || 8128ccd6334SPeter Wemm (egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid && 8138ccd6334SPeter Wemm egid != pc->pc_ucred->cr_groups[0]) || 8148ccd6334SPeter Wemm (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && 8158ccd6334SPeter Wemm sgid != pc->pc_ucred->cr_groups[0])) && 8168ccd6334SPeter Wemm (error = suser_xxx(0, p, PRISON_ROOT)) != 0) 8178ccd6334SPeter Wemm return (error); 8188ccd6334SPeter Wemm 8198ccd6334SPeter Wemm if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { 8208ccd6334SPeter Wemm pc->pc_ucred = crcopy(pc->pc_ucred); 8218ccd6334SPeter Wemm pc->pc_ucred->cr_groups[0] = egid; 8228ccd6334SPeter Wemm setsugid(p); 8238ccd6334SPeter Wemm } 8248ccd6334SPeter Wemm if (rgid != (gid_t)-1 && pc->p_rgid != rgid) { 8258ccd6334SPeter Wemm pc->p_rgid = rgid; 8268ccd6334SPeter Wemm setsugid(p); 8278ccd6334SPeter Wemm } 8288ccd6334SPeter Wemm if (sgid != (gid_t)-1 && pc->p_svgid != sgid) { 8298ccd6334SPeter Wemm pc->p_svgid = sgid; 8308ccd6334SPeter Wemm setsugid(p); 8318ccd6334SPeter Wemm } 8328ccd6334SPeter Wemm return (0); 8338ccd6334SPeter Wemm } 8348ccd6334SPeter Wemm 8358ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 8368ccd6334SPeter Wemm struct getresuid_args { 8378ccd6334SPeter Wemm uid_t *ruid; 8388ccd6334SPeter Wemm uid_t *euid; 8398ccd6334SPeter Wemm uid_t *suid; 8408ccd6334SPeter Wemm }; 8418ccd6334SPeter Wemm #endif 8428ccd6334SPeter Wemm /* ARGSUSED */ 8438ccd6334SPeter Wemm int 8448ccd6334SPeter Wemm getresuid(p, uap) 8458ccd6334SPeter Wemm register struct proc *p; 8468ccd6334SPeter Wemm struct getresuid_args *uap; 8478ccd6334SPeter Wemm { 8488ccd6334SPeter Wemm struct pcred *pc = p->p_cred; 8498ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 8508ccd6334SPeter Wemm 8518ccd6334SPeter Wemm if (uap->ruid) 8528ccd6334SPeter Wemm error1 = copyout((caddr_t)&pc->p_ruid, 8538ccd6334SPeter Wemm (caddr_t)uap->ruid, sizeof(pc->p_ruid)); 8548ccd6334SPeter Wemm if (uap->euid) 8558ccd6334SPeter Wemm error2 = copyout((caddr_t)&pc->pc_ucred->cr_uid, 8568ccd6334SPeter Wemm (caddr_t)uap->euid, sizeof(pc->pc_ucred->cr_uid)); 8578ccd6334SPeter Wemm if (uap->suid) 8588ccd6334SPeter Wemm error3 = copyout((caddr_t)&pc->p_svuid, 8598ccd6334SPeter Wemm (caddr_t)uap->suid, sizeof(pc->p_svuid)); 8608ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 8618ccd6334SPeter Wemm } 8628ccd6334SPeter Wemm 8638ccd6334SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 8648ccd6334SPeter Wemm struct getresgid_args { 8658ccd6334SPeter Wemm gid_t *rgid; 8668ccd6334SPeter Wemm gid_t *egid; 8678ccd6334SPeter Wemm gid_t *sgid; 8688ccd6334SPeter Wemm }; 8698ccd6334SPeter Wemm #endif 8708ccd6334SPeter Wemm /* ARGSUSED */ 8718ccd6334SPeter Wemm int 8728ccd6334SPeter Wemm getresgid(p, uap) 8738ccd6334SPeter Wemm register struct proc *p; 8748ccd6334SPeter Wemm struct getresgid_args *uap; 8758ccd6334SPeter Wemm { 8768ccd6334SPeter Wemm struct pcred *pc = p->p_cred; 8778ccd6334SPeter Wemm int error1 = 0, error2 = 0, error3 = 0; 8788ccd6334SPeter Wemm 8798ccd6334SPeter Wemm if (uap->rgid) 8808ccd6334SPeter Wemm error1 = copyout((caddr_t)&pc->p_rgid, 8818ccd6334SPeter Wemm (caddr_t)uap->rgid, sizeof(pc->p_rgid)); 8828ccd6334SPeter Wemm if (uap->egid) 8838ccd6334SPeter Wemm error2 = copyout((caddr_t)&pc->pc_ucred->cr_groups[0], 8848ccd6334SPeter Wemm (caddr_t)uap->egid, sizeof(pc->pc_ucred->cr_groups[0])); 8858ccd6334SPeter Wemm if (uap->sgid) 8868ccd6334SPeter Wemm error3 = copyout((caddr_t)&pc->p_svgid, 8878ccd6334SPeter Wemm (caddr_t)uap->sgid, sizeof(pc->p_svgid)); 8888ccd6334SPeter Wemm return error1 ? error1 : (error2 ? error2 : error3); 8898ccd6334SPeter Wemm } 8908ccd6334SPeter Wemm 8918ccd6334SPeter Wemm 892b67cbc65SPeter Wemm #ifndef _SYS_SYSPROTO_H_ 893b67cbc65SPeter Wemm struct issetugid_args { 894b67cbc65SPeter Wemm int dummy; 895b67cbc65SPeter Wemm }; 896b67cbc65SPeter Wemm #endif 897b67cbc65SPeter Wemm /* ARGSUSED */ 898b67cbc65SPeter Wemm int 899cb226aaaSPoul-Henning Kamp issetugid(p, uap) 900b67cbc65SPeter Wemm register struct proc *p; 901b67cbc65SPeter Wemm struct issetugid_args *uap; 902b67cbc65SPeter Wemm { 903b67cbc65SPeter Wemm /* 904b67cbc65SPeter Wemm * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 905b67cbc65SPeter Wemm * we use P_SUGID because we consider changing the owners as 906b67cbc65SPeter Wemm * "tainting" as well. 907b67cbc65SPeter Wemm * This is significant for procs that start as root and "become" 908b67cbc65SPeter Wemm * a user without an exec - programs cannot know *everything* 909b67cbc65SPeter Wemm * that libc *might* have put in their data segment. 910b67cbc65SPeter Wemm */ 9110e59fec6SPeter Wemm p->p_retval[0] = (p->p_flag & P_SUGID) ? 1 : 0; 912b67cbc65SPeter Wemm return (0); 913b67cbc65SPeter Wemm } 914b67cbc65SPeter Wemm 915130d0157SRobert Watson int 916130d0157SRobert Watson __setugid(p, uap) 917130d0157SRobert Watson struct proc *p; 918130d0157SRobert Watson struct __setugid_args *uap; 919130d0157SRobert Watson { 920130d0157SRobert Watson 921130d0157SRobert Watson #ifdef REGRESSION 922130d0157SRobert Watson switch (uap->flag) { 923130d0157SRobert Watson case 0: 924130d0157SRobert Watson p->p_flag &= ~P_SUGID; 925130d0157SRobert Watson return (0); 926130d0157SRobert Watson case 1: 927130d0157SRobert Watson p->p_flag |= P_SUGID; 928130d0157SRobert Watson return (0); 929130d0157SRobert Watson default: 930130d0157SRobert Watson return (EINVAL); 931130d0157SRobert Watson } 932130d0157SRobert Watson #else /* !REGRESSION */ 933130d0157SRobert Watson return (ENOSYS); 934130d0157SRobert Watson #endif /* !REGRESSION */ 935130d0157SRobert Watson } 936130d0157SRobert Watson 937df8bae1dSRodney W. Grimes /* 938df8bae1dSRodney W. Grimes * Check if gid is a member of the group set. 939df8bae1dSRodney W. Grimes */ 94026f9a767SRodney W. Grimes int 941df8bae1dSRodney W. Grimes groupmember(gid, cred) 942df8bae1dSRodney W. Grimes gid_t gid; 943df8bae1dSRodney W. Grimes register struct ucred *cred; 944df8bae1dSRodney W. Grimes { 945df8bae1dSRodney W. Grimes register gid_t *gp; 946df8bae1dSRodney W. Grimes gid_t *egp; 947df8bae1dSRodney W. Grimes 948df8bae1dSRodney W. Grimes egp = &(cred->cr_groups[cred->cr_ngroups]); 949df8bae1dSRodney W. Grimes for (gp = cred->cr_groups; gp < egp; gp++) 950df8bae1dSRodney W. Grimes if (*gp == gid) 951df8bae1dSRodney W. Grimes return (1); 952df8bae1dSRodney W. Grimes return (0); 953df8bae1dSRodney W. Grimes } 954df8bae1dSRodney W. Grimes 955579f4eb4SRobert Watson static int suser_permitted = 1; 956579f4eb4SRobert Watson 957579f4eb4SRobert Watson SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, 958579f4eb4SRobert Watson "processes with uid 0 have privilege"); 959579f4eb4SRobert Watson 960df8bae1dSRodney W. Grimes /* 961df8bae1dSRodney W. Grimes * Test whether the specified credentials imply "super-user" 962df8bae1dSRodney W. Grimes * privilege; if so, and we have accounting info, set the flag 963df8bae1dSRodney W. Grimes * indicating use of super-powers. 964df8bae1dSRodney W. Grimes * Returns 0 or error. 965df8bae1dSRodney W. Grimes */ 96626f9a767SRodney W. Grimes int 967f711d546SPoul-Henning Kamp suser(p) 96891421ba2SRobert Watson struct proc *p; 969f711d546SPoul-Henning Kamp { 97075c13541SPoul-Henning Kamp return suser_xxx(0, p, 0); 971f711d546SPoul-Henning Kamp } 972f711d546SPoul-Henning Kamp 973f711d546SPoul-Henning Kamp int 97475c13541SPoul-Henning Kamp suser_xxx(cred, proc, flag) 97591421ba2SRobert Watson struct ucred *cred; 97691421ba2SRobert Watson struct proc *proc; 97775c13541SPoul-Henning Kamp int flag; 978df8bae1dSRodney W. Grimes { 97903095547SRobert Watson if (!suser_permitted) 98003095547SRobert Watson return (EPERM); 98175c13541SPoul-Henning Kamp if (!cred && !proc) { 98275c13541SPoul-Henning Kamp printf("suser_xxx(): THINK!\n"); 983df8bae1dSRodney W. Grimes return (EPERM); 984df8bae1dSRodney W. Grimes } 98575c13541SPoul-Henning Kamp if (!cred) 98675c13541SPoul-Henning Kamp cred = proc->p_ucred; 98775c13541SPoul-Henning Kamp if (cred->cr_uid != 0) 98875c13541SPoul-Henning Kamp return (EPERM); 98991421ba2SRobert Watson if (jailed(cred) && !(flag & PRISON_ROOT)) 99075c13541SPoul-Henning Kamp return (EPERM); 99175c13541SPoul-Henning Kamp return (0); 99275c13541SPoul-Henning Kamp } 993df8bae1dSRodney W. Grimes 994ed639720SRobert Watson /* 995ed639720SRobert Watson * u_cansee(u1, u2): determine if u1 "can see" the subject specified by u2 996ed639720SRobert Watson * Arguments: imutable credentials u1, u2 997ed639720SRobert Watson * Returns: 0 for permitted, an errno value otherwise 998ed639720SRobert Watson * Locks: none 999ed639720SRobert Watson * References: u1 and u2 must be valid for the lifetime of the call 1000ed639720SRobert Watson * u1 may equal u2, in which case only one reference is required 1001ed639720SRobert Watson */ 1002ed639720SRobert Watson int 1003ed639720SRobert Watson u_cansee(struct ucred *u1, struct ucred *u2) 1004a9e0361bSPoul-Henning Kamp { 100591421ba2SRobert Watson int error; 1006a9e0361bSPoul-Henning Kamp 1007ed639720SRobert Watson if ((error = prison_check(u1, u2))) 100891421ba2SRobert Watson return (error); 1009ed639720SRobert Watson if (!ps_showallprocs && u1->cr_uid != u2->cr_uid) { 1010f8e6ab29SRobert Watson if (suser_xxx(u1, NULL, PRISON_ROOT) != 0) 1011387d2c03SRobert Watson return (ESRCH); 1012c52396e3SRobert Watson } 1013387d2c03SRobert Watson return (0); 1014387d2c03SRobert Watson } 1015387d2c03SRobert Watson 1016387d2c03SRobert Watson static int 1017ed639720SRobert Watson p_cansee(struct proc *p1, struct proc *p2, int *privused) 1018ed639720SRobert Watson { 1019ed639720SRobert Watson 1020ed639720SRobert Watson /* XXX: privused is going away, so don't do that here. */ 1021ed639720SRobert Watson if (privused != NULL) 1022ed639720SRobert Watson *privused = 0; 1023ed639720SRobert Watson /* Wrap u_cansee() for all functionality. */ 1024ed639720SRobert Watson return (u_cansee(p1->p_ucred, p2->p_ucred)); 1025ed639720SRobert Watson } 1026ed639720SRobert Watson 1027ed639720SRobert Watson static int 102891421ba2SRobert Watson p_cankill(struct proc *p1, struct proc *p2, int *privused) 1029387d2c03SRobert Watson { 103091421ba2SRobert Watson int error; 1031387d2c03SRobert Watson 1032387d2c03SRobert Watson if (privused != NULL) 1033387d2c03SRobert Watson *privused = 0; 1034387d2c03SRobert Watson 1035a9e0361bSPoul-Henning Kamp if (p1 == p2) 1036a9e0361bSPoul-Henning Kamp return (0); 1037387d2c03SRobert Watson 103891421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 103991421ba2SRobert Watson return (error); 1040387d2c03SRobert Watson 1041a9e0361bSPoul-Henning Kamp if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 1042a9e0361bSPoul-Henning Kamp return (0); 1043a9e0361bSPoul-Henning Kamp if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 1044a9e0361bSPoul-Henning Kamp return (0); 1045387d2c03SRobert Watson /* 1046387d2c03SRobert Watson * XXX should a process be able to affect another process 1047387d2c03SRobert Watson * acting as the same uid (i.e., a userland nfsd or the like?) 1048387d2c03SRobert Watson */ 1049a9e0361bSPoul-Henning Kamp if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 1050a9e0361bSPoul-Henning Kamp return (0); 1051a9e0361bSPoul-Henning Kamp if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 1052a9e0361bSPoul-Henning Kamp return (0); 1053387d2c03SRobert Watson 1054387d2c03SRobert Watson if (!suser_xxx(0, p1, PRISON_ROOT)) { 1055387d2c03SRobert Watson if (privused != NULL) 1056387d2c03SRobert Watson *privused = 1; 1057a9e0361bSPoul-Henning Kamp return (0); 1058387d2c03SRobert Watson } 1059387d2c03SRobert Watson 1060387d2c03SRobert Watson #ifdef CAPABILITIES 1061387d2c03SRobert Watson if (!cap_check_xxx(0, p1, CAP_KILL, PRISON_ROOT)) { 1062387d2c03SRobert Watson if (privused != NULL) 1063387d2c03SRobert Watson *privused = 1; 1064387d2c03SRobert Watson return (0); 1065387d2c03SRobert Watson } 1066387d2c03SRobert Watson #endif 1067387d2c03SRobert Watson 1068a9e0361bSPoul-Henning Kamp return (EPERM); 1069a9e0361bSPoul-Henning Kamp } 1070a9e0361bSPoul-Henning Kamp 1071387d2c03SRobert Watson static int 107291421ba2SRobert Watson p_cansched(struct proc *p1, struct proc *p2, int *privused) 1073387d2c03SRobert Watson { 107491421ba2SRobert Watson int error; 1075387d2c03SRobert Watson 1076387d2c03SRobert Watson if (privused != NULL) 1077387d2c03SRobert Watson *privused = 0; 1078387d2c03SRobert Watson 1079387d2c03SRobert Watson if (p1 == p2) 1080387d2c03SRobert Watson return (0); 1081387d2c03SRobert Watson 108291421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 108391421ba2SRobert Watson return (error); 1084387d2c03SRobert Watson 1085387d2c03SRobert Watson if (p1->p_cred->p_ruid == p2->p_cred->p_ruid) 1086387d2c03SRobert Watson return (0); 1087387d2c03SRobert Watson if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid) 1088387d2c03SRobert Watson return (0); 1089387d2c03SRobert Watson /* 1090387d2c03SRobert Watson * XXX should a process be able to affect another process 1091387d2c03SRobert Watson * acting as the same uid (i.e., a userland nfsd or the like?) 1092387d2c03SRobert Watson */ 1093387d2c03SRobert Watson if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid) 1094387d2c03SRobert Watson return (0); 1095387d2c03SRobert Watson if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid) 1096387d2c03SRobert Watson return (0); 1097387d2c03SRobert Watson 1098387d2c03SRobert Watson if (!suser_xxx(0, p1, PRISON_ROOT)) { 1099387d2c03SRobert Watson if (privused != NULL) 1100387d2c03SRobert Watson *privused = 1; 1101387d2c03SRobert Watson return (0); 1102387d2c03SRobert Watson } 1103387d2c03SRobert Watson 1104387d2c03SRobert Watson #ifdef CAPABILITIES 1105387d2c03SRobert Watson if (!cap_check_xxx(0, p1, CAP_SYS_NICE, PRISON_ROOT)) { 1106387d2c03SRobert Watson if (privused != NULL) 1107387d2c03SRobert Watson *privused = 1; 1108387d2c03SRobert Watson return (0); 1109387d2c03SRobert Watson } 1110387d2c03SRobert Watson #endif 1111387d2c03SRobert Watson 1112387d2c03SRobert Watson return (EPERM); 1113387d2c03SRobert Watson } 1114387d2c03SRobert Watson 1115387d2c03SRobert Watson static int 111691421ba2SRobert Watson p_candebug(struct proc *p1, struct proc *p2, int *privused) 1117387d2c03SRobert Watson { 1118387d2c03SRobert Watson int error; 1119387d2c03SRobert Watson 1120387d2c03SRobert Watson if (privused != NULL) 1121387d2c03SRobert Watson *privused = 0; 1122387d2c03SRobert Watson 1123387d2c03SRobert Watson /* XXX it is authorized, but semantics don't permit it */ 1124387d2c03SRobert Watson if (p1 == p2) 1125387d2c03SRobert Watson return (0); 1126387d2c03SRobert Watson 112791421ba2SRobert Watson if ((error = prison_check(p1->p_ucred, p2->p_ucred))) 112891421ba2SRobert Watson return (error); 1129387d2c03SRobert Watson 1130387d2c03SRobert Watson /* not owned by you, has done setuid (unless you're root) */ 1131387d2c03SRobert Watson /* add a CAP_SYS_PTRACE here? */ 1132c087a04fSRobert Watson if (p1->p_cred->pc_ucred->cr_uid != p2->p_cred->p_ruid || 1133c087a04fSRobert Watson p1->p_cred->p_ruid != p2->p_cred->p_ruid || 11347f73938eSRobert Watson p1->p_cred->p_svuid != p2->p_cred->p_ruid || 1135c087a04fSRobert Watson p2->p_flag & P_SUGID) { 1136387d2c03SRobert Watson if ((error = suser_xxx(0, p1, PRISON_ROOT))) 1137387d2c03SRobert Watson return (error); 1138387d2c03SRobert Watson if (privused != NULL) 1139387d2c03SRobert Watson *privused = 1; 1140387d2c03SRobert Watson } 1141387d2c03SRobert Watson 1142387d2c03SRobert Watson /* can't trace init when securelevel > 0 */ 1143387d2c03SRobert Watson if (securelevel > 0 && p2->p_pid == 1) 1144387d2c03SRobert Watson return (EPERM); 1145387d2c03SRobert Watson 1146387d2c03SRobert Watson return (0); 1147387d2c03SRobert Watson } 1148387d2c03SRobert Watson 1149387d2c03SRobert Watson int 115091421ba2SRobert Watson p_can(struct proc *p1, struct proc *p2, int operation, 1151387d2c03SRobert Watson int *privused) 1152387d2c03SRobert Watson { 1153387d2c03SRobert Watson 1154387d2c03SRobert Watson switch(operation) { 1155387d2c03SRobert Watson case P_CAN_SEE: 1156387d2c03SRobert Watson return (p_cansee(p1, p2, privused)); 1157387d2c03SRobert Watson 1158387d2c03SRobert Watson case P_CAN_KILL: 1159387d2c03SRobert Watson return (p_cankill(p1, p2, privused)); 1160387d2c03SRobert Watson 1161387d2c03SRobert Watson case P_CAN_SCHED: 1162387d2c03SRobert Watson return (p_cansched(p1, p2, privused)); 1163387d2c03SRobert Watson 1164387d2c03SRobert Watson case P_CAN_DEBUG: 1165387d2c03SRobert Watson return (p_candebug(p1, p2, privused)); 1166387d2c03SRobert Watson 1167387d2c03SRobert Watson default: 1168387d2c03SRobert Watson panic("p_can: invalid operation"); 1169387d2c03SRobert Watson } 1170387d2c03SRobert Watson } 1171387d2c03SRobert Watson 1172387d2c03SRobert Watson 1173a9e0361bSPoul-Henning Kamp /* 1174df8bae1dSRodney W. Grimes * Allocate a zeroed cred structure. 1175df8bae1dSRodney W. Grimes */ 1176df8bae1dSRodney W. Grimes struct ucred * 1177df8bae1dSRodney W. Grimes crget() 1178df8bae1dSRodney W. Grimes { 1179df8bae1dSRodney W. Grimes register struct ucred *cr; 1180df8bae1dSRodney W. Grimes 11811e5d626aSAlfred Perlstein MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK|M_ZERO); 1182df8bae1dSRodney W. Grimes cr->cr_ref = 1; 11831e5d626aSAlfred Perlstein mtx_init(&cr->cr_mtx, "ucred", MTX_DEF); 1184df8bae1dSRodney W. Grimes return (cr); 1185df8bae1dSRodney W. Grimes } 1186df8bae1dSRodney W. Grimes 1187df8bae1dSRodney W. Grimes /* 1188661702abSRobert Watson * Claim another reference to a ucred structure 11895c3f70d7SAlfred Perlstein */ 11905c3f70d7SAlfred Perlstein void 11915c3f70d7SAlfred Perlstein crhold(cr) 11925c3f70d7SAlfred Perlstein struct ucred *cr; 11935c3f70d7SAlfred Perlstein { 11945c3f70d7SAlfred Perlstein 11959ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 11965c3f70d7SAlfred Perlstein cr->cr_ref++; 11979ed346baSBosko Milekic mtx_unlock(&(cr)->cr_mtx); 11985c3f70d7SAlfred Perlstein } 11995c3f70d7SAlfred Perlstein 12005c3f70d7SAlfred Perlstein 12015c3f70d7SAlfred Perlstein /* 1202df8bae1dSRodney W. Grimes * Free a cred structure. 1203df8bae1dSRodney W. Grimes * Throws away space when ref count gets to 0. 1204df8bae1dSRodney W. Grimes */ 120526f9a767SRodney W. Grimes void 1206df8bae1dSRodney W. Grimes crfree(cr) 1207df8bae1dSRodney W. Grimes struct ucred *cr; 1208df8bae1dSRodney W. Grimes { 12091e5d626aSAlfred Perlstein 12109ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 1211f535380cSDon Lewis if (--cr->cr_ref == 0) { 12121e5d626aSAlfred Perlstein mtx_destroy(&cr->cr_mtx); 1213f535380cSDon Lewis /* 1214f535380cSDon Lewis * Some callers of crget(), such as nfs_statfs(), 1215f535380cSDon Lewis * allocate a temporary credential, but don't 1216f535380cSDon Lewis * allocate a uidinfo structure. 1217f535380cSDon Lewis */ 1218f535380cSDon Lewis if (cr->cr_uidinfo != NULL) 1219f535380cSDon Lewis uifree(cr->cr_uidinfo); 122091421ba2SRobert Watson /* 122191421ba2SRobert Watson * Free a prison, if any. 122291421ba2SRobert Watson */ 122391421ba2SRobert Watson if (jailed(cr)) 122491421ba2SRobert Watson prison_free(cr->cr_prison); 1225df8bae1dSRodney W. Grimes FREE((caddr_t)cr, M_CRED); 12261e5d626aSAlfred Perlstein } else { 12279ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1228df8bae1dSRodney W. Grimes } 1229f535380cSDon Lewis } 1230df8bae1dSRodney W. Grimes 1231df8bae1dSRodney W. Grimes /* 1232df8bae1dSRodney W. Grimes * Copy cred structure to a new one and free the old one. 1233df8bae1dSRodney W. Grimes */ 1234df8bae1dSRodney W. Grimes struct ucred * 1235df8bae1dSRodney W. Grimes crcopy(cr) 1236df8bae1dSRodney W. Grimes struct ucred *cr; 1237df8bae1dSRodney W. Grimes { 1238df8bae1dSRodney W. Grimes struct ucred *newcr; 1239df8bae1dSRodney W. Grimes 12409ed346baSBosko Milekic mtx_lock(&cr->cr_mtx); 12411e5d626aSAlfred Perlstein if (cr->cr_ref == 1) { 12429ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 1243df8bae1dSRodney W. Grimes return (cr); 12441e5d626aSAlfred Perlstein } 12459ed346baSBosko Milekic mtx_unlock(&cr->cr_mtx); 12461e5d626aSAlfred Perlstein newcr = crdup(cr); 1247df8bae1dSRodney W. Grimes crfree(cr); 1248df8bae1dSRodney W. Grimes return (newcr); 1249df8bae1dSRodney W. Grimes } 1250df8bae1dSRodney W. Grimes 1251df8bae1dSRodney W. Grimes /* 1252df8bae1dSRodney W. Grimes * Dup cred struct to a new held one. 1253df8bae1dSRodney W. Grimes */ 1254df8bae1dSRodney W. Grimes struct ucred * 1255df8bae1dSRodney W. Grimes crdup(cr) 1256df8bae1dSRodney W. Grimes struct ucred *cr; 1257df8bae1dSRodney W. Grimes { 1258df8bae1dSRodney W. Grimes struct ucred *newcr; 1259df8bae1dSRodney W. Grimes 12601e5d626aSAlfred Perlstein MALLOC(newcr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 1261df8bae1dSRodney W. Grimes *newcr = *cr; 12621e5d626aSAlfred Perlstein mtx_init(&newcr->cr_mtx, "ucred", MTX_DEF); 1263f535380cSDon Lewis uihold(newcr->cr_uidinfo); 126491421ba2SRobert Watson if (jailed(newcr)) 126591421ba2SRobert Watson prison_hold(newcr->cr_prison); 1266df8bae1dSRodney W. Grimes newcr->cr_ref = 1; 1267df8bae1dSRodney W. Grimes return (newcr); 1268df8bae1dSRodney W. Grimes } 1269df8bae1dSRodney W. Grimes 1270df8bae1dSRodney W. Grimes /* 1271df8bae1dSRodney W. Grimes * Get login name, if available. 1272df8bae1dSRodney W. Grimes */ 1273d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1274df8bae1dSRodney W. Grimes struct getlogin_args { 1275df8bae1dSRodney W. Grimes char *namebuf; 1276df8bae1dSRodney W. Grimes u_int namelen; 1277df8bae1dSRodney W. Grimes }; 1278d2d3e875SBruce Evans #endif 1279df8bae1dSRodney W. Grimes /* ARGSUSED */ 128026f9a767SRodney W. Grimes int 1281cb226aaaSPoul-Henning Kamp getlogin(p, uap) 1282df8bae1dSRodney W. Grimes struct proc *p; 1283df8bae1dSRodney W. Grimes struct getlogin_args *uap; 1284df8bae1dSRodney W. Grimes { 1285df8bae1dSRodney W. Grimes 128630cf3ac4SAndrey A. Chernov if (uap->namelen > MAXLOGNAME) 128753490b76SAndrey A. Chernov uap->namelen = MAXLOGNAME; 1288df8bae1dSRodney W. Grimes return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 1289df8bae1dSRodney W. Grimes (caddr_t) uap->namebuf, uap->namelen)); 1290df8bae1dSRodney W. Grimes } 1291df8bae1dSRodney W. Grimes 1292df8bae1dSRodney W. Grimes /* 1293df8bae1dSRodney W. Grimes * Set login name. 1294df8bae1dSRodney W. Grimes */ 1295d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1296df8bae1dSRodney W. Grimes struct setlogin_args { 1297df8bae1dSRodney W. Grimes char *namebuf; 1298df8bae1dSRodney W. Grimes }; 1299d2d3e875SBruce Evans #endif 1300df8bae1dSRodney W. Grimes /* ARGSUSED */ 130126f9a767SRodney W. Grimes int 1302cb226aaaSPoul-Henning Kamp setlogin(p, uap) 1303df8bae1dSRodney W. Grimes struct proc *p; 1304df8bae1dSRodney W. Grimes struct setlogin_args *uap; 1305df8bae1dSRodney W. Grimes { 1306df8bae1dSRodney W. Grimes int error; 1307964ca0caSAndrey A. Chernov char logintmp[MAXLOGNAME]; 1308df8bae1dSRodney W. Grimes 130975c13541SPoul-Henning Kamp if ((error = suser_xxx(0, p, PRISON_ROOT))) 1310df8bae1dSRodney W. Grimes return (error); 1311184989c2SDavid Nugent error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, 131210d4743fSDoug Rabson sizeof(logintmp), (size_t *)0); 1313df8bae1dSRodney W. Grimes if (error == ENAMETOOLONG) 1314df8bae1dSRodney W. Grimes error = EINVAL; 1315184989c2SDavid Nugent else if (!error) 1316184989c2SDavid Nugent (void) memcpy(p->p_pgrp->pg_session->s_login, logintmp, 1317964ca0caSAndrey A. Chernov sizeof(logintmp)); 1318df8bae1dSRodney W. Grimes return (error); 1319df8bae1dSRodney W. Grimes } 1320d5f81602SSean Eric Fagan 1321d5f81602SSean Eric Fagan void 1322d5f81602SSean Eric Fagan setsugid(p) 1323d5f81602SSean Eric Fagan struct proc *p; 1324d5f81602SSean Eric Fagan { 1325d5f81602SSean Eric Fagan p->p_flag |= P_SUGID; 132689361835SSean Eric Fagan if (!(p->p_pfsflags & PF_ISUGID)) 1327d5f81602SSean Eric Fagan p->p_stops = 0; 1328d5f81602SSean Eric Fagan } 1329f535380cSDon Lewis 1330f535380cSDon Lewis /* 1331f535380cSDon Lewis * Helper function to change the effective uid of a process 1332f535380cSDon Lewis */ 1333f535380cSDon Lewis void 1334f535380cSDon Lewis change_euid(p, euid) 1335f535380cSDon Lewis struct proc *p; 1336f535380cSDon Lewis uid_t euid; 1337f535380cSDon Lewis { 1338f535380cSDon Lewis struct pcred *pc; 1339f535380cSDon Lewis struct uidinfo *uip; 1340f535380cSDon Lewis 1341f535380cSDon Lewis pc = p->p_cred; 1342f535380cSDon Lewis /* 1343f535380cSDon Lewis * crcopy is essentially a NOP if ucred has a reference count 1344f535380cSDon Lewis * of 1, which is true if it has already been copied. 1345f535380cSDon Lewis */ 1346f535380cSDon Lewis pc->pc_ucred = crcopy(pc->pc_ucred); 1347f535380cSDon Lewis uip = pc->pc_ucred->cr_uidinfo; 1348f535380cSDon Lewis pc->pc_ucred->cr_uid = euid; 1349f535380cSDon Lewis pc->pc_ucred->cr_uidinfo = uifind(euid); 1350f535380cSDon Lewis uifree(uip); 1351f535380cSDon Lewis } 1352f535380cSDon Lewis 1353f535380cSDon Lewis /* 1354f535380cSDon Lewis * Helper function to change the real uid of a process 1355f535380cSDon Lewis * 1356f535380cSDon Lewis * The per-uid process count for this process is transfered from 1357f535380cSDon Lewis * the old uid to the new uid. 1358f535380cSDon Lewis */ 1359810bfc8eSAndrew Gallatin void 1360f535380cSDon Lewis change_ruid(p, ruid) 1361f535380cSDon Lewis struct proc *p; 1362f535380cSDon Lewis uid_t ruid; 1363f535380cSDon Lewis { 1364f535380cSDon Lewis struct pcred *pc; 1365f535380cSDon Lewis struct uidinfo *uip; 1366f535380cSDon Lewis 1367f535380cSDon Lewis pc = p->p_cred; 1368f535380cSDon Lewis (void)chgproccnt(pc->p_uidinfo, -1, 0); 1369f535380cSDon Lewis uip = pc->p_uidinfo; 1370f535380cSDon Lewis /* It is assumed that pcred is not shared between processes */ 1371f535380cSDon Lewis pc->p_ruid = ruid; 1372f535380cSDon Lewis pc->p_uidinfo = uifind(ruid); 1373f535380cSDon Lewis (void)chgproccnt(pc->p_uidinfo, 1, 0); 1374f535380cSDon Lewis uifree(uip); 1375f535380cSDon Lewis } 1376