From a53e2a69acf2074bda1b627baf8a0806152ba5b2 Mon Sep 17 00:00:00 2001 From: hpa Date: Fri, 21 Jan 2005 01:35:33 +0000 Subject: Add password support to simple menu system --- NEWS | 2 + README.menu | 27 +++++++++- com32/libutil/get_key.c | 10 ++-- com32/libutil/include/getkey.h | 5 +- com32/modules/menu.c | 119 ++++++++++++++++++++++++++++++++++------- com32/modules/readconfig.c | 5 ++ 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 */ } -- cgit v1.2.1