Add password support to simple menu system
authorhpa <hpa>
Fri, 21 Jan 2005 01:35:33 +0000 (01:35 +0000)
committerhpa <hpa>
Fri, 21 Jan 2005 01:35:33 +0000 (01:35 +0000)
NEWS
README.menu
com32/libutil/get_key.c
com32/libutil/include/getkey.h
com32/modules/menu.c
com32/modules/readconfig.c

diff --git a/NEWS b/NEWS
index 425c233..2b029ab 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ Changes in 3.08:
        * Add API function for idle loop.
        * libutil: Add do_idle() function for idle loop, make
          get_key() use it.
+       * libutil: Add SHA-1 and base64 functions.
+       * Simple menu system: add password support.
 
 Changes in 3.07:
        * Fix chainloading (chain.c32).
index 83b2b57..25bb30f 100644 (file)
@@ -78,13 +78,38 @@ MENU DEFAULT
        default is specified, use the first one.
 
 
+MENU PASSWD passwd
+
+       (Only valid after a LABEL statement.)
+       Sets a password on this menu entry.  "passwd" can be either a
+       cleartext password or a SHA-1 encrypted password; use the
+       included Perl script "sha1pass" to encrypt passwords.
+       (Obviously, if you don't encrypt your passwords they will not
+       be very secure at all.)
+
+       If you are using passwords, you want to make sure you also use
+       the settings "NOESCAPE 1", "PROMPT 0", and either set
+       "ALLOWOPTIONS 0" or use a master password (see below.)
+
+       If passwd is an empty string, this menu entry can only be
+       unlocked with the master password.
+
+
+MENU MASTER PASSWD passwd
+
+       Sets a master password.  This password can be used to boot any
+       menu entry, and is required for the [Tab] and [Esc] keys to
+       work.
+
+
 The menu system honours the TIMEOUT command; if TIMEOUT is specified
 it will execute the ONTIMEOUT command if one exists, otherwise it will
 pick the default menu option.
 
 Normally, the user can press [Tab] to edit the menu entry, and [Esc]
 to return to the SYSLINUX command line.  However, if the configuration
-file specifies ALLOWOPTIONS 0, these keys will be disabled.
+file specifies ALLOWOPTIONS 0, these keys will be disabled, and if
+MENU MASTER PASSWD is set, they require the master password.
 
 The simple menu system supports serial console, using the normal
 SERIAL directive.  However, it can be quite slow over a slow serial
index e3b8f02..228253e 100644 (file)
@@ -75,8 +75,8 @@ static const struct keycode keycodes[] = {
   CODE(KEY_PGDN, "\0\x51"),
   CODE(KEY_HOME, "\0\x47"),
   CODE(KEY_END,  "\0\x4F"),
-  CODE(KEY_INS "\0\x52"),
-  CODE(KEY_DEL "\0\x53"),
+  CODE(KEY_INSERT, "\0\x52"),
+  CODE(KEY_DELETE, "\0\x53"),
 
   /* Now, VT/xterm/Linux codes */
   CODE(KEY_F1,   "\033[[A"),
@@ -110,9 +110,9 @@ static const struct keycode keycodes[] = {
   CODE(KEY_END,  "\033[4~"),
   CODE(KEY_END,  "\033[F"),
   CODE(KEY_END,  "\033OF"),
-  CODE(KEY_INS "\033[2~"),
-  CODE(KEY_INS "\033[@"),
-  CODE(KEY_DEL "\033[3~"),
+  CODE(KEY_INSERT, "\033[2~"),
+  CODE(KEY_INSERT, "\033[@"),
+  CODE(KEY_DELETE, "\033[3~"),
 };
 #define NCODES ((int)(sizeof keycodes/sizeof(struct keycode)))
 
index 37efc66..d41d8c0 100644 (file)
@@ -45,6 +45,7 @@
 #define KEY_TAB                0x0009
 #define KEY_ENTER      0x000d
 #define KEY_ESC                0x001b
+#define KEY_DEL                0x007f
 
 #define KEY_F1         0x0100
 #define KEY_F2         0x0101
@@ -67,8 +68,8 @@
 #define KEY_PGDN       0x0125
 #define KEY_HOME       0x0126
 #define KEY_END                0x0127
-#define KEY_INS                0x0128
-#define KEY_DEL                0x0129
+#define KEY_INSERT     0x0128
+#define KEY_DELETE     0x0129
 
 int get_key(FILE *, clock_t);
 
index 83d8b5b..b7620d7 100644 (file)
@@ -198,10 +198,12 @@ passwd_compare(const char *passwd, const char *entry)
 }
 
 static int
