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*47972Smarc * @(#)kern_prot.c 7.20 (Berkeley) 04/12/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" 1747540Skarels #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 3247540Skarels 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 4447540Skarels *retval = p->p_pptr->p_pid; 4544405Skarels return (0); 467498Sroot } 477498Sroot 4847540Skarels /* Get process group ID; note that POSIX getpgrp takes no parameter */ 4943393Skarels getpgrp(p, uap, retval) 5043393Skarels struct proc *p; 5147540Skarels 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 6647540Skarels *retval = p->p_cred->p_ruid; 6743393Skarels #ifdef COMPAT_43 6847540Skarels 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 8047540Skarels *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 9147540Skarels *retval = p->p_cred->p_rgid; 9243393Skarels #ifdef COMPAT_43 9347540Skarels 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 { 10947540Skarels 11047540Skarels *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 { 12247540Skarels 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) { 13047540Skarels *retval = pc->pc_ucred->cr_ngroups; 13144405Skarels return (0); 13237578Smckusick } 13347540Skarels if (ngrp < pc->pc_ucred->cr_ngroups) 13444405Skarels return (EINVAL); 13547540Skarels ngrp = pc->pc_ucred->cr_ngroups; 13647540Skarels 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) 14747540Skarels 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 { 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 * 164*47972Smarc * 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 */ 17443393Skarels /* ARGSUSED */ 175*47972Smarc setpgid(curp, uap, retval) 176*47972Smarc struct proc *curp; 17743393Skarels register struct args { 178*47972Smarc int targpid; /* target process id */ 179*47972Smarc int targpgid; /* target pgrp id */ 18043393Skarels } *uap; 18143393Skarels int *retval; 18243393Skarels { 183*47972Smarc register struct proc *targp; /* target process */ 184*47972Smarc register struct pgrp *targpgrp; /* target pgrp */ 1857498Sroot 186*47972Smarc if (uap->targpid && uap->targpid != curp->p_pid) { 187*47972Smarc if ((targp = pfind(uap->targpid)) == 0 || !inferior(targp)) 18844405Skarels return (ESRCH); 189*47972Smarc if (targp->p_session != curp->p_session) 19044405Skarels return (EPERM); 191*47972Smarc if (targp->p_flag&SEXEC) 19244405Skarels return (EACCES); 19343393Skarels } else 194*47972Smarc targp = curp; 195*47972Smarc if (SESS_LEADER(targp)) 19644405Skarels return (EPERM); 197*47972Smarc if (uap->targpgid == 0) 198*47972Smarc uap->targpgid = curp->p_pid; 199*47972Smarc else if (uap->targpgid != curp->p_pid) 200*47972Smarc if ((targpgrp = pgfind(uap->targpgid)) == 0 || 201*47972Smarc targpgrp->pg_mem == NULL || 202*47972Smarc targpgrp->pg_session != curp->p_session) 20345908Sbostic return (EPERM); 204*47972Smarc enterpgrp(targp, uap->targpgid, 0); 20544405Skarels return (0); 2067498Sroot } 2077498Sroot 20843393Skarels /* ARGSUSED */ 20943393Skarels setuid(p, uap, retval) 21047540Skarels struct proc *p; 21143393Skarels struct args { 21243393Skarels int uid; 21343393Skarels } *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 /* 22545908Sbostic * Everything's okay, do it. Copy credentials so other references do 22645908Sbostic * not see our changes. 22743393Skarels */ 22847540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 22947540Skarels pc->pc_ucred->cr_uid = uid; 23047540Skarels pc->p_ruid = uid; 23147540Skarels pc->p_svuid = uid; 23244405Skarels return (0); 23343393Skarels } 23443393Skarels 23543393Skarels /* ARGSUSED */ 23643393Skarels seteuid(p, uap, retval) 23747540Skarels struct proc *p; 23843393Skarels struct args { 23943393Skarels int euid; 24043393Skarels } *uap; 24143393Skarels int *retval; 24243393Skarels { 24347540Skarels register struct pcred *pc = p->p_cred; 24443393Skarels register uid_t euid; 24543393Skarels int error; 24643393Skarels 24743393Skarels euid = uap->euid; 24847540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 24947540Skarels (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 */ 25547540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 25647540Skarels 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 { 26847540Skarels register struct pcred *pc = p->p_cred; 26943393Skarels register gid_t gid; 27043393Skarels int error; 27143393Skarels 27243393Skarels gid = uap->gid; 27347540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 27444405Skarels return (error); 27547540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 27647540Skarels pc->pc_ucred->cr_groups[0] = gid; 27747540Skarels pc->p_rgid = gid; 27847540Skarels 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 { 29047540Skarels register struct pcred *pc = p->p_cred; 29143393Skarels register gid_t egid; 29243393Skarels int error; 29343393Skarels 29443393Skarels egid = uap->egid; 29547540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 29647540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 29744405Skarels return (error); 29847540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 29947540Skarels 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 { 31347540Skarels register struct pcred *pc = p->p_cred; 31443393Skarels register uid_t ruid, euid; 31543393Skarels int error; 3169160Ssam 31743393Skarels if (uap->ruid == -1) 31847540Skarels 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 * 32547540Skarels * if (ruid != pc->p_ruid && 32647540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 32743393Skarels */ 32847540Skarels if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && 32947540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 33044405Skarels return (error); 33143393Skarels if (uap->euid == -1) 33247540Skarels euid = pc->pc_ucred->cr_uid; 33343393Skarels else 33443393Skarels euid = uap->euid; 33547540Skarels if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && 33647540Skarels 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 */ 34247540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 34347540Skarels pc->pc_ucred->cr_uid = euid; 34447540Skarels pc->p_ruid = ruid; 34544405Skarels return (0); 3469160Ssam } 3479160Ssam 34843393Skarels /* ARGSUSED */ 34943393Skarels osetregid(p, uap, retval) 35047540Skarels register struct proc *p; 35143393Skarels struct args { 3529160Ssam int rgid; 3539160Ssam int egid; 3549160Ssam } *uap; 35543393Skarels int *retval; 35643393Skarels { 35747540Skarels register struct pcred *pc = p->p_cred; 35843393Skarels register gid_t rgid, egid; 35943393Skarels int error; 3609160Ssam 36143393Skarels if (uap->rgid == -1) 36247540Skarels 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 * 37047540Skarels * if (rgid != pc->p_rgid && 37147540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 37243393Skarels */ 37347540Skarels if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && 37447540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 37544405Skarels return (error); 37643393Skarels if (uap->egid == -1) 37747540Skarels egid = pc->pc_ucred->cr_groups[0]; 37843393Skarels else 37943393Skarels egid = uap->egid; 38047540Skarels if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && 38147540Skarels egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 38244405Skarels return (error); 38347540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 38447540Skarels pc->pc_ucred->cr_groups[0] = egid; 38547540Skarels 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 { 39947540Skarels 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 40547540Skarels 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); 41247540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 41347540Skarels pc->pc_ucred->cr_ngroups = ngrp; 41444942Sbostic /* convert from int's to gid_t's */ 41547540Skarels 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 { 47647540Skarels 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 53247540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 53347540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 53447540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 53547540Skarels (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 55147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55244405Skarels return (error); 55347540Skarels error = copyinstr((caddr_t) uap->namebuf, 55447540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 55547540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 55647540Skarels if (error == ENAMETOOLONG) 55740667Skarels error = EINVAL; 55844405Skarels return (error); 55937579Smckusick } 560