123372Smckusick /* 243393Skarels * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California. 337578Smckusick * All rights reserved. 423372Smckusick * 537578Smckusick * Redistribution and use in source and binary forms are permitted 637578Smckusick * provided that the above copyright notice and this paragraph are 737578Smckusick * duplicated in all such forms and that any documentation, 837578Smckusick * advertising materials, and other materials related to such 937578Smckusick * distribution and use acknowledge that the software was developed 1037578Smckusick * by the University of California, Berkeley. The name of the 1137578Smckusick * University may not be used to endorse or promote products derived 1237578Smckusick * from this software without specific prior written permission. 1337578Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437578Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537578Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637578Smckusick * 17*44405Skarels * @(#)kern_prot.c 7.12 (Berkeley) 06/28/90 1823372Smckusick */ 197420Sroot 207420Sroot /* 217498Sroot * System calls related to processes and protection 227420Sroot */ 237420Sroot 2417092Sbloom #include "param.h" 2537578Smckusick #include "acct.h" 2617092Sbloom #include "systm.h" 27*44405Skarels #include "user.h" 2817092Sbloom #include "proc.h" 2917092Sbloom #include "timeb.h" 3017092Sbloom #include "times.h" 3137578Smckusick #include "malloc.h" 327420Sroot 3343393Skarels /* ARGSUSED */ 3443393Skarels getpid(p, uap, retval) 3543393Skarels struct proc *p; 3643393Skarels void *uap; 3743393Skarels int *retval; 3843393Skarels { 3937579Smckusick 4043393Skarels *retval = p->p_pid; 4143393Skarels #ifdef COMPAT_43 4243393Skarels retval[1] = p->p_ppid; 4343393Skarels #endif 44*44405Skarels return (0); 4543393Skarels } 4643393Skarels 4743393Skarels /* ARGSUSED */ 4843393Skarels getppid(p, uap, retval) 4943393Skarels struct proc *p; 5043393Skarels void *uap; 5143393Skarels int *retval; 527498Sroot { 537498Sroot 5443393Skarels *retval = p->p_ppid; 55*44405Skarels return (0); 567498Sroot } 577498Sroot 5843393Skarels getpgrp(p, uap, retval) 5943393Skarels struct proc *p; 6043393Skarels struct args { 6143393Skarels int pid; 6243393Skarels } *uap; 6343393Skarels int *retval; 647498Sroot { 657498Sroot 6643393Skarels if (uap->pid != 0 && (p = pfind(uap->pid)) == 0) 67*44405Skarels return (ESRCH); 6843393Skarels *retval = p->p_pgrp->pg_id; 69*44405Skarels return (0); 707498Sroot } 717498Sroot 7243393Skarels /* ARGSUSED */ 7343393Skarels getuid(p, uap, retval) 7443393Skarels struct proc *p; 7543393Skarels void *uap; 7643393Skarels int *retval; 777420Sroot { 787420Sroot 7943393Skarels *retval = p->p_ruid; 8043393Skarels #ifdef COMPAT_43 8143393Skarels retval[1] = u.u_cred->cr_uid; 8243393Skarels #endif 83*44405Skarels return (0); 847420Sroot } 857420Sroot 8643393Skarels /* ARGSUSED */ 8743393Skarels geteuid(p, uap, retval) 8843393Skarels struct proc *p; 8943393Skarels void *uap; 9043393Skarels int *retval; 917498Sroot { 927498Sroot 9343393Skarels *retval = u.u_cred->cr_uid; 94*44405Skarels return (0); 957498Sroot } 967498Sroot 9743393Skarels /* ARGSUSED */ 9843393Skarels getgid(p, uap, retval) 9943393Skarels struct proc *p; 10043393Skarels void *uap; 10143393Skarels int *retval; 1027498Sroot { 10343393Skarels 10443393Skarels *retval = p->p_rgid; 10543393Skarels #ifdef COMPAT_43 10643393Skarels retval[1] = u.u_cred->cr_groups[0]; 10743393Skarels #endif 108*44405Skarels return (0); 10943393Skarels } 11043393Skarels 11143393Skarels /* 11243393Skarels * Get effective group ID. 11343393Skarels * The "egid" is groups[0], and thus could be obtained via getgroups; 11443393Skarels * this is somewhat painful to do correctly in a library function, 11543393Skarels * this the existence of this syscall. 11643393Skarels */ 11743393Skarels /* ARGSUSED */ 11843393Skarels getegid(p, uap, retval) 11943393Skarels struct proc *p; 12043393Skarels void *uap; 12143393Skarels int *retval; 12243393Skarels { 12343393Skarels 12443393Skarels *retval = u.u_cred->cr_groups[0]; 125*44405Skarels return (0); 12643393Skarels } 12743393Skarels 12843393Skarels getgroups(p, uap, retval) 12943393Skarels struct proc *p; 13043393Skarels register struct arg { 1318624Sroot u_int gidsetsize; 13243393Skarels int *gidset; /* XXX not yet POSIX */ 13343393Skarels } *uap; 13443393Skarels int *retval; 13543393Skarels { 13618362Skarels register gid_t *gp; 13718362Skarels register int *lp; 13818362Skarels int groups[NGROUPS]; 13943393Skarels int error; 1407498Sroot 14137578Smckusick if (uap->gidsetsize == 0) { 14243393Skarels *retval = u.u_cred->cr_ngroups; 143*44405Skarels return (0); 14437578Smckusick } 14543393Skarels if (uap->gidsetsize < u.u_cred->cr_ngroups) 146*44405Skarels return (EINVAL); 14740667Skarels uap->gidsetsize = u.u_cred->cr_ngroups; 14840667Skarels gp = u.u_cred->cr_groups; 14937578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 15018362Skarels *lp++ = *gp++; 15143393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 15243393Skarels uap->gidsetsize * sizeof (groups[0]))) 153*44405Skarels return (error); 15443393Skarels *retval = uap->gidsetsize; 155*44405Skarels return (0); 1567498Sroot } 1577498Sroot 15843393Skarels /* ARGSUSED */ 15943393Skarels setsid(p, uap, retval) 16043393Skarels struct proc *p; 16143393Skarels void *uap; 16243393Skarels int *retval; 16337579Smckusick { 16437579Smckusick 16543393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 166*44405Skarels return (EPERM); 16743393Skarels } else { 16837579Smckusick pgmv(p, p->p_pid, 1); 16943393Skarels *retval = p->p_pid; 170*44405Skarels return (0); 17137579Smckusick } 17237579Smckusick } 17337579Smckusick 17437579Smckusick /* 17543393Skarels * set process group (setpgrp/setpgid) 17637579Smckusick * 17740667Skarels * caller does setpgrp(pid, pgid) 17840667Skarels * 17940667Skarels * pid must be caller or child of caller (ESRCH) 18040667Skarels * if a child 18140667Skarels * pid must be in same session (EPERM) 18240667Skarels * pid can't have done an exec (EACCES) 18340667Skarels * if pgid != pid 18440667Skarels * there must exist some pid in same session having pgid (EPERM) 18540667Skarels * pid must not be session leader (EPERM) 18637579Smckusick */ 18743393Skarels /* ARGSUSED */ 18843393Skarels setpgrp(cp, uap, retval) 18943393Skarels struct proc *cp; 19043393Skarels register struct args { 1917498Sroot int pid; 19237579Smckusick int pgid; 19343393Skarels } *uap; 19443393Skarels int *retval; 19543393Skarels { 19637579Smckusick register struct proc *p; 19737579Smckusick register struct pgrp *pgrp; 1987498Sroot 19943393Skarels if (uap->pid != 0) { 20043393Skarels if ((p = pfind(uap->pid)) == 0 || !inferior(p)) 201*44405Skarels return (ESRCH); 20243393Skarels if (p->p_session != cp->p_session) 203*44405Skarels return (EPERM); 20443393Skarels if (p->p_flag&SEXEC) 205*44405Skarels return (EACCES); 20643393Skarels } else 20743393Skarels p = cp; 20843393Skarels if (SESS_LEADER(p)) 209*44405Skarels return (EPERM); 21037579Smckusick if (uap->pgid == 0) 21137579Smckusick uap->pgid = p->p_pid; 21237579Smckusick else if ((uap->pgid != p->p_pid) && 21337579Smckusick (((pgrp = pgfind(uap->pgid)) == 0) || 21437579Smckusick pgrp->pg_mem == NULL || 21543393Skarels pgrp->pg_session != u.u_procp->p_session)) 216*44405Skarels return (EPERM); 21737579Smckusick /* 21843393Skarels * done checking, now do it 21937579Smckusick */ 22037579Smckusick pgmv(p, uap->pgid, 0); 221*44405Skarels return (0); 2227498Sroot } 2237498Sroot 22443393Skarels /* ARGSUSED */ 22543393Skarels setuid(p, uap, retval) 22643393Skarels register struct proc *p; 22743393Skarels struct args { 22843393Skarels int uid; 22943393Skarels } *uap; 23043393Skarels int *retval; 2317420Sroot { 23243393Skarels register uid_t uid; 23343393Skarels int error; 23443393Skarels 23543393Skarels uid = uap->uid; 23643393Skarels if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 237*44405Skarels return (error); 23843393Skarels /* 23943393Skarels * Everything's okay, do it. 24043393Skarels * Copy credentials so other references do not 24143393Skarels * see our changes. 24243393Skarels */ 24343393Skarels if (u.u_cred->cr_ref > 1) 24443393Skarels u.u_cred = crcopy(u.u_cred); 24543393Skarels u.u_cred->cr_uid = uid; 24643393Skarels p->p_uid = uid; 24743393Skarels p->p_ruid = uid; 24843393Skarels p->p_svuid = uid; 249*44405Skarels return (0); 25043393Skarels } 25143393Skarels 25243393Skarels /* ARGSUSED */ 25343393Skarels seteuid(p, uap, retval) 25443393Skarels register struct proc *p; 25543393Skarels struct args { 25643393Skarels int euid; 25743393Skarels } *uap; 25843393Skarels int *retval; 25943393Skarels { 26043393Skarels register uid_t euid; 26143393Skarels int error; 26243393Skarels 26343393Skarels euid = uap->euid; 26443393Skarels if (euid != p->p_ruid && euid != p->p_svuid && 26543393Skarels (error = suser(u.u_cred, &u.u_acflag))) 266*44405Skarels return (error); 26743393Skarels /* 26843393Skarels * Everything's okay, do it. 26943393Skarels * Copy credentials so other references do not 27043393Skarels * see our changes. 27143393Skarels */ 27243393Skarels if (u.u_cred->cr_ref > 1) 27343393Skarels u.u_cred = crcopy(u.u_cred); 27443393Skarels u.u_cred->cr_uid = euid; 27543393Skarels p->p_uid = euid; 276*44405Skarels return (0); 27743393Skarels } 27843393Skarels 27943393Skarels /* ARGSUSED */ 28043393Skarels setgid(p, uap, retval) 28143393Skarels struct proc *p; 28243393Skarels struct args { 28343393Skarels int gid; 28443393Skarels } *uap; 28543393Skarels int *retval; 28643393Skarels { 28743393Skarels register gid_t gid; 28843393Skarels int error; 28943393Skarels 29043393Skarels gid = uap->gid; 29143393Skarels if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 292*44405Skarels return (error); 29343393Skarels if (u.u_cred->cr_ref > 1) 29443393Skarels u.u_cred = crcopy(u.u_cred); 29543393Skarels p->p_rgid = gid; 29643393Skarels u.u_cred->cr_groups[0] = gid; 29743393Skarels p->p_svgid = gid; /* ??? */ 298*44405Skarels return (0); 29943393Skarels } 30043393Skarels 30143393Skarels /* ARGSUSED */ 30243393Skarels setegid(p, uap, retval) 30343393Skarels struct proc *p; 30443393Skarels struct args { 30543393Skarels int egid; 30643393Skarels } *uap; 30743393Skarels int *retval; 30843393Skarels { 30943393Skarels register gid_t egid; 31043393Skarels int error; 31143393Skarels 31243393Skarels egid = uap->egid; 31343393Skarels if (egid != p->p_rgid && egid != p->p_svgid && 31443393Skarels (error = suser(u.u_cred, &u.u_acflag))) 315*44405Skarels return (error); 31643393Skarels if (u.u_cred->cr_ref > 1) 31743393Skarels u.u_cred = crcopy(u.u_cred); 31843393Skarels u.u_cred->cr_groups[0] = egid; 319*44405Skarels return (0); 32043393Skarels } 32143393Skarels 32243393Skarels #ifdef COMPAT_43 32343393Skarels /* ARGSUSED */ 32443393Skarels osetreuid(p, uap, retval) 32543393Skarels register struct proc *p; 32643393Skarels struct args { 3279160Ssam int ruid; 3289160Ssam int euid; 3299160Ssam } *uap; 33043393Skarels int *retval; 33143393Skarels { 33243393Skarels register uid_t ruid, euid; 33343393Skarels int error; 3349160Ssam 33543393Skarels if (uap->ruid == -1) 33640667Skarels ruid = p->p_ruid; 33743393Skarels else 33843393Skarels ruid = uap->ruid; 33943393Skarels /* 34043393Skarels * Allow setting real uid to previous effective, 34143393Skarels * for swapping real and effective. 34243393Skarels * This should be: 34343393Skarels * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 34443393Skarels */ 34540667Skarels if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 34643393Skarels (error = suser(u.u_cred, &u.u_acflag))) 347*44405Skarels return (error); 34843393Skarels if (uap->euid == -1) 34940667Skarels euid = u.u_cred->cr_uid; 35043393Skarels else 35143393Skarels euid = uap->euid; 35240667Skarels if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 35343393Skarels euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag))) 354*44405Skarels return (error); 3559160Ssam /* 3569160Ssam * Everything's okay, do it. 35737578Smckusick * Copy credentials so other references do not 35837578Smckusick * see our changes. 3599160Ssam */ 36037578Smckusick if (u.u_cred->cr_ref > 1) 36137578Smckusick u.u_cred = crcopy(u.u_cred); 36240667Skarels u.u_cred->cr_uid = euid; 36340667Skarels p->p_uid = euid; 36440667Skarels p->p_ruid = ruid; 365*44405Skarels return (0); 3669160Ssam } 3679160Ssam 36843393Skarels /* ARGSUSED */ 36943393Skarels osetregid(p, uap, retval) 37043393Skarels struct proc *p; 37143393Skarels struct args { 3729160Ssam int rgid; 3739160Ssam int egid; 3749160Ssam } *uap; 37543393Skarels int *retval; 37643393Skarels { 37743393Skarels register gid_t rgid, egid; 37843393Skarels int error; 3799160Ssam 38043393Skarels if (uap->rgid == -1) 38140667Skarels rgid = p->p_rgid; 38243393Skarels else 38343393Skarels rgid = uap->rgid; 38443393Skarels /* 38543393Skarels * Allow setting real gid to previous effective, 38643393Skarels * for swapping real and effective. This didn't really work 38743393Skarels * correctly in 4.[23], but is preserved so old stuff doesn't fail. 38843393Skarels * This should be: 38943393Skarels * if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 39043393Skarels */ 39140667Skarels if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 39243393Skarels (error = suser(u.u_cred, &u.u_acflag))) 393*44405Skarels return (error); 39443393Skarels if (uap->egid == -1) 39540667Skarels egid = u.u_cred->cr_groups[0]; 39643393Skarels else 39743393Skarels egid = uap->egid; 39840667Skarels if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 39943393Skarels egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag))) 400*44405Skarels return (error); 40137578Smckusick if (u.u_cred->cr_ref > 1) 40237578Smckusick u.u_cred = crcopy(u.u_cred); 40340667Skarels p->p_rgid = rgid; 40440667Skarels u.u_cred->cr_groups[0] = egid; 405*44405Skarels return (0); 4069160Ssam } 40743393Skarels #endif 4089160Ssam 40943393Skarels /* ARGSUSED */ 41043393Skarels setgroups(p, uap, retval) 41143393Skarels struct proc *p; 41243393Skarels struct args { 4138624Sroot u_int gidsetsize; 4147498Sroot int *gidset; 41543393Skarels } *uap; 41643393Skarels int *retval; 41743393Skarels { 41818362Skarels register gid_t *gp; 41918362Skarels register int *lp; 42043393Skarels int error, ngrp, groups[NGROUPS]; 4217498Sroot 42243393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 423*44405Skarels return (error); 42440667Skarels ngrp = uap->gidsetsize; 42543393Skarels if (ngrp > NGROUPS) 426*44405Skarels return (EINVAL); 42743393Skarels error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 42818362Skarels uap->gidsetsize * sizeof (groups[0])); 42943393Skarels if (error) 430*44405Skarels return (error); 43140667Skarels gp = u.u_cred->cr_groups; 43237578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 43318362Skarels *gp++ = *lp++; 43440667Skarels u.u_cred->cr_ngroups = ngrp; 435*44405Skarels return (0); 4367498Sroot } 4377498Sroot 4387498Sroot /* 43937578Smckusick * Check if gid is a member of the group set. 44011810Ssam */ 44137578Smckusick groupmember(gid, cred) 44226275Skarels gid_t gid; 44337578Smckusick register struct ucred *cred; 4447866Sroot { 44518362Skarels register gid_t *gp; 44637578Smckusick gid_t *egp; 4477866Sroot 44837578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 44937578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4507866Sroot if (*gp == gid) 45137578Smckusick return (1); 45237578Smckusick return (0); 4537866Sroot } 4547866Sroot 45511810Ssam /* 45637578Smckusick * Test if the current user is the super user. 45711810Ssam */ 45837578Smckusick suser(cred, acflag) 45937578Smckusick struct ucred *cred; 46037578Smckusick short *acflag; 4617866Sroot { 4627866Sroot 46337578Smckusick if (cred->cr_uid == 0) { 46437578Smckusick if (acflag) 46537578Smckusick *acflag |= ASU; 46637578Smckusick return (0); 46718362Skarels } 46837578Smckusick return (EPERM); 4697866Sroot } 47011810Ssam 47111810Ssam /* 47237578Smckusick * Allocate a zeroed cred structure. 47311810Ssam */ 47437578Smckusick struct ucred * 47537578Smckusick crget() 47611810Ssam { 47737578Smckusick register struct ucred *cr; 47811810Ssam 47937578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 48037578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 48137578Smckusick cr->cr_ref = 1; 48243393Skarels return (cr); 48311810Ssam } 48437085Skfall 48537085Skfall /* 48637578Smckusick * Free a cred structure. 48737578Smckusick * Throws away space when ref count gets to 0. 48837085Skfall */ 48937578Smckusick crfree(cr) 49037578Smckusick struct ucred *cr; 49137578Smckusick { 49243393Skarels int s = splimp(); 49337085Skfall 49437578Smckusick if (--cr->cr_ref != 0) { 49537578Smckusick (void) splx(s); 49637578Smckusick return; 49737578Smckusick } 49837578Smckusick FREE((caddr_t)cr, M_CRED); 49937578Smckusick (void) splx(s); 50037578Smckusick } 50137578Smckusick 50237578Smckusick /* 50337578Smckusick * Copy cred structure to a new one and free the old one. 50437578Smckusick */ 50537578Smckusick struct ucred * 50637578Smckusick crcopy(cr) 50737578Smckusick struct ucred *cr; 50837085Skfall { 50937578Smckusick struct ucred *newcr; 51037085Skfall 51137578Smckusick newcr = crget(); 51237578Smckusick *newcr = *cr; 51337578Smckusick crfree(cr); 51437578Smckusick newcr->cr_ref = 1; 51543393Skarels return (newcr); 51637085Skfall } 51737085Skfall 51837085Skfall /* 51937578Smckusick * Dup cred struct to a new held one. 52037085Skfall */ 52137578Smckusick struct ucred * 52237578Smckusick crdup(cr) 52337578Smckusick struct ucred *cr; 52437085Skfall { 52537578Smckusick struct ucred *newcr; 52637085Skfall 52737578Smckusick newcr = crget(); 52837578Smckusick *newcr = *cr; 52937578Smckusick newcr->cr_ref = 1; 53043393Skarels return (newcr); 53137085Skfall } 53237579Smckusick 53337579Smckusick /* 53440667Skarels * Get login name, if available. 53537579Smckusick */ 53643393Skarels /* ARGSUSED */ 53743393Skarels getlogin(p, uap, retval) 53843393Skarels struct proc *p; 53943393Skarels struct args { 54037579Smckusick char *namebuf; 54137579Smckusick u_int namelen; 54243393Skarels } *uap; 54343393Skarels int *retval; 54443393Skarels { 54537579Smckusick 54643393Skarels if (uap->namelen > sizeof (p->p_logname)) 54743393Skarels uap->namelen = sizeof (p->p_logname); 548*44405Skarels return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 54943393Skarels uap->namelen)); 55037579Smckusick } 55137579Smckusick 55237579Smckusick /* 55340667Skarels * Set login name. 55437579Smckusick */ 55543393Skarels /* ARGSUSED */ 55643393Skarels setlogin(p, uap, retval) 55743393Skarels struct proc *p; 55843393Skarels struct args { 55943393Skarels char *namebuf; 56043393Skarels } *uap; 56143393Skarels int *retval; 56237579Smckusick { 56340667Skarels int error; 56437579Smckusick 56543393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 566*44405Skarels return (error); 56743393Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 56843393Skarels sizeof (p->p_logname) - 1, (int *) 0); 56940667Skarels if (error == ENOENT) /* name too long */ 57040667Skarels error = EINVAL; 571*44405Skarels return (error); 57237579Smckusick } 573