-ask_passwd(const struct menu_entry *entry)
+ask_passwd(const char *menu_entry)
 {
   static const char title[] = "Password required";
-  static char user_passwd[] = "passw0rd";
+  char user_passwd[WIDTH], *p;
+  int done;
+  int key;
   int x;
 
   printf("\033[%d;%dH%s\016l", PASSWD_ROW, PASSWD_MARGIN+1,
@@ -209,7 +211,7 @@ ask_passwd(const struct menu_entry *entry)
   for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ )
     putchar('q');
   
-  printf("k\033[%d;%dx", PASSWD_ROW+1, PASSWD_MARGIN+1);
+  printf("k\033[%d;%dHx", PASSWD_ROW+1, PASSWD_MARGIN+1);
   for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ )
     putchar(' ');
 
@@ -218,17 +220,62 @@ ask_passwd(const struct menu_entry *entry)
     putchar('q');
   
   printf("j\017\033[%d;%dH%s %s \033[%d;%dH%s",
-        PASSWD_ROW, WIDTH-(sizeof(title)+1)/2,
+        PASSWD_ROW, (WIDTH-((int)sizeof(title)+1))/2,
         menu_attrib->pwdheader, title,
         PASSWD_ROW+1, PASSWD_MARGIN+3, menu_attrib->pwdentry);
 
   /* Actually allow user to type a password, then compare to the SHA1 */
-  if ( (menu_master_passwd && passwd_compare(menu_master_passwd, user_passwd))
-       || (entry && entry->passwd &&
-          passwd_compare(entry->passwd, user_passwd)) )
-    return 1;
-  else
-    return 0;
+  done = 0;
+  p = user_passwd;
+
+  while ( !done ) {
+    key = get_key(stdin, 0);
+
+    switch ( key ) {
+    case KEY_ENTER:
+    case KEY_CTRL('J'):
+      done = 1;
+      break;
+
+    case KEY_ESC:
+    case KEY_CTRL('C'):
+      p = user_passwd;         /* No password entered */
+      done = 1;
+      break;
+
+    case KEY_BACKSPACE:
+    case KEY_DEL:
+    case KEY_DELETE:
+      if ( p > user_passwd ) {
+       printf("\b \b");
+       p--;
+      }
+      break;
+
+    case KEY_CTRL('U'):
+      while ( p > user_passwd ) {
+       printf("\b \b");
+       p--;
+      }
+      break;
+
+    default:
+      if ( key >= ' ' && key <= 0xFF &&
+          (p-user_passwd) < WIDTH-2*PASSWD_MARGIN-5 ) {
+       *p++ = key;
+       putchar('*');
+      }
+      break;
+    }
+  }
+
+  if ( p == user_passwd )
+    return 0;                  /* No password entered */
+
+  *p = '\0';
+      
+  return (menu_master_passwd && passwd_compare(menu_master_passwd, user_passwd))
+    || (menu_entry && passwd_compare(menu_entry, user_passwd));
 }
 
 
@@ -270,7 +317,7 @@ draw_menu(int sel, int top)
     putchar('q');
   fputs("j\017", stdout);
 
