123372Smckusick /* 263182Sbostic * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 365799Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 923372Smckusick * 1044439Sbostic * %sccs.include.redist.c% 1137578Smckusick * 12*67875Shibler * @(#)kern_prot.c 8.7 (Berkeley) 11/01/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; 357*67875Shibler union { 358*67875Shibler struct setuid_args sa; 359*67875Shibler struct seteuid_args ea; 360*67875Shibler } args; 36155163Smckusick 36255163Smckusick /* 363*67875Shibler * If ruid == euid then setreuid is being used to emulate setuid, 364*67875Shibler * just do it. 36555163Smckusick */ 366*67875Shibler if (uap->ruid != -1 && uap->ruid == uap->euid) { 367*67875Shibler args.sa.uid = uap->ruid; 368*67875Shibler return (setuid(p, &args.sa, retval)); 369*67875Shibler } 370*67875Shibler /* 371*67875Shibler * Otherwise we assume that the intent of setting ruid is to be 372*67875Shibler * able to get back ruid priviledge (i.e. swapping ruid and euid). 373*67875Shibler * So we make sure that we will be able to do so, but do not 374*67875Shibler * actually set the ruid. 375*67875Shibler */ 37665512Smckusick if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid && 37755163Smckusick uap->ruid != pc->p_svuid) 37855163Smckusick return (EPERM); 37965512Smckusick if (uap->euid == (uid_t)-1) 38055163Smckusick return (0); 381*67875Shibler args.ea.euid = uap->euid; 382*67875Shibler return (seteuid(p, &args.ea, retval)); 38355163Smckusick } 38455163Smckusick 38555163Smckusick struct setregid_args { 38655163Smckusick int rgid; 38755163Smckusick int egid; 38855163Smckusick }; 38955163Smckusick /* ARGSUSED */ 39055163Smckusick osetregid(p, uap, retval) 39155163Smckusick register struct proc *p; 39255163Smckusick struct setregid_args *uap; 39355163Smckusick int *retval; 39455163Smckusick { 39555163Smckusick register struct pcred *pc = p->p_cred; 396*67875Shibler union { 397*67875Shibler struct setgid_args sa; 398*67875Shibler struct setegid_args ea; 399*67875Shibler } args; 40055163Smckusick 40155163Smckusick /* 402*67875Shibler * If rgid == egid then setreuid is being used to emulate setgid, 403*67875Shibler * just do it. 40455163Smckusick */ 405*67875Shibler if (uap->rgid != -1 && uap->rgid == uap->egid) { 406*67875Shibler args.sa.gid = uap->rgid; 407*67875Shibler return (setgid(p, &args.sa, retval)); 408*67875Shibler } 409*67875Shibler /* 410*67875Shibler * Otherwise we assume that the intent of setting rgid is to be 411*67875Shibler * able to get back rgid priviledge (i.e. swapping rgid and egid). 412*67875Shibler * So we make sure that we will be able to do so, but do not 413*67875Shibler * actually set the rgid. 414*67875Shibler */ 41565512Smckusick if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid && 41655163Smckusick uap->rgid != pc->p_svgid) 41755163Smckusick return (EPERM); 41865512Smckusick if (uap->egid == (gid_t)-1) 41955163Smckusick return (0); 420*67875Shibler args.ea.egid = uap->egid; 421*67875Shibler return (setegid(p, &args.ea, retval)); 42255163Smckusick } 42355163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 42455163Smckusick 4257498Sroot /* 42637578Smckusick * Check if gid is a member of the group set. 42711810Ssam */ 42837578Smckusick groupmember(gid, cred) 42926275Skarels gid_t gid; 43037578Smckusick register struct ucred *cred; 4317866Sroot { 43218362Skarels register gid_t *gp; 43337578Smckusick gid_t *egp; 4347866Sroot 43537578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 43637578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4377866Sroot if (*gp == gid) 43837578Smckusick return (1); 43937578Smckusick return (0); 4407866Sroot } 4417866Sroot 44211810Ssam /* 44346293Skarels * Test whether the specified credentials imply "super-user" 44446293Skarels * privilege; if so, and we have accounting info, set the flag 44546293Skarels * indicating use of super-powers. 44646293Skarels * Returns 0 or error. 44711810Ssam */ 44837578Smckusick suser(cred, acflag) 44937578Smckusick struct ucred *cred; 45037578Smckusick short *acflag; 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 { 48165537Sbostic int s; 48237085Skfall 48365537Sbostic s = splimp(); /* ??? */ 48465537Sbostic if (--cr->cr_ref == 0) 48565537Sbostic FREE((caddr_t)cr, M_CRED); 48637578Smckusick (void) splx(s); 48737578Smckusick } 48837578Smckusick 48937578Smckusick /* 49037578Smckusick * Copy cred structure to a new one and free the old one. 49137578Smckusick */ 49237578Smckusick struct ucred * 49337578Smckusick crcopy(cr) 49437578Smckusick struct ucred *cr; 49537085Skfall { 49637578Smckusick struct ucred *newcr; 49737085Skfall 49845908Sbostic if (cr->cr_ref == 1) 49945908Sbostic return (cr); 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 */ 52554925Storek struct getlogin_args { 52654925Storek char *namebuf; 52754925Storek u_int namelen; 52854925Storek }; 52943393Skarels /* ARGSUSED */ 53043393Skarels getlogin(p, uap, retval) 53143393Skarels struct proc *p; 53254925Storek struct getlogin_args *uap; 53343393Skarels int *retval; 53443393Skarels { 53537579Smckusick 53647540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 53747540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 53847540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 53947540Skarels (caddr_t) uap->namebuf, uap->namelen)); 54037579Smckusick } 54137579Smckusick 54237579Smckusick /* 54340667Skarels * Set login name. 54437579Smckusick */ 54554925Storek struct setlogin_args { 54654925Storek char *namebuf; 54754925Storek }; 54843393Skarels /* ARGSUSED */ 54943393Skarels setlogin(p, uap, retval) 55043393Skarels struct proc *p; 55154925Storek struct setlogin_args *uap; 55243393Skarels int *retval; 55337579Smckusick { 55440667Skarels int error; 55537579Smckusick 55647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55744405Skarels return (error); 55847540Skarels error = copyinstr((caddr_t) uap->namebuf, 55947540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 56047540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 56147540Skarels if (error == ENAMETOOLONG) 56240667Skarels error = EINVAL; 56344405Skarels return (error); 56437579Smckusick } 565