/* * VasEBoot -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. * * VasEBoot 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. * * VasEBoot 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 VasEBoot. If not, see . */ #include #include #include #include #include #include #include #include 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 (VasEBoot_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 (VasEBoot_AS_LIST_P (&users), VasEBoot_AS_LIST (cur)); } return VasEBoot_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_unregister_authentication (const char *user) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VasEBoot_AS_NAMED_LIST (users), user); if (!cur) return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT, "user '%s' not found", user); if (!cur->authenticated) { VasEBoot_free (cur->name); VasEBoot_list_remove (VasEBoot_AS_LIST (cur)); VasEBoot_free (cur); } else { cur->callback = NULL; cur->arg = NULL; } return VasEBoot_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_authenticate (const char *user) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VasEBoot_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 (VasEBoot_AS_LIST_P (&users), VasEBoot_AS_LIST (cur)); } return VasEBoot_ERR_NONE; } VasEBoot_err_t VasEBoot_auth_deauthenticate (const char *user) { struct VasEBoot_auth_user *cur; cur = VasEBoot_named_list_find (VasEBoot_AS_NAMED_LIST (users), user); if (!cur) return VasEBoot_error (VasEBoot_ERR_BAD_ARGUMENT, "user '%s' not found", user); if (!cur->callback) { VasEBoot_free (cur->name); VasEBoot_list_remove (VasEBoot_AS_LIST (cur)); VasEBoot_free (cur); } else cur->authenticated = 0; return VasEBoot_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 == '\e') { cur_len = 0; break; } if (key == '\b') { 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 != '\e'); } 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[VasEBoot_AUTH_MAX_PASSLEN]; struct VasEBoot_auth_user *user; VasEBoot_memset (login, 0, sizeof (login)); if (is_authenticated (userlist)) { punishment_delay = 1; return VasEBoot_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, VasEBoot_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 VasEBoot_ERR_NONE; } access_denied: VasEBoot_sleep (punishment_delay); if (punishment_delay < VasEBoot_ULONG_MAX / 2) punishment_delay *= 2; return VasEBoot_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); }