123372Smckusick /* 2*47540Skarels * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University 3*47540Skarels * of California. All rights reserved. 423372Smckusick * 544439Sbostic * %sccs.include.redist.c% 637578Smckusick * 7*47540Skarels * @(#)kern_prot.c 7.19 (Berkeley) 03/17/91 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" 17*47540Skarels #include "ucred.h" 1817092Sbloom #include "proc.h" 1917092Sbloom #include "timeb.h" 2017092Sbloom #include "times.h" 2137578Smckusick #include "malloc.h" 227420Sroot 2343393Skarels /* ARGSUSED */ 2443393Skarels getpid(p, uap, retval) 2543393Skarels struct proc *p; 2643393Skarels void *uap; 2743393Skarels int *retval; 2843393Skarels { 2937579Smckusick 3043393Skarels *retval = p->p_pid; 3143393Skarels #ifdef COMPAT_43 32*47540Skarels retval[1] = p->p_pptr->p_pid; 3343393Skarels #endif 3444405Skarels return (0); 3543393Skarels } 3643393Skarels 3743393Skarels /* ARGSUSED */ 3843393Skarels getppid(p, uap, retval) 3943393Skarels struct proc *p; 4043393Skarels void *uap; 4143393Skarels int *retval; 427498Sroot { 437498Sroot 44*47540Skarels *retval = p->p_pptr->p_pid; 4544405Skarels return (0); 467498Sroot } 477498Sroot 48*47540Skarels /* Get process group ID; note that POSIX getpgrp takes no parameter */ 4943393Skarels getpgrp(p, uap, retval) 5043393Skarels struct proc *p; 51*47540Skarels void *uap; 5243393Skarels int *retval; 537498Sroot { 547498Sroot 5543393Skarels *retval = p->p_pgrp->pg_id; 5644405Skarels return (0); 577498Sroot } 587498Sroot 5943393Skarels /* ARGSUSED */ 6043393Skarels getuid(p, uap, retval) 6143393Skarels struct proc *p; 6243393Skarels void *uap; 6343393Skarels int *retval; 647420Sroot { 657420Sroot 66*47540Skarels *retval = p->p_cred->p_ruid; 6743393Skarels #ifdef COMPAT_43 68*47540Skarels retval[1] = p->p_ucred->cr_uid; 6943393Skarels #endif 7044405Skarels return (0); 717420Sroot } 727420Sroot 7343393Skarels /* ARGSUSED */ 7443393Skarels geteuid(p, uap, retval) 7543393Skarels struct proc *p; 7643393Skarels void *uap; 7743393Skarels int *retval; 787498Sroot { 797498Sroot 80*47540Skarels *retval = p->p_ucred->cr_uid; 8144405Skarels return (0); 827498Sroot } 837498Sroot 8443393Skarels /* ARGSUSED */ 8543393Skarels getgid(p, uap, retval) 8643393Skarels struct proc *p; 8743393Skarels void *uap; 8843393Skarels int *retval; 897498Sroot { 9043393Skarels 91*47540Skarels *retval = p->p_cred->p_rgid; 9243393Skarels #ifdef COMPAT_43 93*47540Skarels retval[1] = p->p_ucred->cr_groups[0]; 9443393Skarels #endif 9544405Skarels return (0); 9643393Skarels } 9743393Skarels 9843393Skarels /* 9945908Sbostic * Get effective group ID. The "egid" is groups[0], and could be obtained 10045908Sbostic * via getgroups. This syscall exists because it is somewhat painful to do 10145908Sbostic * correctly in a library function. 10243393Skarels */ 10343393Skarels /* ARGSUSED */ 10443393Skarels getegid(p, uap, retval) 10543393Skarels struct proc *p; 10643393Skarels void *uap; 10743393Skarels int *retval; 10843393Skarels { 109*47540Skarels 110*47540Skarels *retval = p->p_ucred->cr_groups[0]; 11144405Skarels return (0); 11243393Skarels } 11343393Skarels 11443393Skarels getgroups(p, uap, retval) 11543393Skarels struct proc *p; 11643393Skarels register struct arg { 1178624Sroot u_int gidsetsize; 11843393Skarels int *gidset; /* XXX not yet POSIX */ 11943393Skarels } *uap; 12043393Skarels int *retval; 12143393Skarels { 122*47540Skarels register struct pcred *pc = p->p_cred; 12318362Skarels register gid_t *gp; 12418362Skarels register int *lp; 12544994Skarels register u_int ngrp; 12618362Skarels int groups[NGROUPS]; 12743393Skarels int error; 1287498Sroot 12944994Skarels if ((ngrp = uap->gidsetsize) == 0) { 130*47540Skarels *retval = pc->pc_ucred->cr_ngroups; 13144405Skarels return (0); 13237578Smckusick } 133*47540Skarels if (ngrp < pc->pc_ucred->cr_ngroups) 13444405Skarels return (EINVAL); 135*47540Skarels ngrp = pc->pc_ucred->cr_ngroups; 136*47540Skarels for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; ) 13718362Skarels *lp++ = *gp++; 13843393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 13944994Skarels ngrp * sizeof (groups[0]))) 14044405Skarels return (error); 14144994Skarels *retval = ngrp; 14244405Skarels return (0); 1437498Sroot } 1447498Sroot 14543393Skarels /* ARGSUSED */ 14643393Skarels setsid(p, uap, retval) 147*47540Skarels register struct proc *p; 14843393Skarels void *uap; 14943393Skarels int *retval; 15037579Smckusick { 15137579Smckusick 15243393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 15344405Skarels return (EPERM); 15443393Skarels } else { 155*47540Skarels enterpgrp(p, p->p_pid, 1); 15643393Skarels *retval = p->p_pid; 15744405Skarels return (0); 15837579Smckusick } 15937579Smckusick } 16037579Smckusick 16137579Smckusick /* 162*47540Skarels * set process group (setpgid/old setpgrp) 16337579Smckusick * 164*47540Skarels * caller does setpgid(pid, pgid) 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 */ 17443393Skarels /* ARGSUSED */ 175*47540Skarels setpgid(cp, uap, retval) 17643393Skarels struct proc *cp; 17743393Skarels register struct args { 1787498Sroot int pid; 17937579Smckusick int pgid; 18043393Skarels } *uap; 18143393Skarels int *retval; 18243393Skarels { 18337579Smckusick register struct proc *p; 18437579Smckusick register struct pgrp *pgrp; 1857498Sroot 18643393Skarels if (uap->pid != 0) { 18743393Skarels if ((p = pfind(uap->pid)) == 0 || !inferior(p)) 18844405Skarels return (ESRCH); 18943393Skarels if (p->p_session != cp->p_session) 19044405Skarels return (EPERM); 19143393Skarels if (p->p_flag&SEXEC) 19244405Skarels return (EACCES); 19343393Skarels } else 19443393Skarels p = cp; 19543393Skarels if (SESS_LEADER(p)) 19644405Skarels return (EPERM); 19737579Smckusick if (uap->pgid == 0) 19837579Smckusick uap->pgid = p->p_pid; 19945908Sbostic else if (uap->pgid != p->p_pid) 20045908Sbostic if ((pgrp = pgfind(uap->pgid)) == 0 || 20145908Sbostic pgrp->pg_mem == NULL || 20245908Sbostic pgrp->pg_session != cp->p_session) 20345908Sbostic return (EPERM); 204*47540Skarels enterpgrp(p, uap->pgid, 0); 20544405Skarels return (0); 2067498Sroot } 2077498Sroot 20843393Skarels /* ARGSUSED */ 20943393Skarels setuid(p, uap, retval) 210*47540Skarels struct proc *p; 21143393Skarels struct args { 21243393Skarels int uid; 21343393Skarels } *uap; 21443393Skarels int *retval; 2157420Sroot { 216*47540Skarels register struct pcred *pc = p->p_cred; 21743393Skarels register uid_t uid; 21843393Skarels int error; 21943393Skarels 22043393Skarels uid = uap->uid; 221*47540Skarels if (uid != pc->p_ruid && 222*47540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 22344405Skarels return (error); 22443393Skarels /* 22545908Sbostic * Everything's okay, do it. Copy credentials so other references do 22645908Sbostic * not see our changes. 22743393Skarels */ 228*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 229*47540Skarels pc->pc_ucred->cr_uid = uid; 230*47540Skarels pc->p_ruid = uid; 231*47540Skarels pc->p_svuid = uid; 23244405Skarels return (0); 23343393Skarels } 23443393Skarels 23543393Skarels /* ARGSUSED */ 23643393Skarels seteuid(p, uap, retval) 237*47540Skarels struct proc *p; 23843393Skarels struct args { 23943393Skarels int euid; 24043393Skarels } *uap; 24143393Skarels int *retval; 24243393Skarels { 243*47540Skarels register struct pcred *pc = p->p_cred; 24443393Skarels register uid_t euid; 24543393Skarels int error; 24643393Skarels 24743393Skarels euid = uap->euid; 248*47540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 249*47540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 25044405Skarels return (error); 25143393Skarels /* 25245908Sbostic * Everything's okay, do it. Copy credentials so other references do 25345908Sbostic * not see our changes. 25443393Skarels */ 255*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 256*47540Skarels pc->pc_ucred->cr_uid = euid; 25744405Skarels return (0); 25843393Skarels } 25943393Skarels 26043393Skarels /* ARGSUSED */ 26143393Skarels setgid(p, uap, retval) 26243393Skarels struct proc *p; 26343393Skarels struct args { 26443393Skarels int gid; 26543393Skarels } *uap; 26643393Skarels int *retval; 26743393Skarels { 268*47540Skarels register struct pcred *pc = p->p_cred; 26943393Skarels register gid_t gid; 27043393Skarels int error; 27143393Skarels 27243393Skarels gid = uap->gid; 273*47540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 27444405Skarels return (error); 275*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 276*47540Skarels pc->pc_ucred->cr_groups[0] = gid; 277*47540Skarels pc->p_rgid = gid; 278*47540Skarels pc->p_svgid = gid; /* ??? */ 27944405Skarels return (0); 28043393Skarels } 28143393Skarels 28243393Skarels /* ARGSUSED */ 28343393Skarels setegid(p, uap, retval) 28443393Skarels struct proc *p; 28543393Skarels struct args { 28643393Skarels int egid; 28743393Skarels } *uap; 28843393Skarels int *retval; 28943393Skarels { 290*47540Skarels register struct pcred *pc = p->p_cred; 29143393Skarels register gid_t egid; 29243393Skarels int error; 29343393Skarels 29443393Skarels egid = uap->egid; 295*47540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 296*47540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 29744405Skarels return (error); 298*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 299*47540Skarels pc->pc_ucred->cr_groups[0] = egid; 30044405Skarels return (0); 30143393Skarels } 30243393Skarels 30343393Skarels #ifdef COMPAT_43 30443393Skarels /* ARGSUSED */ 30543393Skarels osetreuid(p, uap, retval) 30643393Skarels register struct proc *p; 30743393Skarels struct args { 3089160Ssam int ruid; 3099160Ssam int euid; 3109160Ssam } *uap; 31143393Skarels int *retval; 31243393Skarels { 313*47540Skarels register struct pcred *pc = p->p_cred; 31443393Skarels register uid_t ruid, euid; 31543393Skarels int error; 3169160Ssam 31743393Skarels if (uap->ruid == -1) 318*47540Skarels ruid = pc->p_ruid; 31943393Skarels else 32043393Skarels ruid = uap->ruid; 32143393Skarels /* 32245908Sbostic * Allow setting real uid to previous effective, for swapping real and 32345908Sbostic * effective. This should be: 32445908Sbostic * 325*47540Skarels * if (ruid != pc->p_ruid && 326*47540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 32743393Skarels */ 328*47540Skarels if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && 329*47540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 33044405Skarels return (error); 33143393Skarels if (uap->euid == -1) 332*47540Skarels euid = pc->pc_ucred->cr_uid; 33343393Skarels else 33443393Skarels euid = uap->euid; 335*47540Skarels if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && 336*47540Skarels euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) 33744405Skarels return (error); 3389160Ssam /* 33945908Sbostic * Everything's okay, do it. Copy credentials so other references do 34045908Sbostic * not see our changes. 3419160Ssam */ 342*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 343*47540Skarels pc->pc_ucred->cr_uid = euid; 344*47540Skarels pc->p_ruid = ruid; 34544405Skarels return (0); 3469160Ssam } 3479160Ssam 34843393Skarels /* ARGSUSED */ 34943393Skarels osetregid(p, uap, retval) 350*47540Skarels register struct proc *p; 35143393Skarels struct args { 3529160Ssam int rgid; 3539160Ssam int egid; 3549160Ssam } *uap; 35543393Skarels int *retval; 35643393Skarels { 357*47540Skarels register struct pcred *pc = p->p_cred; 35843393Skarels register gid_t rgid, egid; 35943393Skarels int error; 3609160Ssam 36143393Skarels if (uap->rgid == -1) 362*47540Skarels rgid = pc->p_rgid; 36343393Skarels else 36443393Skarels rgid = uap->rgid; 36543393Skarels /* 36645908Sbostic * Allow setting real gid to previous effective, for swapping real and 36745908Sbostic * effective. This didn't really work correctly in 4.[23], but is 36845908Sbostic * preserved so old stuff doesn't fail. This should be: 36945908Sbostic * 370*47540Skarels * if (rgid != pc->p_rgid && 371*47540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 37243393Skarels */ 373*47540Skarels if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && 374*47540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 37544405Skarels return (error); 37643393Skarels if (uap->egid == -1) 377*47540Skarels egid = pc->pc_ucred->cr_groups[0]; 37843393Skarels else 37943393Skarels egid = uap->egid; 380*47540Skarels if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && 381*47540Skarels egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 38244405Skarels return (error); 383*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 384*47540Skarels pc->pc_ucred->cr_groups[0] = egid; 385*47540Skarels pc->p_rgid = rgid; 38644405Skarels return (0); 3879160Ssam } 38843393Skarels #endif 3899160Ssam 39043393Skarels /* ARGSUSED */ 39143393Skarels setgroups(p, uap, retval) 39243393Skarels struct proc *p; 39343393Skarels struct args { 3948624Sroot u_int gidsetsize; 3957498Sroot int *gidset; 39643393Skarels } *uap; 39743393Skarels int *retval; 39843393Skarels { 399*47540Skarels register struct pcred *pc = p->p_cred; 40018362Skarels register gid_t *gp; 40144994Skarels register u_int ngrp; 40218362Skarels register int *lp; 40344942Sbostic int error, groups[NGROUPS]; 4047498Sroot 405*47540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 40644405Skarels return (error); 40744994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 40844405Skarels return (EINVAL); 40944942Sbostic if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 41044994Skarels ngrp * sizeof (groups[0]))) 41144405Skarels return (error); 412*47540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 413*47540Skarels pc->pc_ucred->cr_ngroups = ngrp; 41444942Sbostic /* convert from int's to gid_t's */ 415*47540Skarels for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; ) 41644994Skarels *gp++ = *lp++; 41744405Skarels return (0); 4187498Sroot } 4197498Sroot 4207498Sroot /* 42137578Smckusick * Check if gid is a member of the group set. 42211810Ssam */ 42337578Smckusick groupmember(gid, cred) 42426275Skarels gid_t gid; 42537578Smckusick register struct ucred *cred; 4267866Sroot { 42718362Skarels register gid_t *gp; 42837578Smckusick gid_t *egp; 4297866Sroot 43037578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 43137578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4327866Sroot if (*gp == gid) 43337578Smckusick return (1); 43437578Smckusick return (0); 4357866Sroot } 4367866Sroot 43711810Ssam /* 43846293Skarels * Test whether the specified credentials imply "super-user" 43946293Skarels * privilege; if so, and we have accounting info, set the flag 44046293Skarels * indicating use of super-powers. 44146293Skarels * Returns 0 or error. 44211810Ssam */ 44337578Smckusick suser(cred, acflag) 44437578Smckusick struct ucred *cred; 44537578Smckusick short *acflag; 4467866Sroot { 44737578Smckusick if (cred->cr_uid == 0) { 44837578Smckusick if (acflag) 44937578Smckusick *acflag |= ASU; 45037578Smckusick return (0); 45118362Skarels } 45237578Smckusick return (EPERM); 4537866Sroot } 45411810Ssam 45511810Ssam /* 45637578Smckusick * Allocate a zeroed cred structure. 45711810Ssam */ 45837578Smckusick struct ucred * 45937578Smckusick crget() 46011810Ssam { 46137578Smckusick register struct ucred *cr; 46211810Ssam 46337578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 46437578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 46537578Smckusick cr->cr_ref = 1; 46643393Skarels return (cr); 46711810Ssam } 46837085Skfall 46937085Skfall /* 47037578Smckusick * Free a cred structure. 47137578Smckusick * Throws away space when ref count gets to 0. 47237085Skfall */ 47337578Smckusick crfree(cr) 47437578Smckusick struct ucred *cr; 47537578Smckusick { 476*47540Skarels int s = splimp(); /* ??? */ 47737085Skfall 47837578Smckusick if (--cr->cr_ref != 0) { 47937578Smckusick (void) splx(s); 48037578Smckusick return; 48137578Smckusick } 48237578Smckusick FREE((caddr_t)cr, M_CRED); 48337578Smckusick (void) splx(s); 48437578Smckusick } 48537578Smckusick 48637578Smckusick /* 48737578Smckusick * Copy cred structure to a new one and free the old one. 48837578Smckusick */ 48937578Smckusick struct ucred * 49037578Smckusick crcopy(cr) 49137578Smckusick struct ucred *cr; 49237085Skfall { 49337578Smckusick struct ucred *newcr; 49437085Skfall 49545908Sbostic if (cr->cr_ref == 1) 49645908Sbostic return (cr); 49737578Smckusick newcr = crget(); 49837578Smckusick *newcr = *cr; 49937578Smckusick crfree(cr); 50037578Smckusick newcr->cr_ref = 1; 50143393Skarels return (newcr); 50237085Skfall } 50337085Skfall 50437085Skfall /* 50537578Smckusick * Dup cred struct to a new held one. 50637085Skfall */ 50737578Smckusick struct ucred * 50837578Smckusick crdup(cr) 50937578Smckusick struct ucred *cr; 51037085Skfall { 51137578Smckusick struct ucred *newcr; 51237085Skfall 51337578Smckusick newcr = crget(); 51437578Smckusick *newcr = *cr; 51537578Smckusick newcr->cr_ref = 1; 51643393Skarels return (newcr); 51737085Skfall } 51837579Smckusick 51937579Smckusick /* 52040667Skarels * Get login name, if available. 52137579Smckusick */ 52243393Skarels /* ARGSUSED */ 52343393Skarels getlogin(p, uap, retval) 52443393Skarels struct proc *p; 52543393Skarels struct args { 52637579Smckusick char *namebuf; 52737579Smckusick u_int namelen; 52843393Skarels } *uap; 52943393Skarels int *retval; 53043393Skarels { 53137579Smckusick 532*47540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 533*47540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 534*47540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 535*47540Skarels (caddr_t) uap->namebuf, uap->namelen)); 53637579Smckusick } 53737579Smckusick 53837579Smckusick /* 53940667Skarels * Set login name. 54037579Smckusick */ 54143393Skarels /* ARGSUSED */ 54243393Skarels setlogin(p, uap, retval) 54343393Skarels struct proc *p; 54443393Skarels struct args { 54543393Skarels char *namebuf; 54643393Skarels } *uap; 54743393Skarels int *retval; 54837579Smckusick { 54940667Skarels int error; 55037579Smckusick 551*47540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55244405Skarels return (error); 553*47540Skarels error = copyinstr((caddr_t) uap->namebuf, 554*47540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 555*47540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 556*47540Skarels if (error == ENAMETOOLONG) 55740667Skarels error = EINVAL; 55844405Skarels return (error); 55937579Smckusick } 560