-  if ( allowedit )
+  if ( allowedit && !menu_master_passwd )
     printf("%s\033[%d;1H%s", menu_attrib->tabmsg, TABMSG_ROW,
           pad_line("Press [Tab] to edit options", 1, WIDTH));
 
@@ -324,7 +371,7 @@ edit_cmdline(char *input, int top)
       return NULL;
     case KEY_BACKSPACE:
     case KEY_DEL:
-    case '\x7F':
+    case KEY_DELETE:
       if ( len ) {
        cmdline[--len] = '\0';
        redraw = 1;
@@ -359,6 +406,12 @@ edit_cmdline(char *input, int top)
   }
 }
 
+static void
+clear_screen(void)
+{
+  printf("\033e\033%%@\033)0\033(B%s\033[?25l\033[2J", menu_attrib->screen);
+}
+
 static const char *
 run_menu(void)
 {
@@ -390,7 +443,7 @@ run_menu(void)
       /* Clear and redraw whole screen */
       /* Enable ASCII on G0 and DEC VT on G1; do it in this order
         to avoid confusing the Linux console */
-      printf("\033e\033%%@\033)0\033(B%s\033[?25l\033[2J", menu_attrib->screen);
+      clear_screen();
       clear = 0;
       prev_entry = prev_top = -1;
     }
@@ -409,7 +462,10 @@ run_menu(void)
     case KEY_NONE:             /* Timeout */
       /* This is somewhat hacky, but this at least lets the user
         know what's going on, and still deals with "phantom inputs"
-        e.g. on serial ports. */
+        e.g. on serial ports.
+
+        Warning: a timeout will boot the default entry without any
+        password! */
       if ( entry != defentry )
        entry = defentry;
       else {
@@ -422,8 +478,13 @@ run_menu(void)
       break;
     case KEY_ENTER:
     case KEY_CTRL('J'):
+      if ( menu_entries[entry].passwd ) {
+       clear = 1;
+       done = ask_passwd(menu_entries[entry].passwd);
+      } else {
+       done = 1;
+      }
       cmdline = menu_entries[entry].label;
-      done = 1;
       break;
     case 'P':
     case 'p':
@@ -475,16 +536,36 @@ run_menu(void)
       break;
     case KEY_TAB:
       if ( allowedit ) {
+       int ok = 1;
+
        draw_row(entry-top+4, -1, top, 0, 0);
-       cmdline = edit_cmdline(menu_entries[entry].cmdline, top);
-       done = !!cmdline;
-       clear = 1;              /* In case we hit [Esc] and done is null */
+
+       if ( menu_master_passwd ) {
+         ok = ask_passwd(NULL);
+         clear_screen();
+         draw_menu(-1, top);
+       }
+       
+       if ( ok ) {
+         cmdline = edit_cmdline(menu_entries[entry].cmdline, top);
+         done = !!cmdline;
+         clear = 1;            /* In case we hit [Esc] and done is null */
+       } else {
+         draw_row(entry-top+4, entry, top, 0, 0);
+       }
       }
       break;
     case KEY_CTRL('C'):                /* Ctrl-C */
     case KEY_ESC:              /* Esc */
-      if ( allowedit )
+      if ( allowedit ) {
        done = 1;
+       clear = 1;
+       
+       draw_row(entry-top+4, -1, top, 0, 0);
+
+       if ( menu_master_passwd )
+         done = ask_passwd(NULL);
+      }
       break;
     default:
       if ( key > 0 && key < 0xFF ) {
index 82b2c56..49a81af 100644 (file)
@@ -216,6 +216,11 @@ void parse_config(const char *filename)
        ld.menuhide = 1;
       } else if ( looking_at(p, "passwd") ) {
        ld.passwd = strdup(skipspace(p+6));
+      } else if ( looking_at(p, "master") ) {
+       p = skipspace(p+6);
+       if ( looking_at (p, "passwd") ) {
+         menu_master_passwd = strdup(skipspace(p+6));
+       }
       } else {
        /* Unknown, ignore for now */
       }