/* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. * * VAS_EBOOT 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. * * VAS_EBOOT 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 VAS_EBOOT. If not, see . */ #include #include #include #include #include #include #include #include #ifdef VAS_EBOOT_MACHINE_EFI #include #endif struct VasEBoot_auth_user { struct VasEBoot_auth_user *next; struct VasEBoot_auth_user **prev; char *name; VasEBoot_auth_callback_t callback; void *arg; int authenticated; }; static struct VasEBoot_auth_user *users = NULL; VasEBoot_err_t VasEBoot_auth_register_authentication (const char *user, VasEBoot_auth_callback_t callback, void *arg) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VAS_EBOOT_AS_NAMED_LIST (users), user); if (!cur) cur = VasEBoot_zalloc (sizeof (*cur)); if (!cur) return VasEBoot_errno; cur->callback = callback; cur->arg = arg; if (! cur->name) { cur->name = VasEBoot_strdup (user); if (!cur->name) { VasEBoot_free (cur); return VasEBoot_errno; } VasEBoot_list_push (VAS_EBOOT_AS_LIST_P (&users), VAS_EBOOT_AS_LIST (cur)); } return VAS_EBOOT_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_unregister_authentication (const char *user) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VAS_EBOOT_AS_NAMED_LIST (users), user); if (!cur) return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, "user '%s' not found", user); if (!cur->authenticated) { VasEBoot_free (cur->name); VasEBoot_list_remove (VAS_EBOOT_AS_LIST (cur)); VasEBoot_free (cur); } else { cur->callback = NULL; cur->arg = NULL; } return VAS_EBOOT_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_authenticate (const char *user) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VAS_EBOOT_AS_NAMED_LIST (users), user); if (!cur) cur = VasEBoot_zalloc (sizeof (*cur)); if (!cur) return VasEBoot_errno; cur->authenticated = 1; if (! cur->name) { cur->name = VasEBoot_strdup (user); if (!cur->name) { VasEBoot_free (cur); return VasEBoot_errno; } VasEBoot_list_push (VAS_EBOOT_AS_LIST_P (&users), VAS_EBOOT_AS_LIST (cur)); } return VAS_EBOOT_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_deauthenticate (const char *user) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VAS_EBOOT_AS_NAMED_LIST (users), user); if (!cur) return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, "user '%s' not found", user); if (!cur->callback) { VasEBoot_free (cur->name); VasEBoot_list_remove (VAS_EBOOT_AS_LIST (cur)); VasEBoot_free (cur); } else cur->authenticated = 0; return VAS_EBOOT_ERR_NONE; } static int is_authenticated (const char *userlist) { const char *superusers; struct VasEBoot_auth_user *user; superusers = VasEBoot_env_get ("superusers"); if (!superusers) return 1; FOR_LIST_ELEMENTS (user, users) { if (!(user->authenticated)) continue; if ((userlist && VasEBoot_strword (userlist, user->name)) || VasEBoot_strword (superusers, user->name)) return 1; } return 0; } static int VasEBoot_username_get (char buf[], unsigned buf_size) { unsigned cur_len = 0; int key; while (1) { key = VasEBoot_getkey (); if (key == '\n' || key == '\r') break; if (key == VAS_EBOOT_TERM_ESC) { cur_len = 0; break; } if (key == VAS_EBOOT_TERM_BACKSPACE) { if (cur_len) { cur_len--; VasEBoot_printf ("\b \b"); } continue; } if (!VasEBoot_isprint (key)) continue; if (cur_len + 2 < buf_size) { buf[cur_len++] = key; VasEBoot_printf ("%c", key); } } VasEBoot_memset (buf + cur_len, 0, buf_size - cur_len); VasEBoot_xputs ("\n"); VasEBoot_refresh (); return (key != VAS_EBOOT_TERM_ESC); } VasEBoot_err_t VasEBoot_auth_check_cli_access (void) { if (VasEBoot_is_cli_need_auth () == true) { #ifdef VAS_EBOOT_MACHINE_EFI static bool authenticated = false; if (authenticated == false) { VasEBoot_err_t ret; ret = VasEBoot_cryptodisk_challenge_password (); if (ret == VAS_EBOOT_ERR_NONE) authenticated = true; return ret; } return VAS_EBOOT_ERR_NONE; #else return VAS_EBOOT_ACCESS_DENIED; #endif } return VAS_EBOOT_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_check_authentication (const char *userlist) { char login[1024]; struct VasEBoot_auth_user *cur = NULL; static unsigned long punishment_delay = 1; char entered[VAS_EBOOT_AUTH_MAX_PASSLEN]; struct VasEBoot_auth_user *user; if (VasEBoot_is_cli_disabled ()) return VAS_EBOOT_ACCESS_DENIED; VasEBoot_memset (login, 0, sizeof (login)); if (is_authenticated (userlist)) { punishment_delay = 1; return VAS_EBOOT_ERR_NONE; } VasEBoot_puts_ (N_("Enter username: ")); if (!VasEBoot_username_get (login, sizeof (login) - 1)) goto access_denied; VasEBoot_puts_ (N_("Enter password: ")); if (!VasEBoot_password_get (entered, VAS_EBOOT_AUTH_MAX_PASSLEN)) goto access_denied; FOR_LIST_ELEMENTS (user, users) { if (VasEBoot_strcmp (login, user->name) == 0) cur = user; } if (!cur || ! cur->callback) goto access_denied; cur->callback (login, entered, cur->arg); if (is_authenticated (userlist)) { punishment_delay = 1; return VAS_EBOOT_ERR_NONE; } access_denied: VasEBoot_sleep (punishment_delay); if (punishment_delay < VAS_EBOOT_ULONG_MAX / 2) punishment_delay *= 2; return VAS_EBOOT_ACCESS_DENIED; } static VasEBoot_err_t VasEBoot_cmd_authenticate (struct VasEBoot_command *cmd __attribute__ ((unused)), int argc, char **args) { return VasEBoot_auth_check_authentication ((argc >= 1) ? args[0] : ""); } static VasEBoot_command_t cmd; void VasEBoot_normal_auth_init (void) { cmd = VasEBoot_register_command ("authenticate", VasEBoot_cmd_authenticate, N_("[USERLIST]"), N_("Check whether user is in USERLIST.")); } void VasEBoot_normal_auth_fini (void) { VasEBoot_unregister_command (cmd); }