123372Smckusick /* 263182Sbostic * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 363182Sbostic * Regents of the University of California. All rights reserved. 4*65771Sbostic * (c) UNIX System Laboratories, Inc. 5*65771Sbostic * All or some portions of this file are derived from material licensed 6*65771Sbostic * to the University of California by American Telephone and Telegraph 7*65771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8*65771Sbostic * the permission of UNIX System Laboratories, Inc. 923372Smckusick * 1044439Sbostic * %sccs.include.redist.c% 1137578Smckusick * 12*65771Sbostic * @(#)kern_prot.c 8.5 (Berkeley) 01/21/94 1323372Smckusick */ 147420Sroot 157420Sroot /* 167498Sroot * System calls related to processes and protection 177420Sroot */ 187420Sroot 1957048Smckusick #include <sys/param.h> 2057048Smckusick #include <sys/acct.h> 2157048Smckusick #include <sys/systm.h> 2257048Smckusick #include <sys/ucred.h> 2357048Smckusick #include <sys/proc.h> 2457048Smckusick #include <sys/timeb.h> 2557048Smckusick #include <sys/times.h> 2657048Smckusick #include <sys/malloc.h> 277420Sroot 2854925Storek struct args { 2954925Storek int dummy; 3054925Storek }; 3154925Storek 3243393Skarels /* ARGSUSED */ 3343393Skarels getpid(p, uap, retval) 3443393Skarels struct proc *p; 3554925Storek struct args *uap; 3643393Skarels int *retval; 3743393Skarels { 3837579Smckusick 3943393Skarels *retval = p->p_pid; 4052495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 4147540Skarels retval[1] = p->p_pptr->p_pid; 4243393Skarels #endif 4344405Skarels return (0); 4443393Skarels } 4543393Skarels 4643393Skarels /* ARGSUSED */ 4743393Skarels getppid(p, uap, retval) 4843393Skarels struct proc *p; 4954925Storek struct args *uap; 5043393Skarels int *retval; 517498Sroot { 527498Sroot 5347540Skarels *retval = p->p_pptr->p_pid; 5444405Skarels return (0); 557498Sroot } 567498Sroot 5747540Skarels /* Get process group ID; note that POSIX getpgrp takes no parameter */ 5843393Skarels getpgrp(p, uap, retval) 5943393Skarels struct proc *p; 6054925Storek struct args *uap; 6143393Skarels int *retval; 627498Sroot { 637498Sroot 6443393Skarels *retval = p->p_pgrp->pg_id; 6544405Skarels return (0); 667498Sroot } 677498Sroot 6843393Skarels /* ARGSUSED */ 6943393Skarels getuid(p, uap, retval) 7043393Skarels struct proc *p; 7154925Storek struct args *uap; 7243393Skarels int *retval; 737420Sroot { 747420Sroot 7547540Skarels *retval = p->p_cred->p_ruid; 7652495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 7747540Skarels retval[1] = p->p_ucred->cr_uid; 7843393Skarels #endif 7944405Skarels return (0); 807420Sroot } 817420Sroot 8243393Skarels /* ARGSUSED */ 8343393Skarels geteuid(p, uap, retval) 8443393Skarels struct proc *p; 8554925Storek struct args *uap; 8643393Skarels int *retval; 877498Sroot { 887498Sroot 8947540Skarels *retval = p->p_ucred->cr_uid; 9044405Skarels return (0); 917498Sroot } 927498Sroot 9343393Skarels /* ARGSUSED */ 9443393Skarels getgid(p, uap, retval) 9543393Skarels struct proc *p; 9654925Storek struct args *uap; 9743393Skarels int *retval; 987498Sroot { 9943393Skarels 10047540Skarels *retval = p->p_cred->p_rgid; 10152495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10247540Skarels retval[1] = p->p_ucred->cr_groups[0]; 10343393Skarels #endif 10444405Skarels return (0); 10543393Skarels } 10643393Skarels 10743393Skarels /* 10845908Sbostic * Get effective group ID. The "egid" is groups[0], and could be obtained 10945908Sbostic * via getgroups. This syscall exists because it is somewhat painful to do 11045908Sbostic * correctly in a library function. 11143393Skarels */ 11243393Skarels /* ARGSUSED */ 11343393Skarels getegid(p, uap, retval) 11443393Skarels struct proc *p; 11554925Storek struct args *uap; 11643393Skarels int *retval; 11743393Skarels { 11847540Skarels 11947540Skarels *retval = p->p_ucred->cr_groups[0]; 12044405Skarels return (0); 12143393Skarels } 12243393Skarels 12354925Storek struct getgroups_args { 12454925Storek u_int gidsetsize; 12555162Smckusick gid_t *gidset; 12654925Storek }; 12743393Skarels getgroups(p, uap, retval) 12843393Skarels struct proc *p; 12954925Storek register struct getgroups_args *uap; 13043393Skarels int *retval; 13143393Skarels { 13247540Skarels register struct pcred *pc = p->p_cred; 13344994Skarels register u_int ngrp; 13443393Skarels int error; 1357498Sroot 13644994Skarels if ((ngrp = uap->gidsetsize) == 0) { 13747540Skarels *retval = pc->pc_ucred->cr_ngroups; 13844405Skarels return (0); 13937578Smckusick } 14047540Skarels if (ngrp < pc->pc_ucred->cr_ngroups) 14144405Skarels return (EINVAL); 14247540Skarels ngrp = pc->pc_ucred->cr_ngroups; 14355162Smckusick if (error = copyout((caddr_t)pc->pc_ucred->cr_groups, 14455162Smckusick (caddr_t)uap->gidset, ngrp * sizeof(gid_t))) 14544405Skarels return (error); 14644994Skarels *retval = ngrp; 14744405Skarels return (0); 1487498Sroot } 1497498Sroot 15043393Skarels /* ARGSUSED */ 15143393Skarels setsid(p, uap, retval) 15247540Skarels register struct proc *p; 15354925Storek struct args *uap; 15443393Skarels int *retval; 15537579Smckusick { 15637579Smckusick 15743393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 15844405Skarels return (EPERM); 15943393Skarels } else { 16057049Smarc (void)enterpgrp(p, p->p_pid, 1); 16143393Skarels *retval = p->p_pid; 16244405Skarels return (0); 16337579Smckusick } 16437579Smckusick } 16537579Smckusick 16637579Smckusick /* 16747540Skarels * set process group (setpgid/old setpgrp) 16837579Smckusick * 16947972Smarc * caller does setpgid(targpid, targpgid) 17040667Skarels * 17140667Skarels * pid must be caller or child of caller (ESRCH) 17240667Skarels * if a child 17340667Skarels * pid must be in same session (EPERM) 17440667Skarels * pid can't have done an exec (EACCES) 17540667Skarels * if pgid != pid 17640667Skarels * there must exist some pid in same session having pgid (EPERM) 17740667Skarels * pid must not be session leader (EPERM) 17837579Smckusick */ 17954925Storek struct setpgid_args { 18054925Storek int pid; /* target process id */ 18154925Storek int pgid; /* target pgrp id */ 18254925Storek }; 18343393Skarels /* ARGSUSED */ 18447972Smarc setpgid(curp, uap, retval) 18547972Smarc struct proc *curp; 18654925Storek register struct setpgid_args *uap; 18743393Skarels int *retval; 18843393Skarels { 18947972Smarc register struct proc *targp; /* target process */ 19048990Skarels register struct pgrp *pgrp; /* target pgrp */ 1917498Sroot 19248990Skarels if (uap->pid != 0 && uap->pid != curp->p_pid) { 19348990Skarels if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 19444405Skarels return (ESRCH); 19547972Smarc if (targp->p_session != curp->p_session) 19644405Skarels return (EPERM); 19764586Sbostic if (targp->p_flag & P_EXEC) 19844405Skarels return (EACCES); 19943393Skarels } else 20047972Smarc targp = curp; 20147972Smarc if (SESS_LEADER(targp)) 20244405Skarels return (EPERM); 20348990Skarels if (uap->pgid == 0) 20448990Skarels uap->pgid = targp->p_pid; 20548990Skarels else if (uap->pgid != targp->p_pid) 20648990Skarels if ((pgrp = pgfind(uap->pgid)) == 0 || 20748990Skarels pgrp->pg_session != curp->p_session) 20845908Sbostic return (EPERM); 20957049Smarc return (enterpgrp(targp, uap->pgid, 0)); 2107498Sroot } 2117498Sroot 21254925Storek struct setuid_args { 21355162Smckusick uid_t uid; 21454925Storek }; 21543393Skarels /* ARGSUSED */ 21643393Skarels setuid(p, uap, retval) 21747540Skarels struct proc *p; 21854925Storek struct setuid_args *uap; 21943393Skarels int *retval; 2207420Sroot { 22147540Skarels register struct pcred *pc = p->p_cred; 22243393Skarels register uid_t uid; 22343393Skarels int error; 22443393Skarels 22543393Skarels uid = uap->uid; 22647540Skarels if (uid != pc->p_ruid && 22747540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 22844405Skarels return (error); 22943393Skarels /* 23055403Smckusick * Everything's okay, do it. 23155403Smckusick * Transfer proc count to new user. 23255403Smckusick * Copy credentials so other references do not see our changes. 23343393Skarels */ 23455403Smckusick (void)chgproccnt(pc->p_ruid, -1); 23555403Smckusick (void)chgproccnt(uid, 1); 23647540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 23747540Skarels pc->pc_ucred->cr_uid = uid; 23847540Skarels pc->p_ruid = uid; 23947540Skarels pc->p_svuid = uid; 24064586Sbostic p->p_flag |= P_SUGID; 24144405Skarels return (0); 24243393Skarels } 24343393Skarels 24454925Storek struct seteuid_args { 24555162Smckusick uid_t euid; 24654925Storek }; 24743393Skarels /* ARGSUSED */ 24843393Skarels seteuid(p, uap, retval) 24947540Skarels struct proc *p; 25054925Storek struct seteuid_args *uap; 25143393Skarels int *retval; 25243393Skarels { 25347540Skarels register struct pcred *pc = p->p_cred; 25443393Skarels register uid_t euid; 25543393Skarels int error; 25643393Skarels 25743393Skarels euid = uap->euid; 25847540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 25947540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 26044405Skarels return (error); 26143393Skarels /* 26245908Sbostic * Everything's okay, do it. Copy credentials so other references do 26345908Sbostic * not see our changes. 26443393Skarels */ 26547540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 26647540Skarels pc->pc_ucred->cr_uid = euid; 26764586Sbostic p->p_flag |= P_SUGID; 26844405Skarels return (0); 26943393Skarels } 27043393Skarels 27154925Storek struct setgid_args { 27255162Smckusick gid_t gid; 27354925Storek }; 27443393Skarels /* ARGSUSED */ 27543393Skarels setgid(p, uap, retval) 27643393Skarels struct proc *p; 27754925Storek struct setgid_args *uap; 27843393Skarels int *retval; 27943393Skarels { 28047540Skarels register struct pcred *pc = p->p_cred; 28143393Skarels register gid_t gid; 28243393Skarels int error; 28343393Skarels 28443393Skarels gid = uap->gid; 28547540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 28644405Skarels return (error); 28747540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 28847540Skarels pc->pc_ucred->cr_groups[0] = gid; 28947540Skarels pc->p_rgid = gid; 29047540Skarels pc->p_svgid = gid; /* ??? */ 29164586Sbostic p->p_flag |= P_SUGID; 29244405Skarels return (0); 29343393Skarels } 29443393Skarels 29554925Storek struct setegid_args { 29655162Smckusick gid_t egid; 29754925Storek }; 29843393Skarels /* ARGSUSED */ 29943393Skarels setegid(p, uap, retval) 30043393Skarels struct proc *p; 30154925Storek struct setegid_args *uap; 30243393Skarels int *retval; 30343393Skarels { 30447540Skarels register struct pcred *pc = p->p_cred; 30543393Skarels register gid_t egid; 30643393Skarels int error; 30743393Skarels 30843393Skarels egid = uap->egid; 30947540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 31047540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 31144405Skarels return (error); 31247540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 31347540Skarels pc->pc_ucred->cr_groups[0] = egid; 31464586Sbostic p->p_flag |= P_SUGID; 31544405Skarels return (0); 31643393Skarels } 31743393Skarels 31854925Storek struct setgroups_args { 31954925Storek u_int gidsetsize; 32055162Smckusick gid_t *gidset; 32154925Storek }; 32243393Skarels /* ARGSUSED */ 32343393Skarels setgroups(p, uap, retval) 32443393Skarels struct proc *p; 32554925Storek struct setgroups_args *uap; 32643393Skarels int *retval; 32743393Skarels { 32847540Skarels register struct pcred *pc = p->p_cred; 32944994Skarels register u_int ngrp; 33055162Smckusick int error; 3317498Sroot 33247540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 33344405Skarels return (error); 33444994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 33544405Skarels return (EINVAL); 33655162Smckusick pc->pc_ucred = crcopy(pc->pc_ucred); 33755162Smckusick if (error = copyin((caddr_t)uap->gidset, 33855162Smckusick (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 33944405Skarels return (error); 34047540Skarels pc->pc_ucred->cr_ngroups = ngrp; 34164586Sbostic p->p_flag |= P_SUGID; 34244405Skarels return (0); 3437498Sroot } 3447498Sroot 34555163Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 34655163Smckusick struct setreuid_args { 34755163Smckusick int ruid; 34855163Smckusick int euid; 34955163Smckusick }; 35055163Smckusick /* ARGSUSED */ 35155163Smckusick osetreuid(p, uap, retval) 35255163Smckusick register struct proc *p; 35355163Smckusick struct setreuid_args *uap; 35455163Smckusick int *retval; 35555163Smckusick { 35655163Smckusick register struct pcred *pc = p->p_cred; 35755163Smckusick struct seteuid_args args; 35855163Smckusick 35955163Smckusick /* 36055163Smckusick * we assume that the intent of setting ruid is to be able to get 36155163Smckusick * back ruid priviledge. So we make sure that we will be able to 36255163Smckusick * do so, but do not actually set the ruid. 36355163Smckusick */ 36465512Smckusick if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid && 36555163Smckusick uap->ruid != pc->p_svuid) 36655163Smckusick return (EPERM); 36765512Smckusick if (uap->euid == (uid_t)-1) 36855163Smckusick return (0); 36955163Smckusick args.euid = uap->euid; 37055163Smckusick return (seteuid(p, &args, retval)); 37155163Smckusick } 37255163Smckusick 37355163Smckusick struct setregid_args { 37455163Smckusick int rgid; 37555163Smckusick int egid; 37655163Smckusick }; 37755163Smckusick /* ARGSUSED */ 37855163Smckusick osetregid(p, uap, retval) 37955163Smckusick register struct proc *p; 38055163Smckusick struct setregid_args *uap; 38155163Smckusick int *retval; 38255163Smckusick { 38355163Smckusick register struct pcred *pc = p->p_cred; 38455163Smckusick struct setegid_args args; 38555163Smckusick 38655163Smckusick /* 38755163Smckusick * we assume that the intent of setting rgid is to be able to get 38855163Smckusick * back rgid priviledge. So we make sure that we will be able to 38955163Smckusick * do so, but do not actually set the rgid. 39055163Smckusick */ 39165512Smckusick if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid && 39255163Smckusick uap->rgid != pc->p_svgid) 39355163Smckusick return (EPERM); 39465512Smckusick if (uap->egid == (gid_t)-1) 39555163Smckusick return (0); 39655163Smckusick args.egid = uap->egid; 39755163Smckusick return (setegid(p, &args, retval)); 39855163Smckusick } 39955163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 40055163Smckusick 4017498Sroot /* 40237578Smckusick * Check if gid is a member of the group set. 40311810Ssam */ 40437578Smckusick groupmember(gid, cred) 40526275Skarels gid_t gid; 40637578Smckusick register struct ucred *cred; 4077866Sroot { 40818362Skarels register gid_t *gp; 40937578Smckusick gid_t *egp; 4107866Sroot 41137578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 41237578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4137866Sroot if (*gp == gid) 41437578Smckusick return (1); 41537578Smckusick return (0); 4167866Sroot } 4177866Sroot 41811810Ssam /* 41946293Skarels * Test whether the specified credentials imply "super-user" 42046293Skarels * privilege; if so, and we have accounting info, set the flag 42146293Skarels * indicating use of super-powers. 42246293Skarels * Returns 0 or error. 42311810Ssam */ 42437578Smckusick suser(cred, acflag) 42537578Smckusick struct ucred *cred; 42637578Smckusick short *acflag; 4277866Sroot { 42837578Smckusick if (cred->cr_uid == 0) { 42937578Smckusick if (acflag) 43037578Smckusick *acflag |= ASU; 43137578Smckusick return (0); 43218362Skarels } 43337578Smckusick return (EPERM); 4347866Sroot } 43511810Ssam 43611810Ssam /* 43737578Smckusick * Allocate a zeroed cred structure. 43811810Ssam */ 43937578Smckusick struct ucred * 44037578Smckusick crget() 44111810Ssam { 44237578Smckusick register struct ucred *cr; 44311810Ssam 44437578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 44537578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 44637578Smckusick cr->cr_ref = 1; 44743393Skarels return (cr); 44811810Ssam } 44937085Skfall 45037085Skfall /* 45137578Smckusick * Free a cred structure. 45237578Smckusick * Throws away space when ref count gets to 0. 45337085Skfall */ 45437578Smckusick crfree(cr) 45537578Smckusick struct ucred *cr; 45637578Smckusick { 45765537Sbostic int s; 45837085Skfall 45965537Sbostic s = splimp(); /* ??? */ 46065537Sbostic if (--cr->cr_ref == 0) 46165537Sbostic FREE((caddr_t)cr, M_CRED); 46237578Smckusick (void) splx(s); 46337578Smckusick } 46437578Smckusick 46537578Smckusick /* 46637578Smckusick * Copy cred structure to a new one and free the old one. 46737578Smckusick */ 46837578Smckusick struct ucred * 46937578Smckusick crcopy(cr) 47037578Smckusick struct ucred *cr; 47137085Skfall { 47237578Smckusick struct ucred *newcr; 47337085Skfall 47445908Sbostic if (cr->cr_ref == 1) 47545908Sbostic return (cr); 47637578Smckusick newcr = crget(); 47737578Smckusick *newcr = *cr; 47837578Smckusick crfree(cr); 47937578Smckusick newcr->cr_ref = 1; 48043393Skarels return (newcr); 48137085Skfall } 48237085Skfall 48337085Skfall /* 48437578Smckusick * Dup cred struct to a new held one. 48537085Skfall */ 48637578Smckusick struct ucred * 48737578Smckusick crdup(cr) 48837578Smckusick struct ucred *cr; 48937085Skfall { 49037578Smckusick struct ucred *newcr; 49137085Skfall 49237578Smckusick newcr = crget(); 49337578Smckusick *newcr = *cr; 49437578Smckusick newcr->cr_ref = 1; 49543393Skarels return (newcr); 49637085Skfall } 49737579Smckusick 49837579Smckusick /* 49940667Skarels * Get login name, if available. 50037579Smckusick */ 50154925Storek struct getlogin_args { 50254925Storek char *namebuf; 50354925Storek u_int namelen; 50454925Storek }; 50543393Skarels /* ARGSUSED */ 50643393Skarels getlogin(p, uap, retval) 50743393Skarels struct proc *p; 50854925Storek struct getlogin_args *uap; 50943393Skarels int *retval; 51043393Skarels { 51137579Smckusick 51247540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 51347540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 51447540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 51547540Skarels (caddr_t) uap->namebuf, uap->namelen)); 51637579Smckusick } 51737579Smckusick 51837579Smckusick /* 51940667Skarels * Set login name. 52037579Smckusick */ 52154925Storek struct setlogin_args { 52254925Storek char *namebuf; 52354925Storek }; 52443393Skarels /* ARGSUSED */ 52543393Skarels setlogin(p, uap, retval) 52643393Skarels struct proc *p; 52754925Storek struct setlogin_args *uap; 52843393Skarels int *retval; 52937579Smckusick { 53040667Skarels int error; 53137579Smckusick 53247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 53344405Skarels return (error); 53447540Skarels error = copyinstr((caddr_t) uap->namebuf, 53547540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 53647540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 53747540Skarels if (error == ENAMETOOLONG) 53840667Skarels error = EINVAL; 53944405Skarels return (error); 54037579Smckusick } 541