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*57049Smarc * @(#)kern_prot.c 7.30 (Berkeley) 12/09/92 823372Smckusick */ 97420Sroot 107420Sroot /* 117498Sroot * System calls related to processes and protection 127420Sroot */ 137420Sroot 1457048Smckusick #include <sys/param.h> 1557048Smckusick #include <sys/acct.h> 1657048Smckusick #include <sys/systm.h> 1757048Smckusick #include <sys/ucred.h> 1857048Smckusick #include <sys/proc.h> 1957048Smckusick #include <sys/timeb.h> 2057048Smckusick #include <sys/times.h> 2157048Smckusick #include <sys/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 { 155*57049Smarc (void)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); 204*57049Smarc return (enterpgrp(targp, uap->pgid, 0)); 2057498Sroot } 2067498Sroot 20754925Storek struct setuid_args { 20855162Smckusick uid_t uid; 20954925Storek }; 21043393Skarels /* ARGSUSED */ 21143393Skarels setuid(p, uap, retval) 21247540Skarels struct proc *p; 21354925Storek struct setuid_args *uap; 21443393Skarels int *retval; 2157420Sroot { 21647540Skarels register struct pcred *pc = p->p_cred; 21743393Skarels register uid_t uid; 21843393Skarels int error; 21943393Skarels 22043393Skarels uid = uap->uid; 22147540Skarels if (uid != pc->p_ruid && 22247540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 22344405Skarels return (error); 22443393Skarels /* 22555403Smckusick * Everything's okay, do it. 22655403Smckusick * Transfer proc count to new user. 22755403Smckusick * Copy credentials so other references do not see our changes. 22843393Skarels */ 22955403Smckusick (void)chgproccnt(pc->p_ruid, -1); 23055403Smckusick (void)chgproccnt(uid, 1); 23147540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 23247540Skarels pc->pc_ucred->cr_uid = uid; 23347540Skarels pc->p_ruid = uid; 23447540Skarels pc->p_svuid = uid; 23554339Smckusick p->p_flag |= SUGID; 23644405Skarels return (0); 23743393Skarels } 23843393Skarels 23954925Storek struct seteuid_args { 24055162Smckusick uid_t euid; 24154925Storek }; 24243393Skarels /* ARGSUSED */ 24343393Skarels seteuid(p, uap, retval) 24447540Skarels struct proc *p; 24554925Storek struct seteuid_args *uap; 24643393Skarels int *retval; 24743393Skarels { 24847540Skarels register struct pcred *pc = p->p_cred; 24943393Skarels register uid_t euid; 25043393Skarels int error; 25143393Skarels 25243393Skarels euid = uap->euid; 25347540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 25447540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 25544405Skarels return (error); 25643393Skarels /* 25745908Sbostic * Everything's okay, do it. Copy credentials so other references do 25845908Sbostic * not see our changes. 25943393Skarels */ 26047540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 26147540Skarels pc->pc_ucred->cr_uid = euid; 26254339Smckusick p->p_flag |= SUGID; 26344405Skarels return (0); 26443393Skarels } 26543393Skarels 26654925Storek struct setgid_args { 26755162Smckusick gid_t gid; 26854925Storek }; 26943393Skarels /* ARGSUSED */ 27043393Skarels setgid(p, uap, retval) 27143393Skarels struct proc *p; 27254925Storek struct setgid_args *uap; 27343393Skarels int *retval; 27443393Skarels { 27547540Skarels register struct pcred *pc = p->p_cred; 27643393Skarels register gid_t gid; 27743393Skarels int error; 27843393Skarels 27943393Skarels gid = uap->gid; 28047540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 28144405Skarels return (error); 28247540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 28347540Skarels pc->pc_ucred->cr_groups[0] = gid; 28447540Skarels pc->p_rgid = gid; 28547540Skarels pc->p_svgid = gid; /* ??? */ 28654339Smckusick p->p_flag |= SUGID; 28744405Skarels return (0); 28843393Skarels } 28943393Skarels 29054925Storek struct setegid_args { 29155162Smckusick gid_t egid; 29254925Storek }; 29343393Skarels /* ARGSUSED */ 29443393Skarels setegid(p, uap, retval) 29543393Skarels struct proc *p; 29654925Storek struct setegid_args *uap; 29743393Skarels int *retval; 29843393Skarels { 29947540Skarels register struct pcred *pc = p->p_cred; 30043393Skarels register gid_t egid; 30143393Skarels int error; 30243393Skarels 30343393Skarels egid = uap->egid; 30447540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 30547540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 30644405Skarels return (error); 30747540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 30847540Skarels pc->pc_ucred->cr_groups[0] = egid; 30954339Smckusick p->p_flag |= SUGID; 31044405Skarels return (0); 31143393Skarels } 31243393Skarels 31354925Storek struct setgroups_args { 31454925Storek u_int gidsetsize; 31555162Smckusick gid_t *gidset; 31654925Storek }; 31743393Skarels /* ARGSUSED */ 31843393Skarels setgroups(p, uap, retval) 31943393Skarels struct proc *p; 32054925Storek struct setgroups_args *uap; 32143393Skarels int *retval; 32243393Skarels { 32347540Skarels register struct pcred *pc = p->p_cred; 32444994Skarels register u_int ngrp; 32555162Smckusick int error; 3267498Sroot 32747540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 32844405Skarels return (error); 32944994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 33044405Skarels return (EINVAL); 33155162Smckusick pc->pc_ucred = crcopy(pc->pc_ucred); 33255162Smckusick if (error = copyin((caddr_t)uap->gidset, 33355162Smckusick (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 33444405Skarels return (error); 33547540Skarels pc->pc_ucred->cr_ngroups = ngrp; 33654339Smckusick p->p_flag |= SUGID; 33744405Skarels return (0); 3387498Sroot } 3397498Sroot 34055163Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 34155163Smckusick struct setreuid_args { 34255163Smckusick int ruid; 34355163Smckusick int euid; 34455163Smckusick }; 34555163Smckusick /* ARGSUSED */ 34655163Smckusick osetreuid(p, uap, retval) 34755163Smckusick register struct proc *p; 34855163Smckusick struct setreuid_args *uap; 34955163Smckusick int *retval; 35055163Smckusick { 35155163Smckusick register struct pcred *pc = p->p_cred; 35255163Smckusick struct seteuid_args args; 35355163Smckusick 35455163Smckusick /* 35555163Smckusick * we assume that the intent of setting ruid is to be able to get 35655163Smckusick * back ruid priviledge. So we make sure that we will be able to 35755163Smckusick * do so, but do not actually set the ruid. 35855163Smckusick */ 35955163Smckusick if (uap->ruid != -1 && uap->ruid != pc->p_ruid && 36055163Smckusick uap->ruid != pc->p_svuid) 36155163Smckusick return (EPERM); 36255163Smckusick if (uap->euid == -1) 36355163Smckusick return (0); 36455163Smckusick args.euid = uap->euid; 36555163Smckusick return (seteuid(p, &args, retval)); 36655163Smckusick } 36755163Smckusick 36855163Smckusick struct setregid_args { 36955163Smckusick int rgid; 37055163Smckusick int egid; 37155163Smckusick }; 37255163Smckusick /* ARGSUSED */ 37355163Smckusick osetregid(p, uap, retval) 37455163Smckusick register struct proc *p; 37555163Smckusick struct setregid_args *uap; 37655163Smckusick int *retval; 37755163Smckusick { 37855163Smckusick register struct pcred *pc = p->p_cred; 37955163Smckusick struct setegid_args args; 38055163Smckusick 38155163Smckusick /* 38255163Smckusick * we assume that the intent of setting rgid is to be able to get 38355163Smckusick * back rgid priviledge. So we make sure that we will be able to 38455163Smckusick * do so, but do not actually set the rgid. 38555163Smckusick */ 38655163Smckusick if (uap->rgid != -1 && uap->rgid != pc->p_rgid && 38755163Smckusick uap->rgid != pc->p_svgid) 38855163Smckusick return (EPERM); 38955163Smckusick if (uap->egid == -1) 39055163Smckusick return (0); 39155163Smckusick args.egid = uap->egid; 39255163Smckusick return (setegid(p, &args, retval)); 39355163Smckusick } 39455163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 39555163Smckusick 3967498Sroot /* 39737578Smckusick * Check if gid is a member of the group set. 39811810Ssam */ 39937578Smckusick groupmember(gid, cred) 40026275Skarels gid_t gid; 40137578Smckusick register struct ucred *cred; 4027866Sroot { 40318362Skarels register gid_t *gp; 40437578Smckusick gid_t *egp; 4057866Sroot 40637578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 40737578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4087866Sroot if (*gp == gid) 40937578Smckusick return (1); 41037578Smckusick return (0); 4117866Sroot } 4127866Sroot 41311810Ssam /* 41446293Skarels * Test whether the specified credentials imply "super-user" 41546293Skarels * privilege; if so, and we have accounting info, set the flag 41646293Skarels * indicating use of super-powers. 41746293Skarels * Returns 0 or error. 41811810Ssam */ 41937578Smckusick suser(cred, acflag) 42037578Smckusick struct ucred *cred; 42137578Smckusick short *acflag; 4227866Sroot { 42337578Smckusick if (cred->cr_uid == 0) { 42437578Smckusick if (acflag) 42537578Smckusick *acflag |= ASU; 42637578Smckusick return (0); 42718362Skarels } 42837578Smckusick return (EPERM); 4297866Sroot } 43011810Ssam 43111810Ssam /* 43237578Smckusick * Allocate a zeroed cred structure. 43311810Ssam */ 43437578Smckusick struct ucred * 43537578Smckusick crget() 43611810Ssam { 43737578Smckusick register struct ucred *cr; 43811810Ssam 43937578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 44037578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 44137578Smckusick cr->cr_ref = 1; 44243393Skarels return (cr); 44311810Ssam } 44437085Skfall 44537085Skfall /* 44637578Smckusick * Free a cred structure. 44737578Smckusick * Throws away space when ref count gets to 0. 44837085Skfall */ 44937578Smckusick crfree(cr) 45037578Smckusick struct ucred *cr; 45137578Smckusick { 45247540Skarels int s = splimp(); /* ??? */ 45337085Skfall 45437578Smckusick if (--cr->cr_ref != 0) { 45537578Smckusick (void) splx(s); 45637578Smckusick return; 45737578Smckusick } 45837578Smckusick FREE((caddr_t)cr, M_CRED); 45937578Smckusick (void) splx(s); 46037578Smckusick } 46137578Smckusick 46237578Smckusick /* 46337578Smckusick * Copy cred structure to a new one and free the old one. 46437578Smckusick */ 46537578Smckusick struct ucred * 46637578Smckusick crcopy(cr) 46737578Smckusick struct ucred *cr; 46837085Skfall { 46937578Smckusick struct ucred *newcr; 47037085Skfall 47145908Sbostic if (cr->cr_ref == 1) 47245908Sbostic return (cr); 47337578Smckusick newcr = crget(); 47437578Smckusick *newcr = *cr; 47537578Smckusick crfree(cr); 47637578Smckusick newcr->cr_ref = 1; 47743393Skarels return (newcr); 47837085Skfall } 47937085Skfall 48037085Skfall /* 48137578Smckusick * Dup cred struct to a new held one. 48237085Skfall */ 48337578Smckusick struct ucred * 48437578Smckusick crdup(cr) 48537578Smckusick struct ucred *cr; 48637085Skfall { 48737578Smckusick struct ucred *newcr; 48837085Skfall 48937578Smckusick newcr = crget(); 49037578Smckusick *newcr = *cr; 49137578Smckusick newcr->cr_ref = 1; 49243393Skarels return (newcr); 49337085Skfall } 49437579Smckusick 49537579Smckusick /* 49640667Skarels * Get login name, if available. 49737579Smckusick */ 49854925Storek struct getlogin_args { 49954925Storek char *namebuf; 50054925Storek u_int namelen; 50154925Storek }; 50243393Skarels /* ARGSUSED */ 50343393Skarels getlogin(p, uap, retval) 50443393Skarels struct proc *p; 50554925Storek struct getlogin_args *uap; 50643393Skarels int *retval; 50743393Skarels { 50837579Smckusick 50947540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 51047540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 51147540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 51247540Skarels (caddr_t) uap->namebuf, uap->namelen)); 51337579Smckusick } 51437579Smckusick 51537579Smckusick /* 51640667Skarels * Set login name. 51737579Smckusick */ 51854925Storek struct setlogin_args { 51954925Storek char *namebuf; 52054925Storek }; 52143393Skarels /* ARGSUSED */ 52243393Skarels setlogin(p, uap, retval) 52343393Skarels struct proc *p; 52454925Storek struct setlogin_args *uap; 52543393Skarels int *retval; 52637579Smckusick { 52740667Skarels int error; 52837579Smckusick 52947540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 53044405Skarels return (error); 53147540Skarels error = copyinstr((caddr_t) uap->namebuf, 53247540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 53347540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 53447540Skarels if (error == ENAMETOOLONG) 53540667Skarels error = EINVAL; 53644405Skarels return (error); 53737579Smckusick } 538