I have a working version of the keymap protection sysctl stuff now.
I actually ended up with more levels than I initially thought I
would:

>= 1: Only root can change restricted keys (like boot, panic, ...)
>= 2: Only root can change restricted keys and regular keys.
      Regular users still can change accents and function keys.
>= 3: Only root can change restricted keys, regular keys and accents.
>= 4: Only root can change any of the keymap.

There are two small problems. First is that the sysctl is called
kern.keymap_protection - this should probably be somthing different.
Second, the kbd driver clears the keyboard's accent map if you load
a new keymap, which makes the distinction between level 3 and level
4 less useful.

        David.


Index: kbd.c
===================================================================
RCS file: /cvs/FreeBSD-CVS/src/sys/dev/kbd/kbd.c,v
retrieving revision 1.26
diff -u -r1.26 kbd.c
--- kbd.c       20 Jul 2001 13:05:56 -0000      1.26
+++ kbd.c       30 Aug 2001 10:37:17 -0000
@@ -35,6 +35,8 @@
 #include <sys/conf.h>
 #include <sys/tty.h>
 #include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
 #include <sys/vnode.h>
 #include <sys/uio.h>
 
@@ -766,6 +768,11 @@
  * functions.
  */
 
+static int key_change_ok(struct keyent_t *, struct keyent_t *, struct proc *);
+static int keymap_change_ok(keymap_t *, keymap_t *, struct proc *);
+static int accent_change_ok(accentmap_t *, accentmap_t *, struct proc *);
+static int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct proc *);
+
 int
 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
 {
@@ -773,6 +780,7 @@
        fkeyarg_t *fkeyp;
        int s;
        int i;
+       int error;
 
        s = spltty();
        switch (cmd) {
@@ -802,6 +810,12 @@
                break;
        case PIO_KEYMAP:        /* set keyboard translation table */
 #ifndef KBD_DISABLE_KEYMAP_LOAD
+               error = keymap_change_ok(kbd->kb_keymap, (keymap_t* )arg,
+                   curproc);
+               if (error != 0) {
+                       splx(s);
+                       return error;
+               }
                bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
                bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap));
                break;
@@ -828,6 +842,12 @@
                        splx(s);
                        return EINVAL;
                }
+               error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum],
+                   &keyp->key, curproc);
+               if (error != 0) {
+                       splx(s);
+                       return error;
+               }
                bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum],
                      sizeof(keyp->key));
                break;
@@ -841,6 +861,12 @@
                break;
        case PIO_DEADKEYMAP:    /* set accent key translation table */
 #ifndef KBD_DISABLE_KEYMAP_LOAD
+               error = accent_change_ok(kbd->kb_accentmap,
+                   (accentmap_t *)arg, curproc);
+               if (error != 0) {
+                       splx(s);
+                       return error;
+               }
                bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap));
                break;
 #else
@@ -865,6 +891,12 @@
                        splx(s);
                        return EINVAL;
                }
+               error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum],
+                   fkeyp, curproc);
+               if (error != 0) {
+                       splx(s);
+                       return error;
+               }
                kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK);
                bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str,
                      kbd->kb_fkeytab[fkeyp->keynum].len);
@@ -880,6 +912,109 @@
        }
 
        splx(s);
+       return 0;
+}
+
+static int keymap_protection;
+SYSCTL_INT(_kern, OID_AUTO, keymap_protection, CTLFLAG_RW, &keymap_protection, 0, "");
+
+#define RESTRICTED_KEY(key, i) \
+       ((key->spcl & (0x80 >> i)) && \
+               (key->map[i] == RBT || key->map[i] == SUSP || \
+                key->map[i] == STBY || key->map[i] == DBG || \
+                key->map[i] == PNC || key->map[i] == HALT || \
+                key->map[i] == PDWN))
+
+static int
+key_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct proc *p)
+{
+       int i;
+
+       /* Low keymap_protection means any changes are OK. */
+       if (keymap_protection <= 0)
+               return 0;
+
+       /* High keymap_protection means only root can change the keymap. */
+       if (keymap_protection >= 2) {
+               for (i = 0; i < NUM_STATES; i++)
+                       if (oldkey->map[i] != newkey->map[i])
+                               return suser(p);
+               if (oldkey->spcl != newkey->spcl)
+                       return suser(p);
+               if (oldkey->flgs != newkey->flgs)
+                       return suser(p);
+               return 0;
+       }
+
+       /* Otherwise we have to see if any special keys are being changed. */
+       for (i = 0; i < NUM_STATES; i++) {
+               /*
+                * If either the oldkey or the newkey action is restricted
+                * then we must make sure that the action doesn't change.
+                */
+               if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i))
+                       continue;
+               if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i))
+                   && oldkey->map[i] == newkey->map[i])
+                       continue;
+               return suser(p);
+       }
+
+       return 0;
+}
+
+static int
+keymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct proc *p)
+{
+       int keycode, error;
+
+       for (keycode = 0; keycode < NUM_KEYS; keycode++) {
+               if ((error = key_change_ok(&oldmap->key[keycode],
+                   &newmap->key[keycode], p)) != 0)
+                       return error;
+       }
+       return 0;
+}
+
+static int
+accent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct proc *p)
+{
+       struct acc_t *oldacc, *newacc;
+       int accent, i;
+
+       if (keymap_protection <= 2)
+               return 0;
+
+       if (oldmap->n_accs != newmap->n_accs)
+               return suser(p);
+
+       for (accent = 0; accent < oldmap->n_accs; accent++) {
+               oldacc = &oldmap->acc[accent];
+               newacc = &newmap->acc[accent];
+               if (oldacc->accchar != newacc->accchar)
+                       return suser(p);
+               for (i = 0; i < NUM_ACCENTCHARS; ++i) {
+                       if (oldacc->map[i][0] != newacc->map[i][0])
+                               return suser(p);
+                       if (oldacc->map[i][0] == 0)     /* end of table */
+                               break;
+                       if (oldacc->map[i][1] != newacc->map[i][1])
+                               return suser(p);
+               }
+       }
+
+       return 0;
+}
+
+static int fkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct proc *p)
+{
+       if (keymap_protection <= 3)
+               return 0;
+
+       if (oldkey->len != newkey->flen ||
+           bcmp(oldkey->str, newkey->keydef, oldkey->len != 0))
+               return suser(p);
+
        return 0;
 }
 

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-stable" in the body of the message

Reply via email to