123372Smckusick /* 243393Skarels * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California. 337578Smckusick * All rights reserved. 423372Smckusick * 544439Sbostic * %sccs.include.redist.c% 637578Smckusick * 7*45356Smckusick * @(#)kern_prot.c 7.16 (Berkeley) 10/19/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; 12844994Skarels register u_int ngrp; 12918362Skarels int groups[NGROUPS]; 13043393Skarels int error; 1317498Sroot 13244994Skarels if ((ngrp = uap->gidsetsize) == 0) { 13343393Skarels *retval = u.u_cred->cr_ngroups; 13444405Skarels return (0); 13537578Smckusick } 13644994Skarels if (ngrp < u.u_cred->cr_ngroups) 13744405Skarels return (EINVAL); 13844994Skarels ngrp = u.u_cred->cr_ngroups; 13944994Skarels for (gp = u.u_cred->cr_groups, lp = groups; lp < &groups[ngrp]; ) 14018362Skarels *lp++ = *gp++; 14143393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 14244994Skarels ngrp * sizeof (groups[0]))) 14344405Skarels return (error); 14444994Skarels *retval = ngrp; 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; 40944994Skarels register u_int ngrp; 41018362Skarels register int *lp; 41144942Sbostic int error, groups[NGROUPS]; 4127498Sroot 41343393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 41444405Skarels return (error); 41544994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 41644405Skarels return (EINVAL); 41744942Sbostic if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 41844994Skarels ngrp * sizeof (groups[0]))) 41944405Skarels return (error); 42044994Skarels u.u_cred->cr_ngroups = ngrp; 42144942Sbostic /* convert from int's to gid_t's */ 42244994Skarels for (gp = u.u_cred->cr_groups, lp = groups; ngrp--; ) 42344994Skarels *gp++ = *lp++; 42444405Skarels return (0); 4257498Sroot } 4267498Sroot 4277498Sroot /* 42837578Smckusick * Check if gid is a member of the group set. 42911810Ssam */ 43037578Smckusick groupmember(gid, cred) 43126275Skarels gid_t gid; 43237578Smckusick register struct ucred *cred; 4337866Sroot { 43418362Skarels register gid_t *gp; 43537578Smckusick gid_t *egp; 4367866Sroot 43737578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 43837578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4397866Sroot if (*gp == gid) 44037578Smckusick return (1); 44137578Smckusick return (0); 4427866Sroot } 4437866Sroot 44411810Ssam /* 44537578Smckusick * Test if the current user is the super user. 44611810Ssam */ 44737578Smckusick suser(cred, acflag) 44837578Smckusick struct ucred *cred; 44937578Smckusick short *acflag; 4507866Sroot { 4517866Sroot 45237578Smckusick if (cred->cr_uid == 0) { 45337578Smckusick if (acflag) 45437578Smckusick *acflag |= ASU; 45537578Smckusick return (0); 45618362Skarels } 45737578Smckusick return (EPERM); 4587866Sroot } 45911810Ssam 46011810Ssam /* 46137578Smckusick * Allocate a zeroed cred structure. 46211810Ssam */ 46337578Smckusick struct ucred * 46437578Smckusick crget() 46511810Ssam { 46637578Smckusick register struct ucred *cr; 46711810Ssam 46837578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 46937578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 47037578Smckusick cr->cr_ref = 1; 47143393Skarels return (cr); 47211810Ssam } 47337085Skfall 47437085Skfall /* 47537578Smckusick * Free a cred structure. 47637578Smckusick * Throws away space when ref count gets to 0. 47737085Skfall */ 47837578Smckusick crfree(cr) 47937578Smckusick struct ucred *cr; 48037578Smckusick { 48143393Skarels int s = splimp(); 48237085Skfall 48337578Smckusick if (--cr->cr_ref != 0) { 48437578Smckusick (void) splx(s); 48537578Smckusick return; 48637578Smckusick } 48737578Smckusick FREE((caddr_t)cr, M_CRED); 48837578Smckusick (void) splx(s); 48937578Smckusick } 49037578Smckusick 49137578Smckusick /* 49237578Smckusick * Copy cred structure to a new one and free the old one. 49337578Smckusick */ 49437578Smckusick struct ucred * 49537578Smckusick crcopy(cr) 49637578Smckusick struct ucred *cr; 49737085Skfall { 49837578Smckusick struct ucred *newcr; 49937085Skfall 50037578Smckusick newcr = crget(); 50137578Smckusick *newcr = *cr; 50237578Smckusick crfree(cr); 50337578Smckusick newcr->cr_ref = 1; 50443393Skarels return (newcr); 50537085Skfall } 50637085Skfall 50737085Skfall /* 50837578Smckusick * Dup cred struct to a new held one. 50937085Skfall */ 51037578Smckusick struct ucred * 51137578Smckusick crdup(cr) 51237578Smckusick struct ucred *cr; 51337085Skfall { 51437578Smckusick struct ucred *newcr; 51537085Skfall 51637578Smckusick newcr = crget(); 51737578Smckusick *newcr = *cr; 51837578Smckusick newcr->cr_ref = 1; 51943393Skarels return (newcr); 52037085Skfall } 52137579Smckusick 52237579Smckusick /* 52340667Skarels * Get login name, if available. 52437579Smckusick */ 52543393Skarels /* ARGSUSED */ 52643393Skarels getlogin(p, uap, retval) 52743393Skarels struct proc *p; 52843393Skarels struct args { 52937579Smckusick char *namebuf; 53037579Smckusick u_int namelen; 53143393Skarels } *uap; 53243393Skarels int *retval; 53343393Skarels { 53437579Smckusick 53543393Skarels if (uap->namelen > sizeof (p->p_logname)) 53643393Skarels uap->namelen = sizeof (p->p_logname); 53744405Skarels return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 53843393Skarels uap->namelen)); 53937579Smckusick } 54037579Smckusick 54137579Smckusick /* 54240667Skarels * Set login name. 54337579Smckusick */ 54443393Skarels /* ARGSUSED */ 54543393Skarels setlogin(p, uap, retval) 54643393Skarels struct proc *p; 54743393Skarels struct args { 54843393Skarels char *namebuf; 54943393Skarels } *uap; 55043393Skarels int *retval; 55137579Smckusick { 55240667Skarels int error; 55337579Smckusick 55443393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 55544405Skarels return (error); 55643393Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 55743393Skarels sizeof (p->p_logname) - 1, (int *) 0); 558*45356Smckusick if (error == ENAMETOOLONG) /* name too long */ 55940667Skarels error = EINVAL; 56044405Skarels return (error); 56137579Smckusick } 562