aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--README.menu27
-rw-r--r--com32/libutil/get_key.c10
-rw-r--r--com32/libutil/include/getkey.h5
-rw-r--r--com32/modules/menu.c119
-rw-r--r--com32/modules/readconfig.c5
6 files changed, 141 insertions, 27 deletions
diff --git a/NEWS b/NEWS
index 425c2331..2b029abe 100644
--- 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).
diff --git a/README.menu b/README.menu
index 83b2b578..25bb30f8 100644
--- a/README.menu
+++ b/README.menu
@@ -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
diff --git a/com32/libutil/get_key.c b/com32/libutil/get_key.c
index e3b8f02b..228253e2 100644
--- a/com32/libutil/get_key.c
+++ b/com32/libutil/get_key.c
@@ -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)))
diff --git a/com32/libutil/include/getkey.h b/com32/libutil/include/getkey.h
index 37efc668..d41d8c05 100644
--- a/com32/libutil/include/getkey.h
+++ b/com32/libutil/include/getkey.h
@@ -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);
diff --git a/com32/modules/menu.c b/com32/modules/menu.c
index 83d8b5bd..b7620d72 100644
--- a/com32/modules/menu.c
+++ b/com32/modules/menu.c
@@ -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 ) {
diff --git a/com32/modules/readconfig.c b/com32/modules/readconfig.c
index 82b2c56e..49a81af5 100644
--- a/com32/modules/readconfig.c
+++ b/com32/modules/readconfig.c
@@ -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 */
}