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*55163Smckusick * @(#)kern_prot.c 7.27 (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; 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 /* 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 { 23855162Smckusick 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 { 26555162Smckusick 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 { 28955162Smckusick 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; 31355162Smckusick 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; 32355162Smckusick 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); 32955162Smckusick pc->pc_ucred = crcopy(pc->pc_ucred); 33055162Smckusick if (error = copyin((caddr_t)uap->gidset, 33155162Smckusick (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 338*55163Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 339*55163Smckusick struct setreuid_args { 340*55163Smckusick int ruid; 341*55163Smckusick int euid; 342*55163Smckusick }; 343*55163Smckusick /* ARGSUSED */ 344*55163Smckusick osetreuid(p, uap, retval) 345*55163Smckusick register struct proc *p; 346*55163Smckusick struct setreuid_args *uap; 347*55163Smckusick int *retval; 348*55163Smckusick { 349*55163Smckusick register struct pcred *pc = p->p_cred; 350*55163Smckusick struct seteuid_args args; 351*55163Smckusick 352*55163Smckusick /* 353*55163Smckusick * we assume that the intent of setting ruid is to be able to get 354*55163Smckusick * back ruid priviledge. So we make sure that we will be able to 355*55163Smckusick * do so, but do not actually set the ruid. 356*55163Smckusick */ 357*55163Smckusick if (uap->ruid != -1 && uap->ruid != pc->p_ruid && 358*55163Smckusick uap->ruid != pc->p_svuid) 359*55163Smckusick return (EPERM); 360*55163Smckusick if (uap->euid == -1) 361*55163Smckusick return (0); 362*55163Smckusick args.euid = uap->euid; 363*55163Smckusick return (seteuid(p, &args, retval)); 364*55163Smckusick } 365*55163Smckusick 366*55163Smckusick struct setregid_args { 367*55163Smckusick int rgid; 368*55163Smckusick int egid; 369*55163Smckusick }; 370*55163Smckusick /* ARGSUSED */ 371*55163Smckusick osetregid(p, uap, retval) 372*55163Smckusick register struct proc *p; 373*55163Smckusick struct setregid_args *uap; 374*55163Smckusick int *retval; 375*55163Smckusick { 376*55163Smckusick register struct pcred *pc = p->p_cred; 377*55163Smckusick struct setegid_args args; 378*55163Smckusick 379*55163Smckusick /* 380*55163Smckusick * we assume that the intent of setting rgid is to be able to get 381*55163Smckusick * back rgid priviledge. So we make sure that we will be able to 382*55163Smckusick * do so, but do not actually set the rgid. 383*55163Smckusick */ 384*55163Smckusick if (uap->rgid != -1 && uap->rgid != pc->p_rgid && 385*55163Smckusick uap->rgid != pc->p_svgid) 386*55163Smckusick return (EPERM); 387*55163Smckusick if (uap->egid == -1) 388*55163Smckusick return (0); 389*55163Smckusick args.egid = uap->egid; 390*55163Smckusick return (setegid(p, &args, retval)); 391*55163Smckusick } 392*55163Smckusick #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 393*55163Smckusick 3947498Sroot /* 39537578Smckusick * Check if gid is a member of the group set. 39611810Ssam */ 39737578Smckusick groupmember(gid, cred) 39826275Skarels gid_t gid; 39937578Smckusick register struct ucred *cred; 4007866Sroot { 40118362Skarels register gid_t *gp; 40237578Smckusick gid_t *egp; 4037866Sroot 40437578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 40537578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4067866Sroot if (*gp == gid) 40737578Smckusick return (1); 40837578Smckusick return (0); 4097866Sroot } 4107866Sroot 41111810Ssam /* 41246293Skarels * Test whether the specified credentials imply "super-user" 41346293Skarels * privilege; if so, and we have accounting info, set the flag 41446293Skarels * indicating use of super-powers. 41546293Skarels * Returns 0 or error. 41611810Ssam */ 41737578Smckusick suser(cred, acflag) 41837578Smckusick struct ucred *cred; 41937578Smckusick short *acflag; 4207866Sroot { 42137578Smckusick if (cred->cr_uid == 0) { 42237578Smckusick if (acflag) 42337578Smckusick *acflag |= ASU; 42437578Smckusick return (0); 42518362Skarels } 42637578Smckusick return (EPERM); 4277866Sroot } 42811810Ssam 42911810Ssam /* 43037578Smckusick * Allocate a zeroed cred structure. 43111810Ssam */ 43237578Smckusick struct ucred * 43337578Smckusick crget() 43411810Ssam { 43537578Smckusick register struct ucred *cr; 43611810Ssam 43737578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 43837578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 43937578Smckusick cr->cr_ref = 1; 44043393Skarels return (cr); 44111810Ssam } 44237085Skfall 44337085Skfall /* 44437578Smckusick * Free a cred structure. 44537578Smckusick * Throws away space when ref count gets to 0. 44637085Skfall */ 44737578Smckusick crfree(cr) 44837578Smckusick struct ucred *cr; 44937578Smckusick { 45047540Skarels int s = splimp(); /* ??? */ 45137085Skfall 45237578Smckusick if (--cr->cr_ref != 0) { 45337578Smckusick (void) splx(s); 45437578Smckusick return; 45537578Smckusick } 45637578Smckusick FREE((caddr_t)cr, M_CRED); 45737578Smckusick (void) splx(s); 45837578Smckusick } 45937578Smckusick 46037578Smckusick /* 46137578Smckusick * Copy cred structure to a new one and free the old one. 46237578Smckusick */ 46337578Smckusick struct ucred * 46437578Smckusick crcopy(cr) 46537578Smckusick struct ucred *cr; 46637085Skfall { 46737578Smckusick struct ucred *newcr; 46837085Skfall 46945908Sbostic if (cr->cr_ref == 1) 47045908Sbostic return (cr); 47137578Smckusick newcr = crget(); 47237578Smckusick *newcr = *cr; 47337578Smckusick crfree(cr); 47437578Smckusick newcr->cr_ref = 1; 47543393Skarels return (newcr); 47637085Skfall } 47737085Skfall 47837085Skfall /* 47937578Smckusick * Dup cred struct to a new held one. 48037085Skfall */ 48137578Smckusick struct ucred * 48237578Smckusick crdup(cr) 48337578Smckusick struct ucred *cr; 48437085Skfall { 48537578Smckusick struct ucred *newcr; 48637085Skfall 48737578Smckusick newcr = crget(); 48837578Smckusick *newcr = *cr; 48937578Smckusick newcr->cr_ref = 1; 49043393Skarels return (newcr); 49137085Skfall } 49237579Smckusick 49337579Smckusick /* 49440667Skarels * Get login name, if available. 49537579Smckusick */ 49654925Storek struct getlogin_args { 49754925Storek char *namebuf; 49854925Storek u_int namelen; 49954925Storek }; 50043393Skarels /* ARGSUSED */ 50143393Skarels getlogin(p, uap, retval) 50243393Skarels struct proc *p; 50354925Storek struct getlogin_args *uap; 50443393Skarels int *retval; 50543393Skarels { 50637579Smckusick 50747540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 50847540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 50947540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 51047540Skarels (caddr_t) uap->namebuf, uap->namelen)); 51137579Smckusick } 51237579Smckusick 51337579Smckusick /* 51440667Skarels * Set login name. 51537579Smckusick */ 51654925Storek struct setlogin_args { 51754925Storek char *namebuf; 51854925Storek }; 51943393Skarels /* ARGSUSED */ 52043393Skarels setlogin(p, uap, retval) 52143393Skarels struct proc *p; 52254925Storek struct setlogin_args *uap; 52343393Skarels int *retval; 52437579Smckusick { 52540667Skarels int error; 52637579Smckusick 52747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 52844405Skarels return (error); 52947540Skarels error = copyinstr((caddr_t) uap->namebuf, 53047540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 53147540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 53247540Skarels if (error == ENAMETOOLONG) 53340667Skarels error = EINVAL; 53444405Skarels return (error); 53537579Smckusick } 536