update from Rick Macklem to generate proper error messages
[unix-history] / usr / src / sys / kern / kern_prot.c
index 1df99f2..4ccfd65 100644 (file)
@@ -1,25 +1,41 @@
-/*     kern_prot.c     5.15    83/02/20        */
+/*
+ * 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
  */
 
 
 /*
  * System calls related to processes and protection
  */
 
-#include "../machine/reg.h"
-
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/inode.h"
-#include "../h/proc.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()
 {
 
 getpid()
 {
@@ -36,13 +52,12 @@ getpgrp()
        register struct proc *p;
 
        if (uap->pid == 0)
        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_error = ESRCH;
                return;
        }
-       u.u_r.r_val1 = p->p_pgrp;
+       u.u_r.r_val1 = p->p_pgrp->pg_id;
 }
 
 getuid()
 }
 
 getuid()
@@ -65,44 +80,94 @@ getgroups()
                u_int   gidsetsize;
                int     *gidset;
        } *uap = (struct a *)u.u_ap;
                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) {
+       if (uap->gidsetsize == 0) {
+               u.u_r.r_val1 = u.u_ngroups - GRPSTART;
+               return;
+       }
+       if (uap->gidsetsize < u.u_ngroups - GRPSTART) {
                u.u_error = EINVAL;
                return;
        }
                u.u_error = EINVAL;
                return;
        }
-       uap->gidsetsize = gp - u.u_groups;
-       u.u_error = copyout((caddr_t)u.u_groups, (caddr_t)uap->gidset,
-           uap->gidsetsize * sizeof (u.u_groups[0]));
+       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;
 }
 
        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()
 {
 setpgrp()
 {
-       register struct proc *p;
        register struct a {
                int     pid;
        register struct a {
                int     pid;
-               int     pgrp;
+               int     pgid;
        } *uap = (struct a *)u.u_ap;
        } *uap = (struct a *)u.u_ap;
+       register struct proc *p;
+       register struct pgrp *pgrp;
 
        if (uap->pid == 0)
 
        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;
        }
                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;
+       }
+       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;
        }
                u.u_error = EPERM;
                return;
        }
-       p->p_pgrp = uap->pgrp;
+       /*
+        * done checking, now doit
+        */
+       pgmv(p, uap->pgid, 0);
 }
 
 setreuid()
 }
 
 setreuid()
@@ -117,51 +182,29 @@ setreuid()
        ruid = uap->ruid;
        if (ruid == -1)
                ruid = u.u_ruid;
        ruid = uap->ruid;
        if (ruid == -1)
                ruid = u.u_ruid;
-       if (u.u_ruid != ruid && u.u_uid != ruid && !suser())
                return;
        euid = uap->euid;
        if (euid == -1)
                euid = u.u_uid;
                return;
        euid = uap->euid;
        if (euid == -1)
                euid = u.u_uid;
-       if (u.u_ruid != euid && u.u_uid != euid && !suser())
                return;
        /*
         * Everything's okay, do it.
                return;
        /*
         * Everything's okay, do it.
+        * Copy credentials so other references do not
+        * see our changes.
         */
 #ifdef QUOTA
        if (u.u_quota->q_uid != ruid) {
                qclean();
         */
 #ifdef QUOTA
        if (u.u_quota->q_uid != ruid) {
                qclean();
-               qstart(getquota(ruid, 0, 0));
+               qstart(getquota((uid_t)ruid, 0, 0));
        }
 #endif
        }
 #endif
-       u.u_procp->p_uid = ruid;
+       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;
 }
 
        u.u_ruid = ruid;
        u.u_uid = euid;
 }
 
-#ifndef NOCOMPAT
-osetuid()
-{
-       register uid;
-       register struct a {
-               int     uid;
-       } *uap;
-
-       uap = (struct a *)u.u_ap;
-       uid = uap->uid;
-       if (u.u_ruid == uid || u.u_uid == uid || suser()) {
-#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;
-       }
-}
-#endif
-
 setregid()
 {
        register struct a {
 setregid()
 {
        register struct a {
@@ -174,123 +217,174 @@ setregid()
        rgid = uap->rgid;
        if (rgid == -1)
                rgid = u.u_rgid;
        rgid = uap->rgid;
        if (rgid == -1)
                rgid = u.u_rgid;
-       if (u.u_rgid != rgid && u.u_gid != rgid && !suser())
                return;
        egid = uap->egid;
        if (egid == -1)
                egid = u.u_gid;
                return;
        egid = uap->egid;
        if (egid == -1)
                egid = u.u_gid;
-       if (u.u_rgid != egid && u.u_gid != egid && !suser())
                return;
                return;
-       if (u.u_rgid != rgid) {
-               leavegroup(u.u_rgid);
-               (void) entergroup(rgid);
-               u.u_rgid = rgid;
-       }
+       if (u.u_cred->cr_ref > 1)
+               u.u_cred = crcopy(u.u_cred);
+       u.u_rgid = rgid;
        u.u_gid = egid;
 }
 
        u.u_gid = egid;
 }
 
-#ifndef NOCOMPAT
-osetgid()
-{
-       register gid;
-       register struct a {
-               int     gid;
-       } *uap;
-
-       uap = (struct a *)u.u_ap;
-       gid = uap->gid;
-       if (u.u_rgid == gid || u.u_gid == gid || suser()) {
-               leavegroup(u.u_rgid);
-               (void) entergroup(gid);
-               u.u_gid = gid;
-               u.u_rgid = gid;
-       }
-}
-
 setgroups()
 {
        register struct a {
                u_int   gidsetsize;
                int     *gidset;
        } *uap = (struct a *)u.u_ap;
 setgroups()
 {
        register struct a {
                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;
                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;
        }
                u.u_error = EINVAL;
                return;
        }
-       u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)u.u_groups,
-           uap->gidsetsize * sizeof (u.u_groups[0]));
+       u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
+           uap->gidsetsize * sizeof (groups[0]));
        if (u.u_error)
                return;
        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;
        }
                return;
        }
-       p->p_pgrp = uap->pgrp;
+       FREE((caddr_t)cr, M_CRED);
+       (void) splx(s);
+}
+
+/*
+ * Copy cred structure to a new one and free the old one.
+ */
+struct ucred *
+crcopy(cr)
+       struct ucred *cr;
+{
+       struct ucred *newcr;
+
+       newcr = crget();
+       *newcr = *cr;
+       crfree(cr);
+       newcr->cr_ref = 1;
+       return(newcr);
 }
 }
-/* END DEFUNCT */
 
 
-leavegroup(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)
-                       goto found;
-       return;
-found:
-       for (; gp < &u.u_groups[NGROUPS-1]; gp++)
-               *gp = *(gp+1);
-       *gp = -1;
+       newcr = crget();
+       *newcr = *cr;
+       newcr->cr_ref = 1;
+       return(newcr);
 }
 
 }
 
-entergroup(gid)
-       int gid;
+/*
+ * Get login name of process owner, if available
+ */
+
+getlogname()
 {
 {
-       register int *gp;
+       struct a {
+               char    *namebuf;
+               u_int   namelen;
+       } *uap = (struct a *)u.u_ap;
 
 
-       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);
+       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);
+       }
 }
 }