diff --git a/conf/common.rmk b/conf/common.rmk index 032517f..f5843a7 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -503,7 +503,7 @@ probe_mod_LDFLAGS = $(COMMON_LDFLAGS) # For normal.mod. normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ - normal/autofs.c normal/handler.c \ + normal/auth.c normal/autofs.c normal/handler.c \ normal/color.c normal/completion.c normal/datetime.c normal/menu.c \ normal/menu_entry.c normal/menu_text.c normal/menu_viewer.c \ normal/misc.c diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 7ba5737..6be465b 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -127,7 +127,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/misc.c \ - normal/handler.c normal/autofs.c \ + normal/handler.c normal/auth.c normal/autofs.c \ normal/completion.c normal/datetime.c normal/main.c \ normal/menu_text.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 9177b9d..47b4508 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -54,7 +54,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/command.c normal/datetime.c \ - normal/autofs.c \ + normal/auth.c normal/autofs.c \ normal/completion.c normal/context.c normal/main.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ normal/menu_text.c \ diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 0321979..9543a65 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -82,7 +82,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \ - normal/handler.c normal/autofs.c \ + normal/handler.c normal/auth.c normal/autofs.c \ normal/completion.c normal/main.c normal/menu_text.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ normal/color.c \ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 798aee2..6b827e3 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -136,7 +136,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \ - normal/handler.c normal/autofs.c \ + normal/handler.c normal/auth.c normal/autofs.c \ normal/completion.c normal/main.c normal/color.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ normal/menu_text.c \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index af29d23..08c73b0 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -62,7 +62,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/command.c kern/corecmd.c commands/extcmd.c \ lib/arg.c normal/cmdline.c normal/datetime.c \ normal/completion.c normal/misc.c \ - normal/handler.c normal/autofs.c normal/main.c \ + normal/handler.c normal/auth.c normal/autofs.c normal/main.c \ normal/menu.c \ normal/menu_text.c \ normal/menu_entry.c normal/menu_viewer.c \ diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index aabccee..d61e97c 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -119,7 +119,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/command.c kern/corecmd.c commands/extcmd.c \ lib/arg.c normal/cmdline.c normal/datetime.c \ normal/completion.c normal/misc.c \ - normal/handler.c normal/autofs.c normal/main.c \ + normal/handler.c normal/auth.c normal/autofs.c normal/main.c \ normal/menu.c \ normal/menu_text.c \ normal/menu_entry.c normal/menu_viewer.c \ diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 21da0e1..57254c0 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -50,7 +50,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/command.c kern/corecmd.c commands/extcmd.c kern/file.c \ kern/fs.c commands/boot.c kern/main.c kern/misc.c kern/parser.c \ kern/partition.c kern/readerescue.c kern/term.c \ - lib/arg.c normal/cmdline.c normal/misc.c normal/autofs.c \ + lib/arg.c normal/cmdline.c normal/misc.c normal/auth.c normal/autofs.c \ normal/completion.c normal/datetime.c normal/context.c \ normal/main.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ diff --git a/include/grub/auth.h b/include/grub/auth.h new file mode 100644 index 0000000..6a5d0b6 --- /dev/null +++ b/include/grub/auth.h @@ -0,0 +1,34 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +#ifndef GRUB_AURH_HEADER +#define GRUB_AUTH_HEADER 1 + +#include + +typedef grub_err_t (*grub_auth_callback_t) (const char*, void *); + +grub_err_t grub_auth_register_authentication (const char *user, + grub_auth_callback_t callback, + void *arg); +grub_err_t grub_auth_unregister_authentication (const char *user); + +grub_err_t grub_auth_authenticate (const char *user); +grub_err_t grub_auth_deauthenticate (const char *user); +grub_err_t grub_auth_check_authentication (const char *userlist); + +#endif /* ! GRUB_AUTH_HEADER */ diff --git a/include/grub/err.h b/include/grub/err.h index 3435fb7..7a5ce1a 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -53,7 +53,8 @@ typedef enum GRUB_ERR_BAD_GZIP_DATA, GRUB_ERR_MENU, GRUB_ERR_TIMEOUT, - GRUB_ERR_IO + GRUB_ERR_IO, + GRUB_ERR_ACCESS_DENIED } grub_err_t; diff --git a/include/grub/menu.h b/include/grub/menu.h index 3bd25e8..70aa7fd 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -32,6 +32,9 @@ struct grub_menu_entry /* The title name. */ const char *title; + /* Allowed users. NULL means 'everybody'. */ + const char *users; + /* The classes associated with the menu entry: used to choose an icon or other style attributes. This is a dummy head node for the linked list, so for an entry E, diff --git a/include/grub/normal.h b/include/grub/normal.h index 7d8122a..feebc85 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -56,7 +56,7 @@ void grub_cmdline_run (int nested); /* Defined in `cmdline.c'. */ int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, - int echo_char, int readline); + int echo_char, int readline, int history); grub_err_t grub_set_history (int newsize); /* Defined in `completion.c'. */ diff --git a/normal/auth.c b/normal/auth.c new file mode 100644 index 0000000..8633006 --- /dev/null +++ b/normal/auth.c @@ -0,0 +1,184 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_auth_user +{ + struct grub_auth_user *next; + char *name; + grub_auth_callback_t callback; + void *arg; + int authenticated; +}; + +struct grub_auth_user *users = 0; + +grub_err_t +grub_auth_register_authentication (const char *user, + grub_auth_callback_t callback, + void *arg) +{ + struct grub_auth_user *cur; + + cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user); + if (!cur) + cur = grub_zalloc (sizeof (*cur)); + if (!cur) + return grub_errno; + cur->callback = callback; + cur->arg = arg; + if (! cur->name) + { + cur->name = grub_strdup (user); + if (!cur->name) + { + grub_free (cur); + return grub_errno; + } + grub_list_push (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur)); + } + return GRUB_ERR_NONE; +} + +grub_err_t +grub_auth_unregister_authentication (const char *user) +{ + struct grub_auth_user *cur; + cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user); + if (!cur) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "user '%s' not found", user); + if (!cur->authenticated) + { + grub_free (cur->name); + grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur)); + grub_free (cur); + } + else + { + cur->callback = 0; + cur->arg = 0; + } + return GRUB_ERR_NONE; +} + +grub_err_t +grub_auth_authenticate (const char *user) +{ + struct grub_auth_user *cur; + + cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user); + if (!cur) + cur = grub_zalloc (sizeof (*cur)); + if (!cur) + return grub_errno; + + cur->authenticated = 1; + + if (! cur->name) + { + cur->name = grub_strdup (user); + if (!cur->name) + { + grub_free (cur); + return grub_errno; + } + grub_list_push (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur)); + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_auth_deauthenticate (const char *user) +{ + struct grub_auth_user *cur; + cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user); + if (!cur) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "user '%s' not found", user); + if (!cur->callback) + { + grub_free (cur->name); + grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur)); + grub_free (cur); + } + else + cur->authenticated = 0; + return GRUB_ERR_NONE; +} + +static int +is_authenticated (const char *userlist) +{ + const char *superusers; + + auto int hook (grub_list_t item); + int hook (grub_list_t item) + { + return (userlist && grub_strword (userlist, + ((struct grub_auth_user *) item)->name)) + || grub_strword (superusers, ((struct grub_auth_user *) item)->name); + } + + superusers = grub_env_get ("superusers"); + + if (!superusers) + return GRUB_ERR_NONE; + + return grub_list_iterate (GRUB_AS_LIST (users), hook); +} + +grub_err_t +grub_auth_check_authentication (const char *userlist) +{ + char login[1024] = {0}; + struct grub_auth_user *cur = 0; + grub_err_t err; + + auto int hook (grub_list_t item); + int hook (grub_list_t item) + { + if (grub_strcmp (login, ((struct grub_auth_user *) item)->name) == 0) + { + cur = (struct grub_auth_user *) item; + return 1; + } + return 0; + } + + if (is_authenticated (userlist)) + return GRUB_ERR_NONE; + + if (!grub_cmdline_get ("Enter username: ", login, sizeof (login) - 1, 0, 0, 0)) + return grub_error (GRUB_ERR_ACCESS_DENIED, "login aborted"); + + if (!grub_list_iterate (GRUB_AS_LIST (users), hook) || ! cur->callback) + { + /* XXX Show a fake password prompt*/ + return grub_error (GRUB_ERR_ACCESS_DENIED, "password incorrect"); + } + err = cur->callback (login, cur->arg); + if (is_authenticated (userlist)) + return GRUB_ERR_NONE; + return grub_error (GRUB_ERR_ACCESS_DENIED, "access denied"); +} diff --git a/normal/cmdline.c b/normal/cmdline.c index 9a07d7d..56f8921 100644 --- a/normal/cmdline.c +++ b/normal/cmdline.c @@ -181,7 +181,7 @@ print_completion (const char *item, grub_completion_type_t type, int count) /* FIXME: The dumb interface is not supported yet. */ int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, - int echo_char, int readline) + int echo_char, int readline, int history) { unsigned xpos, ypos, ystart; grub_size_t lpos, llen; @@ -280,7 +280,7 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, cl_insert (cmdline); - if (hist_used == 0) + if (history && hist_used == 0) grub_history_add (buf); while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r') @@ -468,11 +468,14 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, while (buf[lpos] == ' ') lpos++; - histpos = 0; - if (grub_strlen (buf) > 0) + if (history) { - grub_history_replace (histpos, buf); - grub_history_add (""); + histpos = 0; + if (grub_strlen (buf) > 0) + { + grub_history_replace (histpos, buf); + grub_history_add (""); + } } grub_memcpy (cmdline, buf + lpos, llen - lpos + 1); diff --git a/normal/main.c b/normal/main.c index 66d8418..b2029ce 100644 --- a/normal/main.c +++ b/normal/main.c @@ -28,6 +28,7 @@ #include #include #include +#include #define GRUB_DEFAULT_HISTORY_SIZE 50 @@ -164,6 +165,7 @@ grub_normal_add_menu_entry (int argc, const char **args, int i; struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */ struct grub_menu_entry_class *classes_tail; + char *users = 0; /* Allocate dummy head node for class list. */ classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class)); @@ -218,6 +220,18 @@ grub_normal_add_menu_entry (int argc, const char **args, classes_tail = new_class; continue; } + else if (grub_strcmp(arg, "users") == 0) + { + i++; + users = grub_strdup (args[i]); + if (! users) + { + failed = 1; + break; + } + + continue; + } else { /* Handle invalid argument. */ @@ -275,6 +289,7 @@ grub_normal_add_menu_entry (int argc, const char **args, (*last)->title = menutitle; (*last)->classes = classes_head; + (*last)->users = users; (*last)->sourcecode = menusourcecode; menu->size++; @@ -465,7 +480,19 @@ quit: void grub_cmdline_run (int nested) { - grub_reader_t reader = grub_reader_get_current (); + grub_reader_t reader; + grub_err_t err = GRUB_ERR_NONE; + + err = grub_auth_check_authentication (0); + + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + + reader = grub_reader_get_current (); reader_nested = nested; if (reader->init) @@ -501,7 +528,7 @@ grub_normal_read_line (char **line, int cont) while (1) { cmdline[0] = 0; - if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1)) + if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1, 1)) break; if ((reader_nested) || (cont)) diff --git a/normal/menu.c b/normal/menu.c index 59ad83f..b9b7763 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Get a menu entry by its index in the entry list. */ grub_menu_entry_t @@ -124,6 +125,18 @@ get_and_remove_first_entry_number (const char *name) void grub_menu_execute_entry(grub_menu_entry_t entry) { + grub_err_t err = GRUB_ERR_NONE; + + if (entry->users) + err = grub_auth_check_authentication (entry->users); + + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + grub_parser_execute ((char *) entry->sourcecode); if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) diff --git a/normal/menu_entry.c b/normal/menu_entry.c index f7662ff..9505df0 100644 --- a/normal/menu_entry.c +++ b/normal/menu_entry.c @@ -23,6 +23,7 @@ #include #include #include +#include enum update_mode { @@ -1026,6 +1027,16 @@ grub_menu_entry_run (grub_menu_entry_t entry) { struct screen *screen; int prev_c; + grub_err_t err = GRUB_ERR_NONE; + + err = grub_auth_check_authentication (0); + + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } screen = make_screen (entry); if (! screen) diff --git a/normal/menu_viewer.c b/normal/menu_viewer.c index 37d317b..ef715c9 100644 --- a/normal/menu_viewer.c +++ b/normal/menu_viewer.c @@ -21,6 +21,7 @@ #include #include #include +#include /* The list of menu viewers. */ static grub_menu_viewer_t menu_viewer_list; @@ -55,9 +56,24 @@ grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested) { grub_menu_viewer_t cur = get_current_menu_viewer (); + grub_err_t err1, err2; if (!cur) return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available."); - return cur->show_menu (menu, nested); + while (1) + { + err1 = cur->show_menu (menu, nested); + grub_print_error (); + + err2 = grub_auth_check_authentication (0); + if (err2) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + continue; + } + } + + return err1; }