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*54339Smckusick * @(#)kern_prot.c 7.23 (Berkeley) 06/23/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 2343393Skarels /* ARGSUSED */ 2443393Skarels getpid(p, uap, retval) 2543393Skarels struct proc *p; 2643393Skarels void *uap; 2743393Skarels int *retval; 2843393Skarels { 2937579Smckusick 3043393Skarels *retval = p->p_pid; 3152495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 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; 6752495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 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; 9252495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 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 { 17848990Skarels int pid; /* target process id */ 17948990Skarels int pgid; /* target pgrp id */ 18043393Skarels } *uap; 18143393Skarels int *retval; 18243393Skarels { 18347972Smarc register struct proc *targp; /* target process */ 18448990Skarels register struct pgrp *pgrp; /* target pgrp */ 1857498Sroot 18648990Skarels if (uap->pid != 0 && uap->pid != curp->p_pid) { 18748990Skarels 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); 19748990Skarels if (uap->pgid == 0) 19848990Skarels uap->pgid = targp->p_pid; 19948990Skarels else if (uap->pgid != targp->p_pid) 20048990Skarels if ((pgrp = pgfind(uap->pgid)) == 0 || 20148990Skarels pgrp->pg_session != curp->p_session) 20245908Sbostic return (EPERM); 20348990Skarels 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; 231*54339Smckusick p->p_flag |= SUGID; 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; 257*54339Smckusick p->p_flag |= SUGID; 25844405Skarels return (0); 25943393Skarels } 26043393Skarels 26143393Skarels /* ARGSUSED */ 26243393Skarels setgid(p, uap, retval) 26343393Skarels struct proc *p; 26443393Skarels struct args { 26543393Skarels int gid; 26643393Skarels } *uap; 26743393Skarels int *retval; 26843393Skarels { 26947540Skarels register struct pcred *pc = p->p_cred; 27043393Skarels register gid_t gid; 27143393Skarels int error; 27243393Skarels 27343393Skarels gid = uap->gid; 27447540Skarels if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 27544405Skarels return (error); 27647540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 27747540Skarels pc->pc_ucred->cr_groups[0] = gid; 27847540Skarels pc->p_rgid = gid; 27947540Skarels pc->p_svgid = gid; /* ??? */ 280*54339Smckusick p->p_flag |= SUGID; 28144405Skarels return (0); 28243393Skarels } 28343393Skarels 28443393Skarels /* ARGSUSED */ 28543393Skarels setegid(p, uap, retval) 28643393Skarels struct proc *p; 28743393Skarels struct args { 28843393Skarels int egid; 28943393Skarels } *uap; 29043393Skarels int *retval; 29143393Skarels { 29247540Skarels register struct pcred *pc = p->p_cred; 29343393Skarels register gid_t egid; 29443393Skarels int error; 29543393Skarels 29643393Skarels egid = uap->egid; 29747540Skarels if (egid != pc->p_rgid && egid != pc->p_svgid && 29847540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 29944405Skarels return (error); 30047540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 30147540Skarels pc->pc_ucred->cr_groups[0] = egid; 302*54339Smckusick p->p_flag |= SUGID; 30344405Skarels return (0); 30443393Skarels } 30543393Skarels 30652495Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 30743393Skarels /* ARGSUSED */ 30843393Skarels osetreuid(p, uap, retval) 30943393Skarels register struct proc *p; 31043393Skarels struct args { 3119160Ssam int ruid; 3129160Ssam int euid; 3139160Ssam } *uap; 31443393Skarels int *retval; 31543393Skarels { 31647540Skarels register struct pcred *pc = p->p_cred; 31743393Skarels register uid_t ruid, euid; 31843393Skarels int error; 3199160Ssam 32043393Skarels if (uap->ruid == -1) 32147540Skarels ruid = pc->p_ruid; 32243393Skarels else 32343393Skarels ruid = uap->ruid; 32443393Skarels /* 32545908Sbostic * Allow setting real uid to previous effective, for swapping real and 32645908Sbostic * effective. This should be: 32745908Sbostic * 32847540Skarels * if (ruid != pc->p_ruid && 32947540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 33043393Skarels */ 33147540Skarels if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && 33247540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 33344405Skarels return (error); 33443393Skarels if (uap->euid == -1) 33547540Skarels euid = pc->pc_ucred->cr_uid; 33643393Skarels else 33743393Skarels euid = uap->euid; 33847540Skarels if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && 33947540Skarels euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) 34044405Skarels return (error); 3419160Ssam /* 34245908Sbostic * Everything's okay, do it. Copy credentials so other references do 34345908Sbostic * not see our changes. 3449160Ssam */ 34547540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 34647540Skarels pc->pc_ucred->cr_uid = euid; 34747540Skarels pc->p_ruid = ruid; 348*54339Smckusick p->p_flag |= SUGID; 34944405Skarels return (0); 3509160Ssam } 3519160Ssam 35243393Skarels /* ARGSUSED */ 35343393Skarels osetregid(p, uap, retval) 35447540Skarels register struct proc *p; 35543393Skarels struct args { 3569160Ssam int rgid; 3579160Ssam int egid; 3589160Ssam } *uap; 35943393Skarels int *retval; 36043393Skarels { 36147540Skarels register struct pcred *pc = p->p_cred; 36243393Skarels register gid_t rgid, egid; 36343393Skarels int error; 3649160Ssam 36543393Skarels if (uap->rgid == -1) 36647540Skarels rgid = pc->p_rgid; 36743393Skarels else 36843393Skarels rgid = uap->rgid; 36943393Skarels /* 37045908Sbostic * Allow setting real gid to previous effective, for swapping real and 37145908Sbostic * effective. This didn't really work correctly in 4.[23], but is 37245908Sbostic * preserved so old stuff doesn't fail. This should be: 37345908Sbostic * 37447540Skarels * if (rgid != pc->p_rgid && 37547540Skarels * (error = suser(pc->pc_ucred, &p->p_acflag))) 37643393Skarels */ 37747540Skarels if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && 37847540Skarels (error = suser(pc->pc_ucred, &p->p_acflag))) 37944405Skarels return (error); 38043393Skarels if (uap->egid == -1) 38147540Skarels egid = pc->pc_ucred->cr_groups[0]; 38243393Skarels else 38343393Skarels egid = uap->egid; 38447540Skarels if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && 38547540Skarels egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 38644405Skarels return (error); 38747540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 38847540Skarels pc->pc_ucred->cr_groups[0] = egid; 38947540Skarels pc->p_rgid = rgid; 390*54339Smckusick p->p_flag |= SUGID; 39144405Skarels return (0); 3929160Ssam } 39352495Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 3949160Ssam 39543393Skarels /* ARGSUSED */ 39643393Skarels setgroups(p, uap, retval) 39743393Skarels struct proc *p; 39843393Skarels struct args { 3998624Sroot u_int gidsetsize; 4007498Sroot int *gidset; 40143393Skarels } *uap; 40243393Skarels int *retval; 40343393Skarels { 40447540Skarels register struct pcred *pc = p->p_cred; 40518362Skarels register gid_t *gp; 40644994Skarels register u_int ngrp; 40718362Skarels register int *lp; 40844942Sbostic int error, groups[NGROUPS]; 4097498Sroot 41047540Skarels if (error = suser(pc->pc_ucred, &p->p_acflag)) 41144405Skarels return (error); 41244994Skarels if ((ngrp = uap->gidsetsize) > NGROUPS) 41344405Skarels return (EINVAL); 41444942Sbostic if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 41544994Skarels ngrp * sizeof (groups[0]))) 41644405Skarels return (error); 41747540Skarels pc->pc_ucred = crcopy(pc->pc_ucred); 41847540Skarels pc->pc_ucred->cr_ngroups = ngrp; 41944942Sbostic /* convert from int's to gid_t's */ 42047540Skarels for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; ) 42144994Skarels *gp++ = *lp++; 422*54339Smckusick p->p_flag |= SUGID; 42344405Skarels return (0); 4247498Sroot } 4257498Sroot 4267498Sroot /* 42737578Smckusick * Check if gid is a member of the group set. 42811810Ssam */ 42937578Smckusick groupmember(gid, cred) 43026275Skarels gid_t gid; 43137578Smckusick register struct ucred *cred; 4327866Sroot { 43318362Skarels register gid_t *gp; 43437578Smckusick gid_t *egp; 4357866Sroot 43637578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 43737578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4387866Sroot if (*gp == gid) 43937578Smckusick return (1); 44037578Smckusick return (0); 4417866Sroot } 4427866Sroot 44311810Ssam /* 44446293Skarels * Test whether the specified credentials imply "super-user" 44546293Skarels * privilege; if so, and we have accounting info, set the flag 44646293Skarels * indicating use of super-powers. 44746293Skarels * Returns 0 or error. 44811810Ssam */ 44937578Smckusick suser(cred, acflag) 45037578Smckusick struct ucred *cred; 45137578Smckusick short *acflag; 4527866Sroot { 45337578Smckusick if (cred->cr_uid == 0) { 45437578Smckusick if (acflag) 45537578Smckusick *acflag |= ASU; 45637578Smckusick return (0); 45718362Skarels } 45837578Smckusick return (EPERM); 4597866Sroot } 46011810Ssam 46111810Ssam /* 46237578Smckusick * Allocate a zeroed cred structure. 46311810Ssam */ 46437578Smckusick struct ucred * 46537578Smckusick crget() 46611810Ssam { 46737578Smckusick register struct ucred *cr; 46811810Ssam 46937578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 47037578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 47137578Smckusick cr->cr_ref = 1; 47243393Skarels return (cr); 47311810Ssam } 47437085Skfall 47537085Skfall /* 47637578Smckusick * Free a cred structure. 47737578Smckusick * Throws away space when ref count gets to 0. 47837085Skfall */ 47937578Smckusick crfree(cr) 48037578Smckusick struct ucred *cr; 48137578Smckusick { 48247540Skarels int s = splimp(); /* ??? */ 48337085Skfall 48437578Smckusick if (--cr->cr_ref != 0) { 48537578Smckusick (void) splx(s); 48637578Smckusick return; 48737578Smckusick } 48837578Smckusick FREE((caddr_t)cr, M_CRED); 48937578Smckusick (void) splx(s); 49037578Smckusick } 49137578Smckusick 49237578Smckusick /* 49337578Smckusick * Copy cred structure to a new one and free the old one. 49437578Smckusick */ 49537578Smckusick struct ucred * 49637578Smckusick crcopy(cr) 49737578Smckusick struct ucred *cr; 49837085Skfall { 49937578Smckusick struct ucred *newcr; 50037085Skfall 50145908Sbostic if (cr->cr_ref == 1) 50245908Sbostic return (cr); 50337578Smckusick newcr = crget(); 50437578Smckusick *newcr = *cr; 50537578Smckusick crfree(cr); 50637578Smckusick newcr->cr_ref = 1; 50743393Skarels return (newcr); 50837085Skfall } 50937085Skfall 51037085Skfall /* 51137578Smckusick * Dup cred struct to a new held one. 51237085Skfall */ 51337578Smckusick struct ucred * 51437578Smckusick crdup(cr) 51537578Smckusick struct ucred *cr; 51637085Skfall { 51737578Smckusick struct ucred *newcr; 51837085Skfall 51937578Smckusick newcr = crget(); 52037578Smckusick *newcr = *cr; 52137578Smckusick newcr->cr_ref = 1; 52243393Skarels return (newcr); 52337085Skfall } 52437579Smckusick 52537579Smckusick /* 52640667Skarels * Get login name, if available. 52737579Smckusick */ 52843393Skarels /* ARGSUSED */ 52943393Skarels getlogin(p, uap, retval) 53043393Skarels struct proc *p; 53143393Skarels struct args { 53237579Smckusick char *namebuf; 53337579Smckusick u_int namelen; 53443393Skarels } *uap; 53543393Skarels int *retval; 53643393Skarels { 53737579Smckusick 53847540Skarels if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 53947540Skarels uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 54047540Skarels return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 54147540Skarels (caddr_t) uap->namebuf, uap->namelen)); 54237579Smckusick } 54337579Smckusick 54437579Smckusick /* 54540667Skarels * Set login name. 54637579Smckusick */ 54743393Skarels /* ARGSUSED */ 54843393Skarels setlogin(p, uap, retval) 54943393Skarels struct proc *p; 55043393Skarels struct args { 55143393Skarels char *namebuf; 55243393Skarels } *uap; 55343393Skarels int *retval; 55437579Smckusick { 55540667Skarels int error; 55637579Smckusick 55747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55844405Skarels return (error); 55947540Skarels error = copyinstr((caddr_t) uap->namebuf, 56047540Skarels (caddr_t) p->p_pgrp->pg_session->s_login, 56147540Skarels sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 56247540Skarels if (error == ENAMETOOLONG) 56340667Skarels error = EINVAL; 56444405Skarels return (error); 56537579Smckusick } 566