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*55403Smckusick * @(#)kern_prot.c 7.28 (Berkeley) 07/19/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; 12055162Smckusick 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; 13855162Smckusick if (error = copyout((caddr_t)pc->pc_ucred->cr_groups, 13955162Smckusick (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 { 20955162Smckusick 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 /* 226*55403Smckusick * Everything's okay, do it. 227*55403Smckusick * Transfer proc count to new user. 228*55403Smckusick * Copy credentials so other references do not see our changes. 22943393Skarels */ 230*55403Smckusick (void)chgproccnt(pc->p_ruid, -1); 231*55403Smckusick (void)chgproccnt(uid, 1); 23247540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 23347540Skarels pc->pc_ucred->cr_uid = uid; 23447540Skarels pc->p_ruid = uid; 23547540Skarels pc->p_svuid = uid; 23654339Smckusick p->p_flag |= SUGID; 23744405Skarels return (0); 23843393Skarels } 23943393Skarels 24054925Storek struct seteuid_args { 24155162Smckusick uid_t euid; 24254925Storek }; 24343393Skarels /* ARGSUSED */ 24443393Skarels seteuid(p, uap, retval) 24547540Skarels struct proc *p; 24654925Storek struct seteuid_args *uap; 24743393Skarels int *retval; 24843393Skarels { 24947540Skarels register struct pcred *pc = p->p_cred; 25043393Skarels register uid_t euid; 25143393Skarels int error; 25243393Skarels 25343393Skarels euid = uap->euid; 25447540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 25547540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 25644405Skarels return (error); 25743393Skarels /* 25845908Sbostic * Everything's okay, do it. Copy credentials so other references do 25945908Sbostic * not see our changes. 26043393Skarels */ 26147540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 26247540Skarels pc->pc_ucred->cr_uid = euid; 26354339Smckusick p->p_flag |= SUGID; 26444405Skarels return (0); 26543393Skarels } 26643393Skarels 26754925Storek struct setgid_args { 26855162Smckusick gid_t gid; 26954925Storek }; 27043393Skarels /* ARGSUSED */ 27143393Skarels setgid(p, uap, retval) 27243393Skarels struct proc *p; 27354925Storek struct setgid_args *uap; 27443393Skarels int *retval; 27543393Skarels { 27647540Skarels register struct pcred *pc = p->p_cred; 27743393Skarels register gid_t gid; 27843393Skarels int error; 27943393Skarels 28043393Skarels gid = uap->gid; 28147540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 28244405Skarels return (error); 28347540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 28447540Skarels pc->pc_ucred->cr_groups[0] = gid; 28547540Skarels pc->p_rgid = gid; 28647540Skarels pc->p_svgid = gid; /* ??? */ 28754339Smckusick p->p_flag |= SUGID; 28844405Skarels return (0); 28943393Skarels } 29043393Skarels 29154925Storek struct setegid_args { 29255162Smckusick gid_t egid; 29354925Storek }; 29443393Skarels /* ARGSUSED */ 29543393Skarels setegid(p, uap, retval) 29643393Skarels struct proc *p; 29754925Storek struct setegid_args *uap; 29843393Skarels int *retval; 29943393Skarels { 30047540Skarels register struct pcred *pc = p->p_cred; 30143393Skarels register gid_t egid; 30243393Skarels int error; 30343393Skarels 30443393Skarels egid = uap->egid; 30547540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 30647540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 30744405Skarels return (error); 30847540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 30947540Skarels pc->pc_ucred->cr_groups[0] = egid; 31054339Smckusick p->p_flag |= SUGID; 31144405Skarels return (0); 31243393Skarels } 31343393Skarels 31454925Storek struct setgroups_args { 31554925Storek u_int gidsetsize; 31655162Smckusick gid_t *gidset; 31754925Storek }; 31843393Skarels /* ARGSUSED */ 31943393Skarels setgroups(p, uap, retval) 32043393Skarels struct proc *p; 32154925Storek struct setgroups_args *uap; 32243393Skarels int *retval; 32343393Skarels { 32447540Skarels register struct pcred *pc = p->p_cred; 32544994Skarels register u_int ngrp; 32655162Smckusick int error; 3277498Sroot 32847540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 32944405Skarels return (error); 33044994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 33144405Skarels return (EINVAL); 33255162Smckusick pc->pc_ucred = crcopy(pc->pc_ucred); 33355162Smckusick if (error = copyin((caddr_t)uap->gidset, 33455162Smckusick (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 33544405Skarels return (error); 33647540Skarels pc->pc_ucred->cr_ngroups = ngrp; 33754339Smckusick p->p_flag |= SUGID; 33844405Skarels return (0); 3397498Sroot } 3407498Sroot 34155163Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 34255163Smckusick struct setreuid_args { 34355163Smckusick int ruid; 34455163Smckusick int euid; 34555163Smckusick }; 34655163Smckusick /* ARGSUSED */ 34755163Smckusick osetreuid(p, uap, retval) 34855163Smckusick register struct proc *p; 34955163Smckusick struct setreuid_args *uap; 35055163Smckusick int *retval; 35155163Smckusick { 35255163Smckusick register struct pcred *pc = p->p_cred; 35355163Smckusick struct seteuid_args args; 35455163Smckusick 35555163Smckusick /* 35655163Smckusick * we assume that the intent of setting ruid is to be able to get 35755163Smckusick * back ruid priviledge. So we make sure that we will be able to 35855163Smckusick * do so, but do not actually set the ruid. 35955163Smckusick */ 36055163Smckusick if (uap->ruid != -1 && uap->ruid != pc->p_ruid && 36155163Smckusick uap->ruid != pc->p_svuid) 36255163Smckusick return (EPERM); 36355163Smckusick if (uap->euid == -1) 36455163Smckusick return (0); 36555163Smckusick args.euid = uap->euid; 36655163Smckusick return (seteuid(p, &args, retval)); 36755163Smckusick } 36855163Smckusick 36955163Smckusick struct setregid_args { 37055163Smckusick int rgid; 37155163Smckusick int egid; 37255163Smckusick }; 37355163Smckusick /* ARGSUSED */ 37455163Smckusick osetregid(p, uap, retval) 37555163Smckusick register struct proc *p; 37655163Smckusick struct setregid_args *uap; 37755163Smckusick int *retval; 37855163Smckusick { 37955163Smckusick register struct pcred *pc = p->p_cred; 38055163Smckusick struct setegid_args args; 38155163Smckusick 38255163Smckusick /* 38355163Smckusick * we assume that the intent of setting rgid is to be able to get 38455163Smckusick * back rgid priviledge. So we make sure that we will be able to 38555163Smckusick * do so, but do not actually set the rgid. 38655163Smckusick */ 38755163Smckusick if (uap->rgid != -1 && uap->rgid != pc->p_rgid && 38855163Smckusick uap->rgid != pc->p_svgid) 38955163Smckusick return (EPERM); 39055163Smckusick if (uap->egid == -1) 39155163Smckusick return (0); 39255163Smckusick args.egid = uap->egid; 39355163Smckusick return (setegid(p, &args, retval)); 39455163Smckusick } 39555163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 39655163Smckusick 3977498Sroot /* 39837578Smckusick * Check if gid is a member of the group set. 39911810Ssam */ 40037578Smckusick groupmember(gid, cred) 40126275Skarels gid_t gid; 40237578Smckusick register struct ucred *cred; 4037866Sroot { 40418362Skarels register gid_t *gp; 40537578Smckusick gid_t *egp; 4067866Sroot 40737578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 40837578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4097866Sroot if (*gp == gid) 41037578Smckusick return (1); 41137578Smckusick return (0); 4127866Sroot } 4137866Sroot 41411810Ssam /* 41546293Skarels * Test whether the specified credentials imply "super-user" 41646293Skarels * privilege; if so, and we have accounting info, set the flag 41746293Skarels * indicating use of super-powers. 41846293Skarels * Returns 0 or error. 41911810Ssam */ 42037578Smckusick suser(cred, acflag) 42137578Smckusick struct ucred *cred; 42237578Smckusick short *acflag; 4237866Sroot { 42437578Smckusick if (cred->cr_uid == 0) { 42537578Smckusick if (acflag) 42637578Smckusick *acflag |= ASU; 42737578Smckusick return (0); 42818362Skarels } 42937578Smckusick return (EPERM); 4307866Sroot } 43111810Ssam 43211810Ssam /* 43337578Smckusick * Allocate a zeroed cred structure. 43411810Ssam */ 43537578Smckusick struct ucred * 43637578Smckusick crget() 43711810Ssam { 43837578Smckusick register struct ucred *cr; 43911810Ssam 44037578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 44137578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 44237578Smckusick cr->cr_ref = 1; 44343393Skarels return (cr); 44411810Ssam } 44537085Skfall 44637085Skfall /* 44737578Smckusick * Free a cred structure. 44837578Smckusick * Throws away space when ref count gets to 0. 44937085Skfall */ 45037578Smckusick crfree(cr) 45137578Smckusick struct ucred *cr; 45237578Smckusick { 45347540Skarels int s = splimp(); /* ??? */ 45437085Skfall 45537578Smckusick if (--cr->cr_ref != 0) { 45637578Smckusick (void) splx(s); 45737578Smckusick return; 45837578Smckusick } 45937578Smckusick FREE((caddr_t)cr, M_CRED); 46037578Smckusick (void) splx(s); 46137578Smckusick } 46237578Smckusick 46337578Smckusick /* 46437578Smckusick * Copy cred structure to a new one and free the old one. 46537578Smckusick */ 46637578Smckusick struct ucred * 46737578Smckusick crcopy(cr) 46837578Smckusick struct ucred *cr; 46937085Skfall { 47037578Smckusick struct ucred *newcr; 47137085Skfall 47245908Sbostic if (cr->cr_ref == 1) 47345908Sbostic return (cr); 47437578Smckusick newcr = crget(); 47537578Smckusick *newcr = *cr; 47637578Smckusick crfree(cr); 47737578Smckusick newcr->cr_ref = 1; 47843393Skarels return (newcr); 47937085Skfall } 48037085Skfall 48137085Skfall /* 48237578Smckusick * Dup cred struct to a new held one. 48337085Skfall */ 48437578Smckusick struct ucred * 48537578Smckusick crdup(cr) 48637578Smckusick struct ucred *cr; 48737085Skfall { 48837578Smckusick struct ucred *newcr; 48937085Skfall 49037578Smckusick newcr = crget(); 49137578Smckusick *newcr = *cr; 49237578Smckusick newcr->cr_ref = 1; 49343393Skarels return (newcr); 49437085Skfall } 49537579Smckusick 49637579Smckusick /* 49740667Skarels * Get login name, if available. 49837579Smckusick */ 49954925Storek struct getlogin_args { 50054925Storek char *namebuf; 50154925Storek u_int namelen; 50254925Storek }; 50343393Skarels /* ARGSUSED */ 50443393Skarels getlogin(p, uap, retval) 50543393Skarels struct proc *p; 50654925Storek struct getlogin_args *uap; 50743393Skarels int *retval; 50843393Skarels { 50937579Smckusick 51047540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 51147540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 51247540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 51347540Skarels (caddr_t) uap->namebuf, uap->namelen)); 51437579Smckusick } 51537579Smckusick 51637579Smckusick /* 51740667Skarels * Set login name. 51837579Smckusick */ 51954925Storek struct setlogin_args { 52054925Storek char *namebuf; 52154925Storek }; 52243393Skarels /* ARGSUSED */ 52343393Skarels setlogin(p, uap, retval) 52443393Skarels struct proc *p; 52554925Storek struct setlogin_args *uap; 52643393Skarels int *retval; 52737579Smckusick { 52840667Skarels int error; 52937579Smckusick 53047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 53144405Skarels return (error); 53247540Skarels error = copyinstr((caddr_t) uap->namebuf, 53347540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 53447540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 53547540Skarels if (error == ENAMETOOLONG) 53640667Skarels error = EINVAL; 53744405Skarels return (error); 53837579Smckusick } 539