123372Smckusick /* 243393Skarels * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California. 337578Smckusick * All rights reserved. 423372Smckusick * 5*44439Sbostic * %sccs.include.redist.c% 637578Smckusick * 7*44439Sbostic * @(#)kern_prot.c 7.13 (Berkeley) 06/28/90 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" 1744405Skarels #include "user.h" 1817092Sbloom #include "proc.h" 1917092Sbloom #include "timeb.h" 2017092Sbloom #include "times.h" 2137578Smckusick #include "malloc.h" 227420Sroot 2343393Skarels /* ARGSUSED */ 2443393Skarels getpid(p, uap, retval) 2543393Skarels struct proc *p; 2643393Skarels void *uap; 2743393Skarels int *retval; 2843393Skarels { 2937579Smckusick 3043393Skarels *retval = p->p_pid; 3143393Skarels #ifdef COMPAT_43 3243393Skarels retval[1] = p->p_ppid; 3343393Skarels #endif 3444405Skarels return (0); 3543393Skarels } 3643393Skarels 3743393Skarels /* ARGSUSED */ 3843393Skarels getppid(p, uap, retval) 3943393Skarels struct proc *p; 4043393Skarels void *uap; 4143393Skarels int *retval; 427498Sroot { 437498Sroot 4443393Skarels *retval = p->p_ppid; 4544405Skarels return (0); 467498Sroot } 477498Sroot 4843393Skarels getpgrp(p, uap, retval) 4943393Skarels struct proc *p; 5043393Skarels struct args { 5143393Skarels int pid; 5243393Skarels } *uap; 5343393Skarels int *retval; 547498Sroot { 557498Sroot 5643393Skarels if (uap->pid != 0 && (p = pfind(uap->pid)) == 0) 5744405Skarels return (ESRCH); 5843393Skarels *retval = p->p_pgrp->pg_id; 5944405Skarels return (0); 607498Sroot } 617498Sroot 6243393Skarels /* ARGSUSED */ 6343393Skarels getuid(p, uap, retval) 6443393Skarels struct proc *p; 6543393Skarels void *uap; 6643393Skarels int *retval; 677420Sroot { 687420Sroot 6943393Skarels *retval = p->p_ruid; 7043393Skarels #ifdef COMPAT_43 7143393Skarels retval[1] = u.u_cred->cr_uid; 7243393Skarels #endif 7344405Skarels return (0); 747420Sroot } 757420Sroot 7643393Skarels /* ARGSUSED */ 7743393Skarels geteuid(p, uap, retval) 7843393Skarels struct proc *p; 7943393Skarels void *uap; 8043393Skarels int *retval; 817498Sroot { 827498Sroot 8343393Skarels *retval = u.u_cred->cr_uid; 8444405Skarels return (0); 857498Sroot } 867498Sroot 8743393Skarels /* ARGSUSED */ 8843393Skarels getgid(p, uap, retval) 8943393Skarels struct proc *p; 9043393Skarels void *uap; 9143393Skarels int *retval; 927498Sroot { 9343393Skarels 9443393Skarels *retval = p->p_rgid; 9543393Skarels #ifdef COMPAT_43 9643393Skarels retval[1] = u.u_cred->cr_groups[0]; 9743393Skarels #endif 9844405Skarels return (0); 9943393Skarels } 10043393Skarels 10143393Skarels /* 10243393Skarels * Get effective group ID. 10343393Skarels * The "egid" is groups[0], and thus could be obtained via getgroups; 10443393Skarels * this is somewhat painful to do correctly in a library function, 10543393Skarels * this the existence of this syscall. 10643393Skarels */ 10743393Skarels /* ARGSUSED */ 10843393Skarels getegid(p, uap, retval) 10943393Skarels struct proc *p; 11043393Skarels void *uap; 11143393Skarels int *retval; 11243393Skarels { 11343393Skarels 11443393Skarels *retval = u.u_cred->cr_groups[0]; 11544405Skarels return (0); 11643393Skarels } 11743393Skarels 11843393Skarels getgroups(p, uap, retval) 11943393Skarels struct proc *p; 12043393Skarels register struct arg { 1218624Sroot u_int gidsetsize; 12243393Skarels int *gidset; /* XXX not yet POSIX */ 12343393Skarels } *uap; 12443393Skarels int *retval; 12543393Skarels { 12618362Skarels register gid_t *gp; 12718362Skarels register int *lp; 12818362Skarels int groups[NGROUPS]; 12943393Skarels int error; 1307498Sroot 13137578Smckusick if (uap->gidsetsize == 0) { 13243393Skarels *retval = u.u_cred->cr_ngroups; 13344405Skarels return (0); 13437578Smckusick } 13543393Skarels if (uap->gidsetsize < u.u_cred->cr_ngroups) 13644405Skarels return (EINVAL); 13740667Skarels uap->gidsetsize = u.u_cred->cr_ngroups; 13840667Skarels gp = u.u_cred->cr_groups; 13937578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 14018362Skarels *lp++ = *gp++; 14143393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 14243393Skarels uap->gidsetsize * sizeof (groups[0]))) 14344405Skarels return (error); 14443393Skarels *retval = uap->gidsetsize; 14544405Skarels return (0); 1467498Sroot } 1477498Sroot 14843393Skarels /* ARGSUSED */ 14943393Skarels setsid(p, uap, retval) 15043393Skarels struct proc *p; 15143393Skarels void *uap; 15243393Skarels int *retval; 15337579Smckusick { 15437579Smckusick 15543393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 15644405Skarels return (EPERM); 15743393Skarels } else { 15837579Smckusick pgmv(p, p->p_pid, 1); 15943393Skarels *retval = p->p_pid; 16044405Skarels return (0); 16137579Smckusick } 16237579Smckusick } 16337579Smckusick 16437579Smckusick /* 16543393Skarels * set process group (setpgrp/setpgid) 16637579Smckusick * 16740667Skarels * caller does setpgrp(pid, pgid) 16840667Skarels * 16940667Skarels * pid must be caller or child of caller (ESRCH) 17040667Skarels * if a child 17140667Skarels * pid must be in same session (EPERM) 17240667Skarels * pid can't have done an exec (EACCES) 17340667Skarels * if pgid != pid 17440667Skarels * there must exist some pid in same session having pgid (EPERM) 17540667Skarels * pid must not be session leader (EPERM) 17637579Smckusick */ 17743393Skarels /* ARGSUSED */ 17843393Skarels setpgrp(cp, uap, retval) 17943393Skarels struct proc *cp; 18043393Skarels register struct args { 1817498Sroot int pid; 18237579Smckusick int pgid; 18343393Skarels } *uap; 18443393Skarels int *retval; 18543393Skarels { 18637579Smckusick register struct proc *p; 18737579Smckusick register struct pgrp *pgrp; 1887498Sroot 18943393Skarels if (uap->pid != 0) { 19043393Skarels if ((p = pfind(uap->pid)) == 0 || !inferior(p)) 19144405Skarels return (ESRCH); 19243393Skarels if (p->p_session != cp->p_session) 19344405Skarels return (EPERM); 19443393Skarels if (p->p_flag&SEXEC) 19544405Skarels return (EACCES); 19643393Skarels } else 19743393Skarels p = cp; 19843393Skarels if (SESS_LEADER(p)) 19944405Skarels return (EPERM); 20037579Smckusick if (uap->pgid == 0) 20137579Smckusick uap->pgid = p->p_pid; 20237579Smckusick else if ((uap->pgid != p->p_pid) && 20337579Smckusick (((pgrp = pgfind(uap->pgid)) == 0) || 20437579Smckusick pgrp->pg_mem == NULL || 20543393Skarels pgrp->pg_session != u.u_procp->p_session)) 20644405Skarels return (EPERM); 20737579Smckusick /* 20843393Skarels * done checking, now do it 20937579Smckusick */ 21037579Smckusick pgmv(p, uap->pgid, 0); 21144405Skarels return (0); 2127498Sroot } 2137498Sroot 21443393Skarels /* ARGSUSED */ 21543393Skarels setuid(p, uap, retval) 21643393Skarels register struct proc *p; 21743393Skarels struct args { 21843393Skarels int uid; 21943393Skarels } *uap; 22043393Skarels int *retval; 2217420Sroot { 22243393Skarels register uid_t uid; 22343393Skarels int error; 22443393Skarels 22543393Skarels uid = uap->uid; 22643393Skarels if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 22744405Skarels return (error); 22843393Skarels /* 22943393Skarels * Everything's okay, do it. 23043393Skarels * Copy credentials so other references do not 23143393Skarels * see our changes. 23243393Skarels */ 23343393Skarels if (u.u_cred->cr_ref > 1) 23443393Skarels u.u_cred = crcopy(u.u_cred); 23543393Skarels u.u_cred->cr_uid = uid; 23643393Skarels p->p_uid = uid; 23743393Skarels p->p_ruid = uid; 23843393Skarels p->p_svuid = uid; 23944405Skarels return (0); 24043393Skarels } 24143393Skarels 24243393Skarels /* ARGSUSED */ 24343393Skarels seteuid(p, uap, retval) 24443393Skarels register struct proc *p; 24543393Skarels struct args { 24643393Skarels int euid; 24743393Skarels } *uap; 24843393Skarels int *retval; 24943393Skarels { 25043393Skarels register uid_t euid; 25143393Skarels int error; 25243393Skarels 25343393Skarels euid = uap->euid; 25443393Skarels if (euid != p->p_ruid && euid != p->p_svuid && 25543393Skarels (error = suser(u.u_cred, &u.u_acflag))) 25644405Skarels return (error); 25743393Skarels /* 25843393Skarels * Everything's okay, do it. 25943393Skarels * Copy credentials so other references do not 26043393Skarels * see our changes. 26143393Skarels */ 26243393Skarels if (u.u_cred->cr_ref > 1) 26343393Skarels u.u_cred = crcopy(u.u_cred); 26443393Skarels u.u_cred->cr_uid = euid; 26543393Skarels p->p_uid = euid; 26644405Skarels return (0); 26743393Skarels } 26843393Skarels 26943393Skarels /* ARGSUSED */ 27043393Skarels setgid(p, uap, retval) 27143393Skarels struct proc *p; 27243393Skarels struct args { 27343393Skarels int gid; 27443393Skarels } *uap; 27543393Skarels int *retval; 27643393Skarels { 27743393Skarels register gid_t gid; 27843393Skarels int error; 27943393Skarels 28043393Skarels gid = uap->gid; 28143393Skarels if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 28244405Skarels return (error); 28343393Skarels if (u.u_cred->cr_ref > 1) 28443393Skarels u.u_cred = crcopy(u.u_cred); 28543393Skarels p->p_rgid = gid; 28643393Skarels u.u_cred->cr_groups[0] = gid; 28743393Skarels p->p_svgid = gid; /* ??? */ 28844405Skarels return (0); 28943393Skarels } 29043393Skarels 29143393Skarels /* ARGSUSED */ 29243393Skarels setegid(p, uap, retval) 29343393Skarels struct proc *p; 29443393Skarels struct args { 29543393Skarels int egid; 29643393Skarels } *uap; 29743393Skarels int *retval; 29843393Skarels { 29943393Skarels register gid_t egid; 30043393Skarels int error; 30143393Skarels 30243393Skarels egid = uap->egid; 30343393Skarels if (egid != p->p_rgid && egid != p->p_svgid && 30443393Skarels (error = suser(u.u_cred, &u.u_acflag))) 30544405Skarels return (error); 30643393Skarels if (u.u_cred->cr_ref > 1) 30743393Skarels u.u_cred = crcopy(u.u_cred); 30843393Skarels u.u_cred->cr_groups[0] = egid; 30944405Skarels return (0); 31043393Skarels } 31143393Skarels 31243393Skarels #ifdef COMPAT_43 31343393Skarels /* ARGSUSED */ 31443393Skarels osetreuid(p, uap, retval) 31543393Skarels register struct proc *p; 31643393Skarels struct args { 3179160Ssam int ruid; 3189160Ssam int euid; 3199160Ssam } *uap; 32043393Skarels int *retval; 32143393Skarels { 32243393Skarels register uid_t ruid, euid; 32343393Skarels int error; 3249160Ssam 32543393Skarels if (uap->ruid == -1) 32640667Skarels ruid = p->p_ruid; 32743393Skarels else 32843393Skarels ruid = uap->ruid; 32943393Skarels /* 33043393Skarels * Allow setting real uid to previous effective, 33143393Skarels * for swapping real and effective. 33243393Skarels * This should be: 33343393Skarels * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 33443393Skarels */ 33540667Skarels if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 33643393Skarels (error = suser(u.u_cred, &u.u_acflag))) 33744405Skarels return (error); 33843393Skarels if (uap->euid == -1) 33940667Skarels euid = u.u_cred->cr_uid; 34043393Skarels else 34143393Skarels euid = uap->euid; 34240667Skarels if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 34343393Skarels euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag))) 34444405Skarels return (error); 3459160Ssam /* 3469160Ssam * Everything's okay, do it. 34737578Smckusick * Copy credentials so other references do not 34837578Smckusick * see our changes. 3499160Ssam */ 35037578Smckusick if (u.u_cred->cr_ref > 1) 35137578Smckusick u.u_cred = crcopy(u.u_cred); 35240667Skarels u.u_cred->cr_uid = euid; 35340667Skarels p->p_uid = euid; 35440667Skarels p->p_ruid = ruid; 35544405Skarels return (0); 3569160Ssam } 3579160Ssam 35843393Skarels /* ARGSUSED */ 35943393Skarels osetregid(p, uap, retval) 36043393Skarels struct proc *p; 36143393Skarels struct args { 3629160Ssam int rgid; 3639160Ssam int egid; 3649160Ssam } *uap; 36543393Skarels int *retval; 36643393Skarels { 36743393Skarels register gid_t rgid, egid; 36843393Skarels int error; 3699160Ssam 37043393Skarels if (uap->rgid == -1) 37140667Skarels rgid = p->p_rgid; 37243393Skarels else 37343393Skarels rgid = uap->rgid; 37443393Skarels /* 37543393Skarels * Allow setting real gid to previous effective, 37643393Skarels * for swapping real and effective. This didn't really work 37743393Skarels * correctly in 4.[23], but is preserved so old stuff doesn't fail. 37843393Skarels * This should be: 37943393Skarels * if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 38043393Skarels */ 38140667Skarels if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 38243393Skarels (error = suser(u.u_cred, &u.u_acflag))) 38344405Skarels return (error); 38443393Skarels if (uap->egid == -1) 38540667Skarels egid = u.u_cred->cr_groups[0]; 38643393Skarels else 38743393Skarels egid = uap->egid; 38840667Skarels if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 38943393Skarels egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag))) 39044405Skarels return (error); 39137578Smckusick if (u.u_cred->cr_ref > 1) 39237578Smckusick u.u_cred = crcopy(u.u_cred); 39340667Skarels p->p_rgid = rgid; 39440667Skarels u.u_cred->cr_groups[0] = egid; 39544405Skarels return (0); 3969160Ssam } 39743393Skarels #endif 3989160Ssam 39943393Skarels /* ARGSUSED */ 40043393Skarels setgroups(p, uap, retval) 40143393Skarels struct proc *p; 40243393Skarels struct args { 4038624Sroot u_int gidsetsize; 4047498Sroot int *gidset; 40543393Skarels } *uap; 40643393Skarels int *retval; 40743393Skarels { 40818362Skarels register gid_t *gp; 40918362Skarels register int *lp; 41043393Skarels int error, ngrp, groups[NGROUPS]; 4117498Sroot 41243393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 41344405Skarels return (error); 41440667Skarels ngrp = uap->gidsetsize; 41543393Skarels if (ngrp > NGROUPS) 41644405Skarels return (EINVAL); 41743393Skarels error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 41818362Skarels uap->gidsetsize * sizeof (groups[0])); 41943393Skarels if (error) 42044405Skarels return (error); 42140667Skarels gp = u.u_cred->cr_groups; 42237578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 42318362Skarels *gp++ = *lp++; 42440667Skarels u.u_cred->cr_ngroups = ngrp; 42544405Skarels return (0); 4267498Sroot } 4277498Sroot 4287498Sroot /* 42937578Smckusick * Check if gid is a member of the group set. 43011810Ssam */ 43137578Smckusick groupmember(gid, cred) 43226275Skarels gid_t gid; 43337578Smckusick register struct ucred *cred; 4347866Sroot { 43518362Skarels register gid_t *gp; 43637578Smckusick gid_t *egp; 4377866Sroot 43837578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 43937578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4407866Sroot if (*gp == gid) 44137578Smckusick return (1); 44237578Smckusick return (0); 4437866Sroot } 4447866Sroot 44511810Ssam /* 44637578Smckusick * Test if the current user is the super user. 44711810Ssam */ 44837578Smckusick suser(cred, acflag) 44937578Smckusick struct ucred *cred; 45037578Smckusick short *acflag; 4517866Sroot { 4527866Sroot 45337578Smckusick if (cred->cr_uid == 0) { 45437578Smckusick if (acflag) 45537578Smckusick *acflag |= ASU; 45637578Smckusick return (0); 45718362Skarels } 45837578Smckusick return (EPERM); 4597866Sroot } 46011810Ssam 46111810Ssam /* 46237578Smckusick * Allocate a zeroed cred structure. 46311810Ssam */ 46437578Smckusick struct ucred * 46537578Smckusick crget() 46611810Ssam { 46737578Smckusick register struct ucred *cr; 46811810Ssam 46937578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 47037578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 47137578Smckusick cr->cr_ref = 1; 47243393Skarels return (cr); 47311810Ssam } 47437085Skfall 47537085Skfall /* 47637578Smckusick * Free a cred structure. 47737578Smckusick * Throws away space when ref count gets to 0. 47837085Skfall */ 47937578Smckusick crfree(cr) 48037578Smckusick struct ucred *cr; 48137578Smckusick { 48243393Skarels int s = splimp(); 48337085Skfall 48437578Smckusick if (--cr->cr_ref != 0) { 48537578Smckusick (void) splx(s); 48637578Smckusick return; 48737578Smckusick } 48837578Smckusick FREE((caddr_t)cr, M_CRED); 48937578Smckusick (void) splx(s); 49037578Smckusick } 49137578Smckusick 49237578Smckusick /* 49337578Smckusick * Copy cred structure to a new one and free the old one. 49437578Smckusick */ 49537578Smckusick struct ucred * 49637578Smckusick crcopy(cr) 49737578Smckusick struct ucred *cr; 49837085Skfall { 49937578Smckusick struct ucred *newcr; 50037085Skfall 50137578Smckusick newcr = crget(); 50237578Smckusick *newcr = *cr; 50337578Smckusick crfree(cr); 50437578Smckusick newcr->cr_ref = 1; 50543393Skarels return (newcr); 50637085Skfall } 50737085Skfall 50837085Skfall /* 50937578Smckusick * Dup cred struct to a new held one. 51037085Skfall */ 51137578Smckusick struct ucred * 51237578Smckusick crdup(cr) 51337578Smckusick struct ucred *cr; 51437085Skfall { 51537578Smckusick struct ucred *newcr; 51637085Skfall 51737578Smckusick newcr = crget(); 51837578Smckusick *newcr = *cr; 51937578Smckusick newcr->cr_ref = 1; 52043393Skarels return (newcr); 52137085Skfall } 52237579Smckusick 52337579Smckusick /* 52440667Skarels * Get login name, if available. 52537579Smckusick */ 52643393Skarels /* ARGSUSED */ 52743393Skarels getlogin(p, uap, retval) 52843393Skarels struct proc *p; 52943393Skarels struct args { 53037579Smckusick char *namebuf; 53137579Smckusick u_int namelen; 53243393Skarels } *uap; 53343393Skarels int *retval; 53443393Skarels { 53537579Smckusick 53643393Skarels if (uap->namelen > sizeof (p->p_logname)) 53743393Skarels uap->namelen = sizeof (p->p_logname); 53844405Skarels return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 53943393Skarels uap->namelen)); 54037579Smckusick } 54137579Smckusick 54237579Smckusick /* 54340667Skarels * Set login name. 54437579Smckusick */ 54543393Skarels /* ARGSUSED */ 54643393Skarels setlogin(p, uap, retval) 54743393Skarels struct proc *p; 54843393Skarels struct args { 54943393Skarels char *namebuf; 55043393Skarels } *uap; 55143393Skarels int *retval; 55237579Smckusick { 55340667Skarels int error; 55437579Smckusick 55543393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 55644405Skarels return (error); 55743393Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 55843393Skarels sizeof (p->p_logname) - 1, (int *) 0); 55940667Skarels if (error == ENOENT) /* name too long */ 56040667Skarels error = EINVAL; 56144405Skarels return (error); 56237579Smckusick } 563