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*55162Smckusick * @(#)kern_prot.c 7.26 (Berkeley) 07/13/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 2354925Storek struct args { 2454925Storek int dummy; 2554925Storek }; 2654925Storek 2743393Skarels /* ARGSUSED */ 2843393Skarels getpid(p, uap, retval) 2943393Skarels struct proc *p; 3054925Storek 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; 4454925Storek 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; 5554925Storek 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; 6654925Storek 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; 8054925Storek 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; 9154925Storek 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; 11054925Storek struct args *uap; 11143393Skarels int *retval; 11243393Skarels { 11347540Skarels 11447540Skarels *retval = p->p_ucred->cr_groups[0]; 11544405Skarels return (0); 11643393Skarels } 11743393Skarels 11854925Storek struct getgroups_args { 11954925Storek u_int gidsetsize; 120*55162Smckusick gid_t *gidset; 12154925Storek }; 12243393Skarels getgroups(p, uap, retval) 12343393Skarels struct proc *p; 12454925Storek register struct getgroups_args *uap; 12543393Skarels int *retval; 12643393Skarels { 12747540Skarels register struct pcred *pc = p->p_cred; 12844994Skarels register u_int ngrp; 12943393Skarels int error; 1307498Sroot 13144994Skarels if ((ngrp = uap->gidsetsize) == 0) { 13247540Skarels *retval = pc->pc_ucred->cr_ngroups; 13344405Skarels return (0); 13437578Smckusick } 13547540Skarels if (ngrp < pc->pc_ucred->cr_ngroups) 13644405Skarels return (EINVAL); 13747540Skarels ngrp = pc->pc_ucred->cr_ngroups; 138*55162Smckusick if (error = copyout((caddr_t)pc->pc_ucred->cr_groups, 139*55162Smckusick (caddr_t)uap->gidset, ngrp * sizeof(gid_t))) 14044405Skarels return (error); 14144994Skarels *retval = ngrp; 14244405Skarels return (0); 1437498Sroot } 1447498Sroot 14543393Skarels /* ARGSUSED */ 14643393Skarels setsid(p, uap, retval) 14747540Skarels register struct proc *p; 14854925Storek struct args *uap; 14943393Skarels int *retval; 15037579Smckusick { 15137579Smckusick 15243393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 15344405Skarels return (EPERM); 15443393Skarels } else { 15547540Skarels enterpgrp(p, p->p_pid, 1); 15643393Skarels *retval = p->p_pid; 15744405Skarels return (0); 15837579Smckusick } 15937579Smckusick } 16037579Smckusick 16137579Smckusick /* 16247540Skarels * set process group (setpgid/old setpgrp) 16337579Smckusick * 16447972Smarc * caller does setpgid(targpid, targpgid) 16540667Skarels * 16640667Skarels * pid must be caller or child of caller (ESRCH) 16740667Skarels * if a child 16840667Skarels * pid must be in same session (EPERM) 16940667Skarels * pid can't have done an exec (EACCES) 17040667Skarels * if pgid != pid 17140667Skarels * there must exist some pid in same session having pgid (EPERM) 17240667Skarels * pid must not be session leader (EPERM) 17337579Smckusick */ 17454925Storek struct setpgid_args { 17554925Storek int pid; /* target process id */ 17654925Storek int pgid; /* target pgrp id */ 17754925Storek }; 17843393Skarels /* ARGSUSED */ 17947972Smarc setpgid(curp, uap, retval) 18047972Smarc struct proc *curp; 18154925Storek register struct setpgid_args *uap; 18243393Skarels int *retval; 18343393Skarels { 18447972Smarc register struct proc *targp; /* target process */ 18548990Skarels register struct pgrp *pgrp; /* target pgrp */ 1867498Sroot 18748990Skarels if (uap->pid != 0 && uap->pid != curp->p_pid) { 18848990Skarels if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 18944405Skarels return (ESRCH); 19047972Smarc if (targp->p_session != curp->p_session) 19144405Skarels return (EPERM); 19247972Smarc if (targp->p_flag&SEXEC) 19344405Skarels return (EACCES); 19443393Skarels } else 19547972Smarc targp = curp; 19647972Smarc if (SESS_LEADER(targp)) 19744405Skarels return (EPERM); 19848990Skarels if (uap->pgid == 0) 19948990Skarels uap->pgid = targp->p_pid; 20048990Skarels else if (uap->pgid != targp->p_pid) 20148990Skarels if ((pgrp = pgfind(uap->pgid)) == 0 || 20248990Skarels pgrp->pg_session != curp->p_session) 20345908Sbostic return (EPERM); 20448990Skarels enterpgrp(targp, uap->pgid, 0); 20544405Skarels return (0); 2067498Sroot } 2077498Sroot 20854925Storek struct setuid_args { 209*55162Smckusick uid_t uid; 21054925Storek }; 21143393Skarels /* ARGSUSED */ 21243393Skarels setuid(p, uap, retval) 21347540Skarels struct proc *p; 21454925Storek struct setuid_args *uap; 21543393Skarels int *retval; 2167420Sroot { 21747540Skarels register struct pcred *pc = p->p_cred; 21843393Skarels register uid_t uid; 21943393Skarels int error; 22043393Skarels 22143393Skarels uid = uap->uid; 22247540Skarels if (uid != pc->p_ruid && 22347540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 22444405Skarels return (error); 22543393Skarels /* 22645908Sbostic * Everything's okay, do it. Copy credentials so other references do 22745908Sbostic * not see our changes. 22843393Skarels */ 22947540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 23047540Skarels pc->pc_ucred->cr_uid = uid; 23147540Skarels pc->p_ruid = uid; 23247540Skarels pc->p_svuid = uid; 23354339Smckusick p->p_flag |= SUGID; 23444405Skarels return (0); 23543393Skarels } 23643393Skarels 23754925Storek struct seteuid_args { 238*55162Smckusick uid_t euid; 23954925Storek }; 24043393Skarels /* ARGSUSED */ 24143393Skarels seteuid(p, uap, retval) 24247540Skarels struct proc *p; 24354925Storek struct seteuid_args *uap; 24443393Skarels int *retval; 24543393Skarels { 24647540Skarels register struct pcred *pc = p->p_cred; 24743393Skarels register uid_t euid; 24843393Skarels int error; 24943393Skarels 25043393Skarels euid = uap->euid; 25147540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 25247540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 25344405Skarels return (error); 25443393Skarels /* 25545908Sbostic * Everything's okay, do it. Copy credentials so other references do 25645908Sbostic * not see our changes. 25743393Skarels */ 25847540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 25947540Skarels pc->pc_ucred->cr_uid = euid; 26054339Smckusick p->p_flag |= SUGID; 26144405Skarels return (0); 26243393Skarels } 26343393Skarels 26454925Storek struct setgid_args { 265*55162Smckusick gid_t gid; 26654925Storek }; 26743393Skarels /* ARGSUSED */ 26843393Skarels setgid(p, uap, retval) 26943393Skarels struct proc *p; 27054925Storek struct setgid_args *uap; 27143393Skarels int *retval; 27243393Skarels { 27347540Skarels register struct pcred *pc = p->p_cred; 27443393Skarels register gid_t gid; 27543393Skarels int error; 27643393Skarels 27743393Skarels gid = uap->gid; 27847540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 27944405Skarels return (error); 28047540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 28147540Skarels pc->pc_ucred->cr_groups[0] = gid; 28247540Skarels pc->p_rgid = gid; 28347540Skarels pc->p_svgid = gid; /* ??? */ 28454339Smckusick p->p_flag |= SUGID; 28544405Skarels return (0); 28643393Skarels } 28743393Skarels 28854925Storek struct setegid_args { 289*55162Smckusick gid_t egid; 29054925Storek }; 29143393Skarels /* ARGSUSED */ 29243393Skarels setegid(p, uap, retval) 29343393Skarels struct proc *p; 29454925Storek struct setegid_args *uap; 29543393Skarels int *retval; 29643393Skarels { 29747540Skarels register struct pcred *pc = p->p_cred; 29843393Skarels register gid_t egid; 29943393Skarels int error; 30043393Skarels 30143393Skarels egid = uap->egid; 30247540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 30347540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 30444405Skarels return (error); 30547540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 30647540Skarels pc->pc_ucred->cr_groups[0] = egid; 30754339Smckusick p->p_flag |= SUGID; 30844405Skarels return (0); 30943393Skarels } 31043393Skarels 31154925Storek struct setgroups_args { 31254925Storek u_int gidsetsize; 313*55162Smckusick gid_t *gidset; 31454925Storek }; 31543393Skarels /* ARGSUSED */ 31643393Skarels setgroups(p, uap, retval) 31743393Skarels struct proc *p; 31854925Storek struct setgroups_args *uap; 31943393Skarels int *retval; 32043393Skarels { 32147540Skarels register struct pcred *pc = p->p_cred; 32244994Skarels register u_int ngrp; 323*55162Smckusick int error; 3247498Sroot 32547540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 32644405Skarels return (error); 32744994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 32844405Skarels return (EINVAL); 329*55162Smckusick pc->pc_ucred = crcopy(pc->pc_ucred); 330*55162Smckusick if (error = copyin((caddr_t)uap->gidset, 331*55162Smckusick (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 33244405Skarels return (error); 33347540Skarels pc->pc_ucred->cr_ngroups = ngrp; 33454339Smckusick p->p_flag |= SUGID; 33544405Skarels return (0); 3367498Sroot } 3377498Sroot 3387498Sroot /* 33937578Smckusick * Check if gid is a member of the group set. 34011810Ssam */ 34137578Smckusick groupmember(gid, cred) 34226275Skarels gid_t gid; 34337578Smckusick register struct ucred *cred; 3447866Sroot { 34518362Skarels register gid_t *gp; 34637578Smckusick gid_t *egp; 3477866Sroot 34837578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 34937578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 3507866Sroot if (*gp == gid) 35137578Smckusick return (1); 35237578Smckusick return (0); 3537866Sroot } 3547866Sroot 35511810Ssam /* 35646293Skarels * Test whether the specified credentials imply "super-user" 35746293Skarels * privilege; if so, and we have accounting info, set the flag 35846293Skarels * indicating use of super-powers. 35946293Skarels * Returns 0 or error. 36011810Ssam */ 36137578Smckusick suser(cred, acflag) 36237578Smckusick struct ucred *cred; 36337578Smckusick short *acflag; 3647866Sroot { 36537578Smckusick if (cred->cr_uid == 0) { 36637578Smckusick if (acflag) 36737578Smckusick *acflag |= ASU; 36837578Smckusick return (0); 36918362Skarels } 37037578Smckusick return (EPERM); 3717866Sroot } 37211810Ssam 37311810Ssam /* 37437578Smckusick * Allocate a zeroed cred structure. 37511810Ssam */ 37637578Smckusick struct ucred * 37737578Smckusick crget() 37811810Ssam { 37937578Smckusick register struct ucred *cr; 38011810Ssam 38137578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 38237578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 38337578Smckusick cr->cr_ref = 1; 38443393Skarels return (cr); 38511810Ssam } 38637085Skfall 38737085Skfall /* 38837578Smckusick * Free a cred structure. 38937578Smckusick * Throws away space when ref count gets to 0. 39037085Skfall */ 39137578Smckusick crfree(cr) 39237578Smckusick struct ucred *cr; 39337578Smckusick { 39447540Skarels int s = splimp(); /* ??? */ 39537085Skfall 39637578Smckusick if (--cr->cr_ref != 0) { 39737578Smckusick (void) splx(s); 39837578Smckusick return; 39937578Smckusick } 40037578Smckusick FREE((caddr_t)cr, M_CRED); 40137578Smckusick (void) splx(s); 40237578Smckusick } 40337578Smckusick 40437578Smckusick /* 40537578Smckusick * Copy cred structure to a new one and free the old one. 40637578Smckusick */ 40737578Smckusick struct ucred * 40837578Smckusick crcopy(cr) 40937578Smckusick struct ucred *cr; 41037085Skfall { 41137578Smckusick struct ucred *newcr; 41237085Skfall 41345908Sbostic if (cr->cr_ref == 1) 41445908Sbostic return (cr); 41537578Smckusick newcr = crget(); 41637578Smckusick *newcr = *cr; 41737578Smckusick crfree(cr); 41837578Smckusick newcr->cr_ref = 1; 41943393Skarels return (newcr); 42037085Skfall } 42137085Skfall 42237085Skfall /* 42337578Smckusick * Dup cred struct to a new held one. 42437085Skfall */ 42537578Smckusick struct ucred * 42637578Smckusick crdup(cr) 42737578Smckusick struct ucred *cr; 42837085Skfall { 42937578Smckusick struct ucred *newcr; 43037085Skfall 43137578Smckusick newcr = crget(); 43237578Smckusick *newcr = *cr; 43337578Smckusick newcr->cr_ref = 1; 43443393Skarels return (newcr); 43537085Skfall } 43637579Smckusick 43737579Smckusick /* 43840667Skarels * Get login name, if available. 43937579Smckusick */ 44054925Storek struct getlogin_args { 44154925Storek char *namebuf; 44254925Storek u_int namelen; 44354925Storek }; 44443393Skarels /* ARGSUSED */ 44543393Skarels getlogin(p, uap, retval) 44643393Skarels struct proc *p; 44754925Storek struct getlogin_args *uap; 44843393Skarels int *retval; 44943393Skarels { 45037579Smckusick 45147540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 45247540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 45347540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 45447540Skarels (caddr_t) uap->namebuf, uap->namelen)); 45537579Smckusick } 45637579Smckusick 45737579Smckusick /* 45840667Skarels * Set login name. 45937579Smckusick */ 46054925Storek struct setlogin_args { 46154925Storek char *namebuf; 46254925Storek }; 46343393Skarels /* ARGSUSED */ 46443393Skarels setlogin(p, uap, retval) 46543393Skarels struct proc *p; 46654925Storek struct setlogin_args *uap; 46743393Skarels int *retval; 46837579Smckusick { 46940667Skarels int error; 47037579Smckusick 47147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 47244405Skarels return (error); 47347540Skarels error = copyinstr((caddr_t) uap->namebuf, 47447540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 47547540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 47647540Skarels if (error == ENAMETOOLONG) 47740667Skarels error = EINVAL; 47844405Skarels return (error); 47937579Smckusick } 480