123372Smckusick /* 247540Skarels * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University 347540Skarels * of California. All rights reserved. 423372Smckusick * 544439Sbostic * %sccs.include.redist.c% 637578Smckusick * 7*54925Storek * @(#)kern_prot.c 7.25 (Berkeley) 07/10/92 823372Smckusick */ 97420Sroot 107420Sroot /* 117498Sroot * System calls related to processes and protection 127420Sroot */ 137420Sroot 1417092Sbloom #include "param.h" 1537578Smckusick #include "acct.h" 1617092Sbloom #include "systm.h" 1747540Skarels #include "ucred.h" 1817092Sbloom #include "proc.h" 1917092Sbloom #include "timeb.h" 2017092Sbloom #include "times.h" 2137578Smckusick #include "malloc.h" 227420Sroot 23*54925Storek struct args { 24*54925Storek int dummy; 25*54925Storek }; 26*54925Storek 2743393Skarels /* ARGSUSED */ 2843393Skarels getpid(p, uap, retval) 2943393Skarels struct proc *p; 30*54925Storek struct args *uap; 3143393Skarels int *retval; 3243393Skarels { 3337579Smckusick 3443393Skarels *retval = p->p_pid; 3552495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 3647540Skarels retval[1] = p->p_pptr->p_pid; 3743393Skarels #endif 3844405Skarels return (0); 3943393Skarels } 4043393Skarels 4143393Skarels /* ARGSUSED */ 4243393Skarels getppid(p, uap, retval) 4343393Skarels struct proc *p; 44*54925Storek struct args *uap; 4543393Skarels int *retval; 467498Sroot { 477498Sroot 4847540Skarels *retval = p->p_pptr->p_pid; 4944405Skarels return (0); 507498Sroot } 517498Sroot 5247540Skarels /* Get process group ID; note that POSIX getpgrp takes no parameter */ 5343393Skarels getpgrp(p, uap, retval) 5443393Skarels struct proc *p; 55*54925Storek struct args *uap; 5643393Skarels int *retval; 577498Sroot { 587498Sroot 5943393Skarels *retval = p->p_pgrp->pg_id; 6044405Skarels return (0); 617498Sroot } 627498Sroot 6343393Skarels /* ARGSUSED */ 6443393Skarels getuid(p, uap, retval) 6543393Skarels struct proc *p; 66*54925Storek struct args *uap; 6743393Skarels int *retval; 687420Sroot { 697420Sroot 7047540Skarels *retval = p->p_cred->p_ruid; 7152495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 7247540Skarels retval[1] = p->p_ucred->cr_uid; 7343393Skarels #endif 7444405Skarels return (0); 757420Sroot } 767420Sroot 7743393Skarels /* ARGSUSED */ 7843393Skarels geteuid(p, uap, retval) 7943393Skarels struct proc *p; 80*54925Storek struct args *uap; 8143393Skarels int *retval; 827498Sroot { 837498Sroot 8447540Skarels *retval = p->p_ucred->cr_uid; 8544405Skarels return (0); 867498Sroot } 877498Sroot 8843393Skarels /* ARGSUSED */ 8943393Skarels getgid(p, uap, retval) 9043393Skarels struct proc *p; 91*54925Storek struct args *uap; 9243393Skarels int *retval; 937498Sroot { 9443393Skarels 9547540Skarels *retval = p->p_cred->p_rgid; 9652495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9747540Skarels retval[1] = p->p_ucred->cr_groups[0]; 9843393Skarels #endif 9944405Skarels return (0); 10043393Skarels } 10143393Skarels 10243393Skarels /* 10345908Sbostic * Get effective group ID. The "egid" is groups[0], and could be obtained 10445908Sbostic * via getgroups. This syscall exists because it is somewhat painful to do 10545908Sbostic * correctly in a library function. 10643393Skarels */ 10743393Skarels /* ARGSUSED */ 10843393Skarels getegid(p, uap, retval) 10943393Skarels struct proc *p; 110*54925Storek struct args *uap; 11143393Skarels int *retval; 11243393Skarels { 11347540Skarels 11447540Skarels *retval = p->p_ucred->cr_groups[0]; 11544405Skarels return (0); 11643393Skarels } 11743393Skarels 118*54925Storek struct getgroups_args { 119*54925Storek u_int gidsetsize; 120*54925Storek int *gidset; /* XXX not yet POSIX */ 121*54925Storek }; 12243393Skarels getgroups(p, uap, retval) 12343393Skarels struct proc *p; 124*54925Storek register struct getgroups_args *uap; 12543393Skarels int *retval; 12643393Skarels { 12747540Skarels register struct pcred *pc = p->p_cred; 12818362Skarels register gid_t *gp; 12918362Skarels register int *lp; 13044994Skarels register u_int ngrp; 13118362Skarels int groups[NGROUPS]; 13243393Skarels int error; 1337498Sroot 13444994Skarels if ((ngrp = uap->gidsetsize) == 0) { 13547540Skarels *retval = pc->pc_ucred->cr_ngroups; 13644405Skarels return (0); 13737578Smckusick } 13847540Skarels if (ngrp < pc->pc_ucred->cr_ngroups) 13944405Skarels return (EINVAL); 14047540Skarels ngrp = pc->pc_ucred->cr_ngroups; 14147540Skarels for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; ) 14218362Skarels *lp++ = *gp++; 14343393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 14444994Skarels ngrp * sizeof (groups[0]))) 14544405Skarels return (error); 14644994Skarels *retval = ngrp; 14744405Skarels return (0); 1487498Sroot } 1497498Sroot 15043393Skarels /* ARGSUSED */ 15143393Skarels setsid(p, uap, retval) 15247540Skarels register struct proc *p; 153*54925Storek struct args *uap; 15443393Skarels int *retval; 15537579Smckusick { 15637579Smckusick 15743393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 15844405Skarels return (EPERM); 15943393Skarels } else { 16047540Skarels enterpgrp(p, p->p_pid, 1); 16143393Skarels *retval = p->p_pid; 16244405Skarels return (0); 16337579Smckusick } 16437579Smckusick } 16537579Smckusick 16637579Smckusick /* 16747540Skarels * set process group (setpgid/old setpgrp) 16837579Smckusick * 16947972Smarc * caller does setpgid(targpid, targpgid) 17040667Skarels * 17140667Skarels * pid must be caller or child of caller (ESRCH) 17240667Skarels * if a child 17340667Skarels * pid must be in same session (EPERM) 17440667Skarels * pid can't have done an exec (EACCES) 17540667Skarels * if pgid != pid 17640667Skarels * there must exist some pid in same session having pgid (EPERM) 17740667Skarels * pid must not be session leader (EPERM) 17837579Smckusick */ 179*54925Storek struct setpgid_args { 180*54925Storek int pid; /* target process id */ 181*54925Storek int pgid; /* target pgrp id */ 182*54925Storek }; 18343393Skarels /* ARGSUSED */ 18447972Smarc setpgid(curp, uap, retval) 18547972Smarc struct proc *curp; 186*54925Storek register struct setpgid_args *uap; 18743393Skarels int *retval; 18843393Skarels { 18947972Smarc register struct proc *targp; /* target process */ 19048990Skarels register struct pgrp *pgrp; /* target pgrp */ 1917498Sroot 19248990Skarels if (uap->pid != 0 && uap->pid != curp->p_pid) { 19348990Skarels if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 19444405Skarels return (ESRCH); 19547972Smarc if (targp->p_session != curp->p_session) 19644405Skarels return (EPERM); 19747972Smarc if (targp->p_flag&SEXEC) 19844405Skarels return (EACCES); 19943393Skarels } else 20047972Smarc targp = curp; 20147972Smarc if (SESS_LEADER(targp)) 20244405Skarels return (EPERM); 20348990Skarels if (uap->pgid == 0) 20448990Skarels uap->pgid = targp->p_pid; 20548990Skarels else if (uap->pgid != targp->p_pid) 20648990Skarels if ((pgrp = pgfind(uap->pgid)) == 0 || 20748990Skarels pgrp->pg_session != curp->p_session) 20845908Sbostic return (EPERM); 20948990Skarels enterpgrp(targp, uap->pgid, 0); 21044405Skarels return (0); 2117498Sroot } 2127498Sroot 213*54925Storek struct setuid_args { 214*54925Storek int uid; 215*54925Storek }; 21643393Skarels /* ARGSUSED */ 21743393Skarels setuid(p, uap, retval) 21847540Skarels struct proc *p; 219*54925Storek struct setuid_args *uap; 22043393Skarels int *retval; 2217420Sroot { 22247540Skarels register struct pcred *pc = p->p_cred; 22343393Skarels register uid_t uid; 22443393Skarels int error; 22543393Skarels 22643393Skarels uid = uap->uid; 22747540Skarels if (uid != pc->p_ruid && 22847540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 22944405Skarels return (error); 23043393Skarels /* 23145908Sbostic * Everything's okay, do it. Copy credentials so other references do 23245908Sbostic * not see our changes. 23343393Skarels */ 23447540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 23547540Skarels pc->pc_ucred->cr_uid = uid; 23647540Skarels pc->p_ruid = uid; 23747540Skarels pc->p_svuid = uid; 23854339Smckusick p->p_flag |= SUGID; 23944405Skarels return (0); 24043393Skarels } 24143393Skarels 242*54925Storek struct seteuid_args { 243*54925Storek int euid; 244*54925Storek }; 24543393Skarels /* ARGSUSED */ 24643393Skarels seteuid(p, uap, retval) 24747540Skarels struct proc *p; 248*54925Storek struct seteuid_args *uap; 24943393Skarels int *retval; 25043393Skarels { 25147540Skarels register struct pcred *pc = p->p_cred; 25243393Skarels register uid_t euid; 25343393Skarels int error; 25443393Skarels 25543393Skarels euid = uap->euid; 25647540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 25747540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 25844405Skarels return (error); 25943393Skarels /* 26045908Sbostic * Everything's okay, do it. Copy credentials so other references do 26145908Sbostic * not see our changes. 26243393Skarels */ 26347540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 26447540Skarels pc->pc_ucred->cr_uid = euid; 26554339Smckusick p->p_flag |= SUGID; 26644405Skarels return (0); 26743393Skarels } 26843393Skarels 269*54925Storek struct setgid_args { 270*54925Storek int gid; 271*54925Storek }; 27243393Skarels /* ARGSUSED */ 27343393Skarels setgid(p, uap, retval) 27443393Skarels struct proc *p; 275*54925Storek struct setgid_args *uap; 27643393Skarels int *retval; 27743393Skarels { 27847540Skarels register struct pcred *pc = p->p_cred; 27943393Skarels register gid_t gid; 28043393Skarels int error; 28143393Skarels 28243393Skarels gid = uap->gid; 28347540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 28444405Skarels return (error); 28547540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 28647540Skarels pc->pc_ucred->cr_groups[0] = gid; 28747540Skarels pc->p_rgid = gid; 28847540Skarels pc->p_svgid = gid; /* ??? */ 28954339Smckusick p->p_flag |= SUGID; 29044405Skarels return (0); 29143393Skarels } 29243393Skarels 293*54925Storek struct setegid_args { 294*54925Storek int egid; 295*54925Storek }; 29643393Skarels /* ARGSUSED */ 29743393Skarels setegid(p, uap, retval) 29843393Skarels struct proc *p; 299*54925Storek struct setegid_args *uap; 30043393Skarels int *retval; 30143393Skarels { 30247540Skarels register struct pcred *pc = p->p_cred; 30343393Skarels register gid_t egid; 30443393Skarels int error; 30543393Skarels 30643393Skarels egid = uap->egid; 30747540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 30847540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 30944405Skarels return (error); 31047540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 31147540Skarels pc->pc_ucred->cr_groups[0] = egid; 31254339Smckusick p->p_flag |= SUGID; 31344405Skarels return (0); 31443393Skarels } 31543393Skarels 316*54925Storek struct setgroups_args { 317*54925Storek u_int gidsetsize; 318*54925Storek int *gidset; 319*54925Storek }; 32043393Skarels /* ARGSUSED */ 32143393Skarels setgroups(p, uap, retval) 32243393Skarels struct proc *p; 323*54925Storek struct setgroups_args *uap; 32443393Skarels int *retval; 32543393Skarels { 32647540Skarels register struct pcred *pc = p->p_cred; 32718362Skarels register gid_t *gp; 32844994Skarels register u_int ngrp; 32918362Skarels register int *lp; 33044942Sbostic int error, groups[NGROUPS]; 3317498Sroot 33247540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 33344405Skarels return (error); 33444994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 33544405Skarels return (EINVAL); 33644942Sbostic if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 33744994Skarels ngrp * sizeof (groups[0]))) 33844405Skarels return (error); 33947540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 34047540Skarels pc->pc_ucred->cr_ngroups = ngrp; 34144942Sbostic /* convert from int's to gid_t's */ 34247540Skarels for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; ) 34344994Skarels *gp++ = *lp++; 34454339Smckusick p->p_flag |= SUGID; 34544405Skarels return (0); 3467498Sroot } 3477498Sroot 3487498Sroot /* 34937578Smckusick * Check if gid is a member of the group set. 35011810Ssam */ 35137578Smckusick groupmember(gid, cred) 35226275Skarels gid_t gid; 35337578Smckusick register struct ucred *cred; 3547866Sroot { 35518362Skarels register gid_t *gp; 35637578Smckusick gid_t *egp; 3577866Sroot 35837578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 35937578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 3607866Sroot if (*gp == gid) 36137578Smckusick return (1); 36237578Smckusick return (0); 3637866Sroot } 3647866Sroot 36511810Ssam /* 36646293Skarels * Test whether the specified credentials imply "super-user" 36746293Skarels * privilege; if so, and we have accounting info, set the flag 36846293Skarels * indicating use of super-powers. 36946293Skarels * Returns 0 or error. 37011810Ssam */ 37137578Smckusick suser(cred, acflag) 37237578Smckusick struct ucred *cred; 37337578Smckusick short *acflag; 3747866Sroot { 37537578Smckusick if (cred->cr_uid == 0) { 37637578Smckusick if (acflag) 37737578Smckusick *acflag |= ASU; 37837578Smckusick return (0); 37918362Skarels } 38037578Smckusick return (EPERM); 3817866Sroot } 38211810Ssam 38311810Ssam /* 38437578Smckusick * Allocate a zeroed cred structure. 38511810Ssam */ 38637578Smckusick struct ucred * 38737578Smckusick crget() 38811810Ssam { 38937578Smckusick register struct ucred *cr; 39011810Ssam 39137578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 39237578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 39337578Smckusick cr->cr_ref = 1; 39443393Skarels return (cr); 39511810Ssam } 39637085Skfall 39737085Skfall /* 39837578Smckusick * Free a cred structure. 39937578Smckusick * Throws away space when ref count gets to 0. 40037085Skfall */ 40137578Smckusick crfree(cr) 40237578Smckusick struct ucred *cr; 40337578Smckusick { 40447540Skarels int s = splimp(); /* ??? */ 40537085Skfall 40637578Smckusick if (--cr->cr_ref != 0) { 40737578Smckusick (void) splx(s); 40837578Smckusick return; 40937578Smckusick } 41037578Smckusick FREE((caddr_t)cr, M_CRED); 41137578Smckusick (void) splx(s); 41237578Smckusick } 41337578Smckusick 41437578Smckusick /* 41537578Smckusick * Copy cred structure to a new one and free the old one. 41637578Smckusick */ 41737578Smckusick struct ucred * 41837578Smckusick crcopy(cr) 41937578Smckusick struct ucred *cr; 42037085Skfall { 42137578Smckusick struct ucred *newcr; 42237085Skfall 42345908Sbostic if (cr->cr_ref == 1) 42445908Sbostic return (cr); 42537578Smckusick newcr = crget(); 42637578Smckusick *newcr = *cr; 42737578Smckusick crfree(cr); 42837578Smckusick newcr->cr_ref = 1; 42943393Skarels return (newcr); 43037085Skfall } 43137085Skfall 43237085Skfall /* 43337578Smckusick * Dup cred struct to a new held one. 43437085Skfall */ 43537578Smckusick struct ucred * 43637578Smckusick crdup(cr) 43737578Smckusick struct ucred *cr; 43837085Skfall { 43937578Smckusick struct ucred *newcr; 44037085Skfall 44137578Smckusick newcr = crget(); 44237578Smckusick *newcr = *cr; 44337578Smckusick newcr->cr_ref = 1; 44443393Skarels return (newcr); 44537085Skfall } 44637579Smckusick 44737579Smckusick /* 44840667Skarels * Get login name, if available. 44937579Smckusick */ 450*54925Storek struct getlogin_args { 451*54925Storek char *namebuf; 452*54925Storek u_int namelen; 453*54925Storek }; 45443393Skarels /* ARGSUSED */ 45543393Skarels getlogin(p, uap, retval) 45643393Skarels struct proc *p; 457*54925Storek struct getlogin_args *uap; 45843393Skarels int *retval; 45943393Skarels { 46037579Smckusick 46147540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 46247540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 46347540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 46447540Skarels (caddr_t) uap->namebuf, uap->namelen)); 46537579Smckusick } 46637579Smckusick 46737579Smckusick /* 46840667Skarels * Set login name. 46937579Smckusick */ 470*54925Storek struct setlogin_args { 471*54925Storek char *namebuf; 472*54925Storek }; 47343393Skarels /* ARGSUSED */ 47443393Skarels setlogin(p, uap, retval) 47543393Skarels struct proc *p; 476*54925Storek struct setlogin_args *uap; 47743393Skarels int *retval; 47837579Smckusick { 47940667Skarels int error; 48037579Smckusick 48147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48244405Skarels return (error); 48347540Skarels error = copyinstr((caddr_t) uap->namebuf, 48447540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 48547540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 48647540Skarels if (error == ENAMETOOLONG) 48740667Skarels error = EINVAL; 48844405Skarels return (error); 48937579Smckusick } 490