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*45908Sbostic * @(#)kern_prot.c 7.17 (Berkeley) 01/10/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 /* 102*45908Sbostic * Get effective group ID. The "egid" is groups[0], and could be obtained 103*45908Sbostic * via getgroups. This syscall exists because it is somewhat painful to do 104*45908Sbostic * 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; 200*45908Sbostic else if (uap->pgid != p->p_pid) 201*45908Sbostic if ((pgrp = pgfind(uap->pgid)) == 0 || 202*45908Sbostic pgrp->pg_mem == NULL || 203*45908Sbostic pgrp->pg_session != cp->p_session) 204*45908Sbostic 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 /* 224*45908Sbostic * Everything's okay, do it. Copy credentials so other references do 225*45908Sbostic * not see our changes. 22643393Skarels */ 227*45908Sbostic 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 /* 251*45908Sbostic * Everything's okay, do it. Copy credentials so other references do 252*45908Sbostic * not see our changes. 25343393Skarels */ 254*45908Sbostic 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); 274*45908Sbostic 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); 296*45908Sbostic 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 /* 319*45908Sbostic * Allow setting real uid to previous effective, for swapping real and 320*45908Sbostic * effective. This should be: 321*45908Sbostic * 322*45908Sbostic * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 32343393Skarels */ 324*45908Sbostic 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 /* 335*45908Sbostic * Everything's okay, do it. Copy credentials so other references do 336*45908Sbostic * not see our changes. 3379160Ssam */ 338*45908Sbostic 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 /* 362*45908Sbostic * Allow setting real gid to previous effective, for swapping real and 363*45908Sbostic * effective. This didn't really work correctly in 4.[23], but is 364*45908Sbostic * preserved so old stuff doesn't fail. This should be: 365*45908Sbostic * 366*45908Sbostic * 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; 375*45908Sbostic 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); 378*45908Sbostic 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); 406*45908Sbostic 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 /* 43237578Smckusick * Test if the current user is the super user. 43311810Ssam */ 43437578Smckusick suser(cred, acflag) 43537578Smckusick struct ucred *cred; 43637578Smckusick short *acflag; 4377866Sroot { 43837578Smckusick if (cred->cr_uid == 0) { 43937578Smckusick if (acflag) 44037578Smckusick *acflag |= ASU; 44137578Smckusick return (0); 44218362Skarels } 44337578Smckusick return (EPERM); 4447866Sroot } 44511810Ssam 44611810Ssam /* 44737578Smckusick * Allocate a zeroed cred structure. 44811810Ssam */ 44937578Smckusick struct ucred * 45037578Smckusick crget() 45111810Ssam { 45237578Smckusick register struct ucred *cr; 45311810Ssam 45437578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 45537578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 45637578Smckusick cr->cr_ref = 1; 45743393Skarels return (cr); 45811810Ssam } 45937085Skfall 46037085Skfall /* 46137578Smckusick * Free a cred structure. 46237578Smckusick * Throws away space when ref count gets to 0. 46337085Skfall */ 46437578Smckusick crfree(cr) 46537578Smckusick struct ucred *cr; 46637578Smckusick { 46743393Skarels int s = splimp(); 46837085Skfall 46937578Smckusick if (--cr->cr_ref != 0) { 47037578Smckusick (void) splx(s); 47137578Smckusick return; 47237578Smckusick } 47337578Smckusick FREE((caddr_t)cr, M_CRED); 47437578Smckusick (void) splx(s); 47537578Smckusick } 47637578Smckusick 47737578Smckusick /* 47837578Smckusick * Copy cred structure to a new one and free the old one. 47937578Smckusick */ 48037578Smckusick struct ucred * 48137578Smckusick crcopy(cr) 48237578Smckusick struct ucred *cr; 48337085Skfall { 48437578Smckusick struct ucred *newcr; 48537085Skfall 486*45908Sbostic if (cr->cr_ref == 1) 487*45908Sbostic return (cr); 48837578Smckusick newcr = crget(); 48937578Smckusick *newcr = *cr; 49037578Smckusick crfree(cr); 49137578Smckusick newcr->cr_ref = 1; 49243393Skarels return (newcr); 49337085Skfall } 49437085Skfall 49537085Skfall /* 49637578Smckusick * Dup cred struct to a new held one. 49737085Skfall */ 49837578Smckusick struct ucred * 49937578Smckusick crdup(cr) 50037578Smckusick struct ucred *cr; 50137085Skfall { 50237578Smckusick struct ucred *newcr; 50337085Skfall 50437578Smckusick newcr = crget(); 50537578Smckusick *newcr = *cr; 50637578Smckusick newcr->cr_ref = 1; 50743393Skarels return (newcr); 50837085Skfall } 50937579Smckusick 51037579Smckusick /* 51140667Skarels * Get login name, if available. 51237579Smckusick */ 51343393Skarels /* ARGSUSED */ 51443393Skarels getlogin(p, uap, retval) 51543393Skarels struct proc *p; 51643393Skarels struct args { 51737579Smckusick char *namebuf; 51837579Smckusick u_int namelen; 51943393Skarels } *uap; 52043393Skarels int *retval; 52143393Skarels { 52237579Smckusick 52343393Skarels if (uap->namelen > sizeof (p->p_logname)) 52443393Skarels uap->namelen = sizeof (p->p_logname); 52544405Skarels return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 52643393Skarels uap->namelen)); 52737579Smckusick } 52837579Smckusick 52937579Smckusick /* 53040667Skarels * Set login name. 53137579Smckusick */ 53243393Skarels /* ARGSUSED */ 53343393Skarels setlogin(p, uap, retval) 53443393Skarels struct proc *p; 53543393Skarels struct args { 53643393Skarels char *namebuf; 53743393Skarels } *uap; 53843393Skarels int *retval; 53937579Smckusick { 54040667Skarels int error; 54137579Smckusick 54243393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 54344405Skarels return (error); 54443393Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 545*45908Sbostic sizeof (p->p_logname) - 1, (u_int *)0); 54645356Smckusick if (error == ENAMETOOLONG) /* name too long */ 54740667Skarels error = EINVAL; 54844405Skarels return (error); 54937579Smckusick } 550