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*48990Skarels * @(#)kern_prot.c 7.21 (Berkeley) 05/03/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 * 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 */ 17443393Skarels /* ARGSUSED */ 17547972Smarc setpgid(curp, uap, retval) 17647972Smarc struct proc *curp; 17743393Skarels register struct args { 178*48990Skarels int pid; /* target process id */ 179*48990Skarels int pgid; /* target pgrp id */ 18043393Skarels } *uap; 18143393Skarels int *retval; 18243393Skarels { 18347972Smarc register struct proc *targp; /* target process */ 184*48990Skarels register struct pgrp *pgrp; /* target pgrp */ 1857498Sroot 186*48990Skarels if (uap->pid != 0 && uap->pid != curp->p_pid) { 187*48990Skarels if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) 18844405Skarels return (ESRCH); 18947972Smarc if (targp->p_session != curp->p_session) 19044405Skarels return (EPERM); 19147972Smarc if (targp->p_flag&SEXEC) 19244405Skarels return (EACCES); 19343393Skarels } else 19447972Smarc targp = curp; 19547972Smarc if (SESS_LEADER(targp)) 19644405Skarels return (EPERM); 197*48990Skarels if (uap->pgid == 0) 198*48990Skarels uap->pgid = targp->p_pid; 199*48990Skarels else if (uap->pgid != targp->p_pid) 200*48990Skarels if ((pgrp = pgfind(uap->pgid)) == 0 || 201*48990Skarels pgrp->pg_session != curp->p_session) 20245908Sbostic return (EPERM); 203*48990Skarels enterpgrp(targp, uap->pgid, 0); 20444405Skarels return (0); 2057498Sroot } 2067498Sroot 20743393Skarels /* ARGSUSED */ 20843393Skarels setuid(p, uap, retval) 20947540Skarels struct proc *p; 21043393Skarels struct args { 21143393Skarels int uid; 21243393Skarels } *uap; 21343393Skarels int *retval; 2147420Sroot { 21547540Skarels register struct pcred *pc = p->p_cred; 21643393Skarels register uid_t uid; 21743393Skarels int error; 21843393Skarels 21943393Skarels uid = uap->uid; 22047540Skarels if (uid != pc->p_ruid && 22147540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 22244405Skarels return (error); 22343393Skarels /* 22445908Sbostic * Everything's okay, do it. Copy credentials so other references do 22545908Sbostic * not see our changes. 22643393Skarels */ 22747540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 22847540Skarels pc->pc_ucred->cr_uid = uid; 22947540Skarels pc->p_ruid = uid; 23047540Skarels pc->p_svuid = uid; 23144405Skarels return (0); 23243393Skarels } 23343393Skarels 23443393Skarels /* ARGSUSED */ 23543393Skarels seteuid(p, uap, retval) 23647540Skarels struct proc *p; 23743393Skarels struct args { 23843393Skarels int euid; 23943393Skarels } *uap; 24043393Skarels int *retval; 24143393Skarels { 24247540Skarels register struct pcred *pc = p->p_cred; 24343393Skarels register uid_t euid; 24443393Skarels int error; 24543393Skarels 24643393Skarels euid = uap->euid; 24747540Skarels if (euid != pc->p_ruid && euid != pc->p_svuid && 24847540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 24944405Skarels return (error); 25043393Skarels /* 25145908Sbostic * Everything's okay, do it. Copy credentials so other references do 25245908Sbostic * not see our changes. 25343393Skarels */ 25447540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 25547540Skarels pc->pc_ucred->cr_uid = euid; 25644405Skarels return (0); 25743393Skarels } 25843393Skarels 25943393Skarels /* ARGSUSED */ 26043393Skarels setgid(p, uap, retval) 26143393Skarels struct proc *p; 26243393Skarels struct args { 26343393Skarels int gid; 26443393Skarels } *uap; 26543393Skarels int *retval; 26643393Skarels { 26747540Skarels register struct pcred *pc = p->p_cred; 26843393Skarels register gid_t gid; 26943393Skarels int error; 27043393Skarels 27143393Skarels gid = uap->gid; 27247540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 27344405Skarels return (error); 27447540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 27547540Skarels pc->pc_ucred->cr_groups[0] = gid; 27647540Skarels pc->p_rgid = gid; 27747540Skarels pc->p_svgid = gid; /* ??? */ 27844405Skarels return (0); 27943393Skarels } 28043393Skarels 28143393Skarels /* ARGSUSED */ 28243393Skarels setegid(p, uap, retval) 28343393Skarels struct proc *p; 28443393Skarels struct args { 28543393Skarels int egid; 28643393Skarels } *uap; 28743393Skarels int *retval; 28843393Skarels { 28947540Skarels register struct pcred *pc = p->p_cred; 29043393Skarels register gid_t egid; 29143393Skarels int error; 29243393Skarels 29343393Skarels egid = uap->egid; 29447540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 29547540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 29644405Skarels return (error); 29747540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 29847540Skarels pc->pc_ucred->cr_groups[0] = egid; 29944405Skarels return (0); 30043393Skarels } 30143393Skarels 30243393Skarels #ifdef COMPAT_43 30343393Skarels /* ARGSUSED */ 30443393Skarels osetreuid(p, uap, retval) 30543393Skarels register struct proc *p; 30643393Skarels struct args { 3079160Ssam int ruid; 3089160Ssam int euid; 3099160Ssam } *uap; 31043393Skarels int *retval; 31143393Skarels { 31247540Skarels register struct pcred *pc = p->p_cred; 31343393Skarels register uid_t ruid, euid; 31443393Skarels int error; 3159160Ssam 31643393Skarels if (uap->ruid == -1) 31747540Skarels ruid = pc->p_ruid; 31843393Skarels else 31943393Skarels ruid = uap->ruid; 32043393Skarels /* 32145908Sbostic * Allow setting real uid to previous effective, for swapping real and 32245908Sbostic * effective. This should be: 32345908Sbostic * 32447540Skarels * if (ruid != pc->p_ruid && 32547540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 32643393Skarels */ 32747540Skarels if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && 32847540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 32944405Skarels return (error); 33043393Skarels if (uap->euid == -1) 33147540Skarels euid = pc->pc_ucred->cr_uid; 33243393Skarels else 33343393Skarels euid = uap->euid; 33447540Skarels if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && 33547540Skarels euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) 33644405Skarels return (error); 3379160Ssam /* 33845908Sbostic * Everything's okay, do it. Copy credentials so other references do 33945908Sbostic * not see our changes. 3409160Ssam */ 34147540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 34247540Skarels pc->pc_ucred->cr_uid = euid; 34347540Skarels pc->p_ruid = ruid; 34444405Skarels return (0); 3459160Ssam } 3469160Ssam 34743393Skarels /* ARGSUSED */ 34843393Skarels osetregid(p, uap, retval) 34947540Skarels register struct proc *p; 35043393Skarels struct args { 3519160Ssam int rgid; 3529160Ssam int egid; 3539160Ssam } *uap; 35443393Skarels int *retval; 35543393Skarels { 35647540Skarels register struct pcred *pc = p->p_cred; 35743393Skarels register gid_t rgid, egid; 35843393Skarels int error; 3599160Ssam 36043393Skarels if (uap->rgid == -1) 36147540Skarels rgid = pc->p_rgid; 36243393Skarels else 36343393Skarels rgid = uap->rgid; 36443393Skarels /* 36545908Sbostic * Allow setting real gid to previous effective, for swapping real and 36645908Sbostic * effective. This didn't really work correctly in 4.[23], but is 36745908Sbostic * preserved so old stuff doesn't fail. This should be: 36845908Sbostic * 36947540Skarels * if (rgid != pc->p_rgid && 37047540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 37143393Skarels */ 37247540Skarels if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && 37347540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 37444405Skarels return (error); 37543393Skarels if (uap->egid == -1) 37647540Skarels egid = pc->pc_ucred->cr_groups[0]; 37743393Skarels else 37843393Skarels egid = uap->egid; 37947540Skarels if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && 38047540Skarels egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 38144405Skarels return (error); 38247540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 38347540Skarels pc->pc_ucred->cr_groups[0] = egid; 38447540Skarels pc->p_rgid = rgid; 38544405Skarels return (0); 3869160Ssam } 38743393Skarels #endif 3889160Ssam 38943393Skarels /* ARGSUSED */ 39043393Skarels setgroups(p, uap, retval) 39143393Skarels struct proc *p; 39243393Skarels struct args { 3938624Sroot u_int gidsetsize; 3947498Sroot int *gidset; 39543393Skarels } *uap; 39643393Skarels int *retval; 39743393Skarels { 39847540Skarels register struct pcred *pc = p->p_cred; 39918362Skarels register gid_t *gp; 40044994Skarels register u_int ngrp; 40118362Skarels register int *lp; 40244942Sbostic int error, groups[NGROUPS]; 4037498Sroot 40447540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 40544405Skarels return (error); 40644994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 40744405Skarels return (EINVAL); 40844942Sbostic if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 40944994Skarels ngrp * sizeof (groups[0]))) 41044405Skarels return (error); 41147540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 41247540Skarels pc->pc_ucred->cr_ngroups = ngrp; 41344942Sbostic /* convert from int's to gid_t's */ 41447540Skarels for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; ) 41544994Skarels *gp++ = *lp++; 41644405Skarels return (0); 4177498Sroot } 4187498Sroot 4197498Sroot /* 42037578Smckusick * Check if gid is a member of the group set. 42111810Ssam */ 42237578Smckusick groupmember(gid, cred) 42326275Skarels gid_t gid; 42437578Smckusick register struct ucred *cred; 4257866Sroot { 42618362Skarels register gid_t *gp; 42737578Smckusick gid_t *egp; 4287866Sroot 42937578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 43037578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4317866Sroot if (*gp == gid) 43237578Smckusick return (1); 43337578Smckusick return (0); 4347866Sroot } 4357866Sroot 43611810Ssam /* 43746293Skarels * Test whether the specified credentials imply "super-user" 43846293Skarels * privilege; if so, and we have accounting info, set the flag 43946293Skarels * indicating use of super-powers. 44046293Skarels * Returns 0 or error. 44111810Ssam */ 44237578Smckusick suser(cred, acflag) 44337578Smckusick struct ucred *cred; 44437578Smckusick short *acflag; 4457866Sroot { 44637578Smckusick if (cred->cr_uid == 0) { 44737578Smckusick if (acflag) 44837578Smckusick *acflag |= ASU; 44937578Smckusick return (0); 45018362Skarels } 45137578Smckusick return (EPERM); 4527866Sroot } 45311810Ssam 45411810Ssam /* 45537578Smckusick * Allocate a zeroed cred structure. 45611810Ssam */ 45737578Smckusick struct ucred * 45837578Smckusick crget() 45911810Ssam { 46037578Smckusick register struct ucred *cr; 46111810Ssam 46237578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 46337578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 46437578Smckusick cr->cr_ref = 1; 46543393Skarels return (cr); 46611810Ssam } 46737085Skfall 46837085Skfall /* 46937578Smckusick * Free a cred structure. 47037578Smckusick * Throws away space when ref count gets to 0. 47137085Skfall */ 47237578Smckusick crfree(cr) 47337578Smckusick struct ucred *cr; 47437578Smckusick { 47547540Skarels int s = splimp(); /* ??? */ 47637085Skfall 47737578Smckusick if (--cr->cr_ref != 0) { 47837578Smckusick (void) splx(s); 47937578Smckusick return; 48037578Smckusick } 48137578Smckusick FREE((caddr_t)cr, M_CRED); 48237578Smckusick (void) splx(s); 48337578Smckusick } 48437578Smckusick 48537578Smckusick /* 48637578Smckusick * Copy cred structure to a new one and free the old one. 48737578Smckusick */ 48837578Smckusick struct ucred * 48937578Smckusick crcopy(cr) 49037578Smckusick struct ucred *cr; 49137085Skfall { 49237578Smckusick struct ucred *newcr; 49337085Skfall 49445908Sbostic if (cr->cr_ref == 1) 49545908Sbostic return (cr); 49637578Smckusick newcr = crget(); 49737578Smckusick *newcr = *cr; 49837578Smckusick crfree(cr); 49937578Smckusick newcr->cr_ref = 1; 50043393Skarels return (newcr); 50137085Skfall } 50237085Skfall 50337085Skfall /* 50437578Smckusick * Dup cred struct to a new held one. 50537085Skfall */ 50637578Smckusick struct ucred * 50737578Smckusick crdup(cr) 50837578Smckusick struct ucred *cr; 50937085Skfall { 51037578Smckusick struct ucred *newcr; 51137085Skfall 51237578Smckusick newcr = crget(); 51337578Smckusick *newcr = *cr; 51437578Smckusick newcr->cr_ref = 1; 51543393Skarels return (newcr); 51637085Skfall } 51737579Smckusick 51837579Smckusick /* 51940667Skarels * Get login name, if available. 52037579Smckusick */ 52143393Skarels /* ARGSUSED */ 52243393Skarels getlogin(p, uap, retval) 52343393Skarels struct proc *p; 52443393Skarels struct args { 52537579Smckusick char *namebuf; 52637579Smckusick u_int namelen; 52743393Skarels } *uap; 52843393Skarels int *retval; 52943393Skarels { 53037579Smckusick 53147540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 53247540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 53347540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 53447540Skarels (caddr_t) uap->namebuf, uap->namelen)); 53537579Smckusick } 53637579Smckusick 53737579Smckusick /* 53840667Skarels * Set login name. 53937579Smckusick */ 54043393Skarels /* ARGSUSED */ 54143393Skarels setlogin(p, uap, retval) 54243393Skarels struct proc *p; 54343393Skarels struct args { 54443393Skarels char *namebuf; 54543393Skarels } *uap; 54643393Skarels int *retval; 54737579Smckusick { 54840667Skarels int error; 54937579Smckusick 55047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55144405Skarels return (error); 55247540Skarels error = copyinstr((caddr_t) uap->namebuf, 55347540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 55447540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 55547540Skarels if (error == ENAMETOOLONG) 55640667Skarels error = EINVAL; 55744405Skarels return (error); 55837579Smckusick } 559