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*46293Skarels * @(#)kern_prot.c 7.18 (Berkeley) 02/06/91 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 /* 10245908Sbostic * Get effective group ID. The "egid" is groups[0], and could be obtained 10345908Sbostic * via getgroups. This syscall exists because it is somewhat painful to do 10445908Sbostic * correctly in a library function. 10543393Skarels */ 10643393Skarels /* ARGSUSED */ 10743393Skarels getegid(p, uap, retval) 10843393Skarels struct proc *p; 10943393Skarels void *uap; 11043393Skarels int *retval; 11143393Skarels { 11243393Skarels *retval = u.u_cred->cr_groups[0]; 11344405Skarels return (0); 11443393Skarels } 11543393Skarels 11643393Skarels getgroups(p, uap, retval) 11743393Skarels struct proc *p; 11843393Skarels register struct arg { 1198624Sroot u_int gidsetsize; 12043393Skarels int *gidset; /* XXX not yet POSIX */ 12143393Skarels } *uap; 12243393Skarels int *retval; 12343393Skarels { 12418362Skarels register gid_t *gp; 12518362Skarels register int *lp; 12644994Skarels register u_int ngrp; 12718362Skarels int groups[NGROUPS]; 12843393Skarels int error; 1297498Sroot 13044994Skarels if ((ngrp = uap->gidsetsize) == 0) { 13143393Skarels *retval = u.u_cred->cr_ngroups; 13244405Skarels return (0); 13337578Smckusick } 13444994Skarels if (ngrp < u.u_cred->cr_ngroups) 13544405Skarels return (EINVAL); 13644994Skarels ngrp = u.u_cred->cr_ngroups; 13744994Skarels for (gp = u.u_cred->cr_groups, lp = groups; lp < &groups[ngrp]; ) 13818362Skarels *lp++ = *gp++; 13943393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 14044994Skarels ngrp * sizeof (groups[0]))) 14144405Skarels return (error); 14244994Skarels *retval = ngrp; 14344405Skarels return (0); 1447498Sroot } 1457498Sroot 14643393Skarels /* ARGSUSED */ 14743393Skarels setsid(p, uap, retval) 14843393Skarels struct proc *p; 14943393Skarels void *uap; 15043393Skarels int *retval; 15137579Smckusick { 15237579Smckusick 15343393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 15444405Skarels return (EPERM); 15543393Skarels } else { 15637579Smckusick pgmv(p, p->p_pid, 1); 15743393Skarels *retval = p->p_pid; 15844405Skarels return (0); 15937579Smckusick } 16037579Smckusick } 16137579Smckusick 16237579Smckusick /* 16343393Skarels * set process group (setpgrp/setpgid) 16437579Smckusick * 16540667Skarels * caller does setpgrp(pid, pgid) 16640667Skarels * 16740667Skarels * pid must be caller or child of caller (ESRCH) 16840667Skarels * if a child 16940667Skarels * pid must be in same session (EPERM) 17040667Skarels * pid can't have done an exec (EACCES) 17140667Skarels * if pgid != pid 17240667Skarels * there must exist some pid in same session having pgid (EPERM) 17340667Skarels * pid must not be session leader (EPERM) 17437579Smckusick */ 17543393Skarels /* ARGSUSED */ 17643393Skarels setpgrp(cp, uap, retval) 17743393Skarels struct proc *cp; 17843393Skarels register struct args { 1797498Sroot int pid; 18037579Smckusick int pgid; 18143393Skarels } *uap; 18243393Skarels int *retval; 18343393Skarels { 18437579Smckusick register struct proc *p; 18537579Smckusick register struct pgrp *pgrp; 1867498Sroot 18743393Skarels if (uap->pid != 0) { 18843393Skarels if ((p = pfind(uap->pid)) == 0 || !inferior(p)) 18944405Skarels return (ESRCH); 19043393Skarels if (p->p_session != cp->p_session) 19144405Skarels return (EPERM); 19243393Skarels if (p->p_flag&SEXEC) 19344405Skarels return (EACCES); 19443393Skarels } else 19543393Skarels p = cp; 19643393Skarels if (SESS_LEADER(p)) 19744405Skarels return (EPERM); 19837579Smckusick if (uap->pgid == 0) 19937579Smckusick uap->pgid = p->p_pid; 20045908Sbostic else if (uap->pgid != p->p_pid) 20145908Sbostic if ((pgrp = pgfind(uap->pgid)) == 0 || 20245908Sbostic pgrp->pg_mem == NULL || 20345908Sbostic pgrp->pg_session != cp->p_session) 20445908Sbostic return (EPERM); 20537579Smckusick pgmv(p, uap->pgid, 0); 20644405Skarels return (0); 2077498Sroot } 2087498Sroot 20943393Skarels /* ARGSUSED */ 21043393Skarels setuid(p, uap, retval) 21143393Skarels register struct proc *p; 21243393Skarels struct args { 21343393Skarels int uid; 21443393Skarels } *uap; 21543393Skarels int *retval; 2167420Sroot { 21743393Skarels register uid_t uid; 21843393Skarels int error; 21943393Skarels 22043393Skarels uid = uap->uid; 22143393Skarels if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 22244405Skarels return (error); 22343393Skarels /* 22445908Sbostic * Everything's okay, do it. Copy credentials so other references do 22545908Sbostic * not see our changes. 22643393Skarels */ 22745908Sbostic u.u_cred = crcopy(u.u_cred); 22843393Skarels u.u_cred->cr_uid = uid; 22943393Skarels p->p_uid = uid; 23043393Skarels p->p_ruid = uid; 23143393Skarels p->p_svuid = uid; 23244405Skarels return (0); 23343393Skarels } 23443393Skarels 23543393Skarels /* ARGSUSED */ 23643393Skarels seteuid(p, uap, retval) 23743393Skarels register struct proc *p; 23843393Skarels struct args { 23943393Skarels int euid; 24043393Skarels } *uap; 24143393Skarels int *retval; 24243393Skarels { 24343393Skarels register uid_t euid; 24443393Skarels int error; 24543393Skarels 24643393Skarels euid = uap->euid; 24743393Skarels if (euid != p->p_ruid && euid != p->p_svuid && 24843393Skarels (error = suser(u.u_cred, &u.u_acflag))) 24944405Skarels return (error); 25043393Skarels /* 25145908Sbostic * Everything's okay, do it. Copy credentials so other references do 25245908Sbostic * not see our changes. 25343393Skarels */ 25445908Sbostic u.u_cred = crcopy(u.u_cred); 25543393Skarels u.u_cred->cr_uid = euid; 25643393Skarels p->p_uid = euid; 25744405Skarels return (0); 25843393Skarels } 25943393Skarels 26043393Skarels /* ARGSUSED */ 26143393Skarels setgid(p, uap, retval) 26243393Skarels struct proc *p; 26343393Skarels struct args { 26443393Skarels int gid; 26543393Skarels } *uap; 26643393Skarels int *retval; 26743393Skarels { 26843393Skarels register gid_t gid; 26943393Skarels int error; 27043393Skarels 27143393Skarels gid = uap->gid; 27243393Skarels if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 27344405Skarels return (error); 27445908Sbostic u.u_cred = crcopy(u.u_cred); 27543393Skarels p->p_rgid = gid; 27643393Skarels u.u_cred->cr_groups[0] = gid; 27743393Skarels p->p_svgid = gid; /* ??? */ 27844405Skarels return (0); 27943393Skarels } 28043393Skarels 28143393Skarels /* ARGSUSED */ 28243393Skarels setegid(p, uap, retval) 28343393Skarels struct proc *p; 28443393Skarels struct args { 28543393Skarels int egid; 28643393Skarels } *uap; 28743393Skarels int *retval; 28843393Skarels { 28943393Skarels register gid_t egid; 29043393Skarels int error; 29143393Skarels 29243393Skarels egid = uap->egid; 29343393Skarels if (egid != p->p_rgid && egid != p->p_svgid && 29443393Skarels (error = suser(u.u_cred, &u.u_acflag))) 29544405Skarels return (error); 29645908Sbostic u.u_cred = crcopy(u.u_cred); 29743393Skarels u.u_cred->cr_groups[0] = egid; 29844405Skarels return (0); 29943393Skarels } 30043393Skarels 30143393Skarels #ifdef COMPAT_43 30243393Skarels /* ARGSUSED */ 30343393Skarels osetreuid(p, uap, retval) 30443393Skarels register struct proc *p; 30543393Skarels struct args { 3069160Ssam int ruid; 3079160Ssam int euid; 3089160Ssam } *uap; 30943393Skarels int *retval; 31043393Skarels { 31143393Skarels register uid_t ruid, euid; 31243393Skarels int error; 3139160Ssam 31443393Skarels if (uap->ruid == -1) 31540667Skarels ruid = p->p_ruid; 31643393Skarels else 31743393Skarels ruid = uap->ruid; 31843393Skarels /* 31945908Sbostic * Allow setting real uid to previous effective, for swapping real and 32045908Sbostic * effective. This should be: 32145908Sbostic * 32245908Sbostic * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 32343393Skarels */ 32445908Sbostic if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 32543393Skarels (error = suser(u.u_cred, &u.u_acflag))) 32644405Skarels return (error); 32743393Skarels if (uap->euid == -1) 32840667Skarels euid = u.u_cred->cr_uid; 32943393Skarels else 33043393Skarels euid = uap->euid; 33140667Skarels if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 33243393Skarels euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag))) 33344405Skarels return (error); 3349160Ssam /* 33545908Sbostic * Everything's okay, do it. Copy credentials so other references do 33645908Sbostic * not see our changes. 3379160Ssam */ 33845908Sbostic u.u_cred = crcopy(u.u_cred); 33940667Skarels u.u_cred->cr_uid = euid; 34040667Skarels p->p_uid = euid; 34140667Skarels p->p_ruid = ruid; 34244405Skarels return (0); 3439160Ssam } 3449160Ssam 34543393Skarels /* ARGSUSED */ 34643393Skarels osetregid(p, uap, retval) 34743393Skarels struct proc *p; 34843393Skarels struct args { 3499160Ssam int rgid; 3509160Ssam int egid; 3519160Ssam } *uap; 35243393Skarels int *retval; 35343393Skarels { 35443393Skarels register gid_t rgid, egid; 35543393Skarels int error; 3569160Ssam 35743393Skarels if (uap->rgid == -1) 35840667Skarels rgid = p->p_rgid; 35943393Skarels else 36043393Skarels rgid = uap->rgid; 36143393Skarels /* 36245908Sbostic * Allow setting real gid to previous effective, for swapping real and 36345908Sbostic * effective. This didn't really work correctly in 4.[23], but is 36445908Sbostic * preserved so old stuff doesn't fail. This should be: 36545908Sbostic * 36645908Sbostic * if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 36743393Skarels */ 36840667Skarels if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 36943393Skarels (error = suser(u.u_cred, &u.u_acflag))) 37044405Skarels return (error); 37143393Skarels if (uap->egid == -1) 37240667Skarels egid = u.u_cred->cr_groups[0]; 37343393Skarels else 37443393Skarels egid = uap->egid; 37545908Sbostic if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 37643393Skarels egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag))) 37744405Skarels return (error); 37845908Sbostic u.u_cred = crcopy(u.u_cred); 37940667Skarels p->p_rgid = rgid; 38040667Skarels u.u_cred->cr_groups[0] = egid; 38144405Skarels return (0); 3829160Ssam } 38343393Skarels #endif 3849160Ssam 38543393Skarels /* ARGSUSED */ 38643393Skarels setgroups(p, uap, retval) 38743393Skarels struct proc *p; 38843393Skarels struct args { 3898624Sroot u_int gidsetsize; 3907498Sroot int *gidset; 39143393Skarels } *uap; 39243393Skarels int *retval; 39343393Skarels { 39418362Skarels register gid_t *gp; 39544994Skarels register u_int ngrp; 39618362Skarels register int *lp; 39744942Sbostic int error, groups[NGROUPS]; 3987498Sroot 39943393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 40044405Skarels return (error); 40144994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 40244405Skarels return (EINVAL); 40344942Sbostic if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 40444994Skarels ngrp * sizeof (groups[0]))) 40544405Skarels return (error); 40645908Sbostic u.u_cred = crcopy(u.u_cred); 40744994Skarels u.u_cred->cr_ngroups = ngrp; 40844942Sbostic /* convert from int's to gid_t's */ 40944994Skarels for (gp = u.u_cred->cr_groups, lp = groups; ngrp--; ) 41044994Skarels *gp++ = *lp++; 41144405Skarels return (0); 4127498Sroot } 4137498Sroot 4147498Sroot /* 41537578Smckusick * Check if gid is a member of the group set. 41611810Ssam */ 41737578Smckusick groupmember(gid, cred) 41826275Skarels gid_t gid; 41937578Smckusick register struct ucred *cred; 4207866Sroot { 42118362Skarels register gid_t *gp; 42237578Smckusick gid_t *egp; 4237866Sroot 42437578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 42537578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4267866Sroot if (*gp == gid) 42737578Smckusick return (1); 42837578Smckusick return (0); 4297866Sroot } 4307866Sroot 43111810Ssam /* 432*46293Skarels * Test whether the specified credentials imply "super-user" 433*46293Skarels * privilege; if so, and we have accounting info, set the flag 434*46293Skarels * indicating use of super-powers. 435*46293Skarels * Returns 0 or error. 43611810Ssam */ 43737578Smckusick suser(cred, acflag) 43837578Smckusick struct ucred *cred; 43937578Smckusick short *acflag; 4407866Sroot { 44137578Smckusick if (cred->cr_uid == 0) { 44237578Smckusick if (acflag) 44337578Smckusick *acflag |= ASU; 44437578Smckusick return (0); 44518362Skarels } 44637578Smckusick return (EPERM); 4477866Sroot } 44811810Ssam 44911810Ssam /* 45037578Smckusick * Allocate a zeroed cred structure. 45111810Ssam */ 45237578Smckusick struct ucred * 45337578Smckusick crget() 45411810Ssam { 45537578Smckusick register struct ucred *cr; 45611810Ssam 45737578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 45837578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 45937578Smckusick cr->cr_ref = 1; 46043393Skarels return (cr); 46111810Ssam } 46237085Skfall 46337085Skfall /* 46437578Smckusick * Free a cred structure. 46537578Smckusick * Throws away space when ref count gets to 0. 46637085Skfall */ 46737578Smckusick crfree(cr) 46837578Smckusick struct ucred *cr; 46937578Smckusick { 47043393Skarels int s = splimp(); 47137085Skfall 47237578Smckusick if (--cr->cr_ref != 0) { 47337578Smckusick (void) splx(s); 47437578Smckusick return; 47537578Smckusick } 47637578Smckusick FREE((caddr_t)cr, M_CRED); 47737578Smckusick (void) splx(s); 47837578Smckusick } 47937578Smckusick 48037578Smckusick /* 48137578Smckusick * Copy cred structure to a new one and free the old one. 48237578Smckusick */ 48337578Smckusick struct ucred * 48437578Smckusick crcopy(cr) 48537578Smckusick struct ucred *cr; 48637085Skfall { 48737578Smckusick struct ucred *newcr; 48837085Skfall 48945908Sbostic if (cr->cr_ref == 1) 49045908Sbostic return (cr); 49137578Smckusick newcr = crget(); 49237578Smckusick *newcr = *cr; 49337578Smckusick crfree(cr); 49437578Smckusick newcr->cr_ref = 1; 49543393Skarels return (newcr); 49637085Skfall } 49737085Skfall 49837085Skfall /* 49937578Smckusick * Dup cred struct to a new held one. 50037085Skfall */ 50137578Smckusick struct ucred * 50237578Smckusick crdup(cr) 50337578Smckusick struct ucred *cr; 50437085Skfall { 50537578Smckusick struct ucred *newcr; 50637085Skfall 50737578Smckusick newcr = crget(); 50837578Smckusick *newcr = *cr; 50937578Smckusick newcr->cr_ref = 1; 51043393Skarels return (newcr); 51137085Skfall } 51237579Smckusick 51337579Smckusick /* 51440667Skarels * Get login name, if available. 51537579Smckusick */ 51643393Skarels /* ARGSUSED */ 51743393Skarels getlogin(p, uap, retval) 51843393Skarels struct proc *p; 51943393Skarels struct args { 52037579Smckusick char *namebuf; 52137579Smckusick u_int namelen; 52243393Skarels } *uap; 52343393Skarels int *retval; 52443393Skarels { 52537579Smckusick 52643393Skarels if (uap->namelen > sizeof (p->p_logname)) 52743393Skarels uap->namelen = sizeof (p->p_logname); 52844405Skarels return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 52943393Skarels uap->namelen)); 53037579Smckusick } 53137579Smckusick 53237579Smckusick /* 53340667Skarels * Set login name. 53437579Smckusick */ 53543393Skarels /* ARGSUSED */ 53643393Skarels setlogin(p, uap, retval) 53743393Skarels struct proc *p; 53843393Skarels struct args { 53943393Skarels char *namebuf; 54043393Skarels } *uap; 54143393Skarels int *retval; 54237579Smckusick { 54340667Skarels int error; 54437579Smckusick 54543393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 54644405Skarels return (error); 54743393Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 54845908Sbostic sizeof (p->p_logname) - 1, (u_int *)0); 54945356Smckusick if (error == ENAMETOOLONG) /* name too long */ 55040667Skarels error = EINVAL; 55144405Skarels return (error); 55237579Smckusick } 553