X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b724ad1fbeaf3dd78823ad5ec8c2bf5a264314a3..a2f658f997662926f2a54d337f2ed9abde78f991:/usr/src/sys/kern/kern_prot.c diff --git a/usr/src/sys/kern/kern_prot.c b/usr/src/sys/kern/kern_prot.c index 715ede3638..4ccfd65783 100644 --- a/usr/src/sys/kern/kern_prot.c +++ b/usr/src/sys/kern/kern_prot.c @@ -1,26 +1,41 @@ -/* kern_prot.c 5.5 82/08/24 */ +/* + * Copyright (c) 1982, 1986, 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)kern_prot.c 7.7 (Berkeley) %G% + */ /* * System calls related to processes and protection */ -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/reg.h" -#include "../h/inode.h" -#include "../h/proc.h" -#include "../h/clock.h" -#include "../h/mtpr.h" -#include "../h/timeb.h" -#include "../h/times.h" -#include "../h/reboot.h" -#include "../h/fs.h" -#include "../h/conf.h" -#include "../h/buf.h" -#include "../h/mount.h" -#include "../h/quota.h" +#include "param.h" +#include "acct.h" +#include "systm.h" +#include "user.h" +#include "proc.h" +#include "timeb.h" +#include "times.h" +#include "reboot.h" +#include "mount.h" +#include "buf.h" +#include "../ufs/quota.h" +#include "malloc.h" +#define GRPSTART 0 + +#include "machine/reg.h" getpid() { @@ -37,13 +52,12 @@ getpgrp() register struct proc *p; if (uap->pid == 0) - uap->pid = u.u_procp->p_pid; - p = pfind(uap->pid); - if (p == 0) { + p = u.u_procp; + else if ((p = pfind(uap->pid)) == 0) { u.u_error = ESRCH; return; } - u.u_r.r_val1 = p->p_pgrp; + u.u_r.r_val1 = p->p_pgrp->pg_id; } getuid() @@ -63,174 +77,314 @@ getgid() getgroups() { register struct a { - int gidsetsize; + u_int gidsetsize; int *gidset; } *uap = (struct a *)u.u_ap; - register int *gp; + register gid_t *gp; + register int *lp; + int groups[NGROUPS]; - for (gp = &u.u_groups[NGROUPS]; gp > u.u_groups; gp--) - if (gp[-1] >= 0) - break; - if (uap->gidsetsize < gp - u.u_groups) { - u.u_error = EINVAL; + if (uap->gidsetsize == 0) { + u.u_r.r_val1 = u.u_ngroups - GRPSTART; return; } - uap->gidsetsize = gp - u.u_groups; - if (copyout((caddr_t)u.u_groups, (caddr_t)uap->gidset, - uap->gidsetsize * sizeof (u.u_groups[0]))) { - u.u_error = EFAULT; + if (uap->gidsetsize < u.u_ngroups - GRPSTART) { + u.u_error = EINVAL; return; } + uap->gidsetsize = u.u_ngroups - GRPSTART; + gp = &u.u_groups[GRPSTART]; + for (lp = groups; lp < &groups[uap->gidsetsize]; ) + *lp++ = *gp++; + u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset, + uap->gidsetsize * sizeof (groups[0])); + if (u.u_error) + return; u.u_r.r_val1 = uap->gidsetsize; } +setsid() +{ + register struct proc *p = u.u_procp; + + if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid)) + u.u_error = EPERM; + else { + pgmv(p, p->p_pid, 1); + u.u_r.r_val1 = p->p_pid; + } + return; +} + +/* + * set process group + * + * if target pid != caller's pid + * pid must be an inferior + * pid must be in same session + * pid can't have done an exec + * there must exist a pid with pgid in same session + * pid must not be session leader + */ setpgrp() { - register struct proc *p; register struct a { int pid; - int pgrp; + int pgid; } *uap = (struct a *)u.u_ap; + register struct proc *p; + register struct pgrp *pgrp; if (uap->pid == 0) - uap->pid = u.u_procp->p_pid; - p = pfind(uap->pid); - if (p == 0) { + p = u.u_procp; + else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) { u.u_error = ESRCH; return; } -/* need better control mechanisms for process groups */ - if (p->p_uid != u.u_uid && u.u_uid && !inferior(p)) { + else if (p != u.u_procp) { + if (p->p_session != u.u_procp->p_session) { + u.u_error = EPERM; + return; + } + if (p->p_flag&SEXEC) { + u.u_error = EACCES; + return; + } + } + if (SESS_LEADER(p)) { u.u_error = EPERM; return; } - p->p_pgrp = uap->pgrp; + if (uap->pgid == 0) + uap->pgid = p->p_pid; + else if ((uap->pgid != p->p_pid) && + (((pgrp = pgfind(uap->pgid)) == 0) || + pgrp->pg_mem == NULL || + pgrp->pg_session != u.u_procp->p_session)) { + u.u_error = EPERM; + return; + } + /* + * done checking, now doit + */ + pgmv(p, uap->pgid, 0); } -setuid() +setreuid() { - register uid; - register struct a { - int uid; + struct a { + int ruid; + int euid; } *uap; + register int ruid, euid; uap = (struct a *)u.u_ap; - uid = uap->uid; - if (u.u_ruid == uid || u.u_uid == uid || suser()) { + ruid = uap->ruid; + if (ruid == -1) + ruid = u.u_ruid; + return; + euid = uap->euid; + if (euid == -1) + euid = u.u_uid; + return; + /* + * Everything's okay, do it. + * Copy credentials so other references do not + * see our changes. + */ #ifdef QUOTA - if (u.u_quota->q_uid != uid) { - qclean(); - qstart(getquota(uid, 0, 0)); - } -#endif - u.u_uid = uid; - u.u_procp->p_uid = uid; - u.u_ruid = uid; + if (u.u_quota->q_uid != ruid) { + qclean(); + qstart(getquota((uid_t)ruid, 0, 0)); } +#endif + if (u.u_cred->cr_ref > 1) + u.u_cred = crcopy(u.u_cred); + u.u_procp->p_uid = euid; + u.u_ruid = ruid; + u.u_uid = euid; } -setgid() +setregid() { - register gid; register struct a { - int gid; + int rgid; + int egid; } *uap; + register int rgid, egid; uap = (struct a *)u.u_ap; - gid = uap->gid; - if (u.u_rgid == gid || u.u_gid == gid || suser()) { - leavegroup(u.u_gid); leavegroup(u.u_rgid); - (void) entergroup(gid); - u.u_gid = gid; - u.u_rgid = gid; - } + rgid = uap->rgid; + if (rgid == -1) + rgid = u.u_rgid; + return; + egid = uap->egid; + if (egid == -1) + egid = u.u_gid; + return; + if (u.u_cred->cr_ref > 1) + u.u_cred = crcopy(u.u_cred); + u.u_rgid = rgid; + u.u_gid = egid; } setgroups() { register struct a { - int gidsetsize; + u_int gidsetsize; int *gidset; } *uap = (struct a *)u.u_ap; - register int *gp; + register gid_t *gp; + register int *lp; + int ngrp, groups[NGROUPS]; - if (suser()) + if (u.u_error = suser(u.u_cred, &u.u_acflag)) return; - if (uap->gidsetsize > sizeof (u.u_groups) / sizeof (u.u_groups[0])) { + ngrp = uap->gidsetsize + GRPSTART; + if (ngrp > sizeof (u.u_groups) / sizeof (u.u_groups[0])) { u.u_error = EINVAL; return; } - if (copyin((caddr_t)uap->gidset, (caddr_t)u.u_groups, - uap->gidsetsize * sizeof (u.u_groups[0]))) { - u.u_error = EFAULT; + u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups, + uap->gidsetsize * sizeof (groups[0])); + if (u.u_error) return; - } - for (gp = &u.u_groups[uap->gidsetsize]; gp < &u.u_groups[NGROUPS]; gp++) - *gp = -1; + gp = &u.u_groups[GRPSTART]; + for (lp = groups; lp < &groups[uap->gidsetsize]; ) + *gp++ = *lp++; + u.u_ngroups = ngrp; } /* - * Pid of zero implies current process. - * Pgrp -1 is getpgrp system call returning - * current process group. + * Check if gid is a member of the group set. */ -osetpgrp() +groupmember(gid, cred) + gid_t gid; + register struct ucred *cred; { - register struct proc *p; - register struct a { - int pid; - int pgrp; - } *uap; + register gid_t *gp; + gid_t *egp; - uap = (struct a *)u.u_ap; - if (uap->pid == 0) - p = u.u_procp; - else { - p = pfind(uap->pid); - if (p == 0) { - u.u_error = ESRCH; - return; - } - } - if (uap->pgrp <= 0) { - u.u_r.r_val1 = p->p_pgrp; - return; + egp = &(cred->cr_groups[cred->cr_ngroups]); + for (gp = cred->cr_groups; gp < egp; gp++) + if (*gp == gid) + return (1); + return (0); +} + +/* + * Test if the current user is the super user. + */ +suser(cred, acflag) + struct ucred *cred; + short *acflag; +{ + + if (cred->cr_uid == 0) { + if (acflag) + *acflag |= ASU; + return (0); } - if (p->p_uid != u.u_uid && u.u_uid && !inferior(p)) { - u.u_error = EPERM; + return (EPERM); +} + +/* + * Allocate a zeroed cred structure. + */ +struct ucred * +crget() +{ + register struct ucred *cr; + + MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); + bzero((caddr_t)cr, sizeof(*cr)); + cr->cr_ref = 1; + return(cr); +} + +/* + * Free a cred structure. + * Throws away space when ref count gets to 0. + */ +crfree(cr) + struct ucred *cr; +{ + int s = splimp(); + + if (--cr->cr_ref != 0) { + (void) splx(s); return; } - p->p_pgrp = uap->pgrp; + FREE((caddr_t)cr, M_CRED); + (void) splx(s); } -/* END DEFUNCT */ -leavegroup(gid) - int gid; +/* + * Copy cred structure to a new one and free the old one. + */ +struct ucred * +crcopy(cr) + struct ucred *cr; { - register int *gp; + struct ucred *newcr; - for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++) - if (*gp == gid) - goto found; - return; -found: - for (; gp < &u.u_groups[NGROUPS-1]; gp++) - *gp = *(gp+1); - *gp = -1; + newcr = crget(); + *newcr = *cr; + crfree(cr); + newcr->cr_ref = 1; + return(newcr); } -entergroup(gid) - int gid; +/* + * Dup cred struct to a new held one. + */ +struct ucred * +crdup(cr) + struct ucred *cr; { - register int *gp; + struct ucred *newcr; - for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++) - if (*gp == gid) - return (0); - for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++) - if (*gp < 0) { - *gp = gid; - return (0); - } - return (-1); + newcr = crget(); + *newcr = *cr; + newcr->cr_ref = 1; + return(newcr); +} + +/* + * Get login name of process owner, if available + */ + +getlogname() +{ + struct a { + char *namebuf; + u_int namelen; + } *uap = (struct a *)u.u_ap; + + if (uap->namelen > sizeof (u.u_logname)) + uap->namelen = sizeof (u.u_logname); + u.u_error = copyout((caddr_t)u.u_logname, (caddr_t)uap->namebuf, + uap->namelen); +} + +/* + * Set login name of process owner + */ + +setlogname() +{ + struct a { + char *namebuf; + u_int namelen; + } *uap = (struct a *)u.u_ap; + + if (u.u_error = suser(u.u_cred, &u.u_acflag)) + return; + if (uap->namelen > sizeof (u.u_logname) - 1) + u.u_error = EINVAL; + else { + u.u_logname[uap->namelen] = NULL; + u.u_error = copyin((caddr_t)uap->namebuf, + (caddr_t)u.u_logname, uap->namelen); + } }