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
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"),
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)))
}
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,
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(' ');
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));
}
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));
return NULL;
case KEY_BACKSPACE:
case KEY_DEL:
- case '\x7F':
+ case KEY_DELETE:
if ( len ) {
cmdline[--len] = '\0';
redraw = 1;
}
}
+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)
{
/* 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;
}
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 {
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':
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 ) {