/* * 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 #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 = NULL; 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 = NULL; cur->arg = NULL; } 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; struct grub_auth_user *user; superusers = grub_env_get ("superusers"); if (!superusers) return 1; FOR_LIST_ELEMENTS (user, users) { if (!(user->authenticated)) continue; if ((userlist && grub_strword (userlist, user->name)) || grub_strword (superusers, user->name)) return 1; } return 0; } static int grub_username_get (char buf[], unsigned buf_size) { unsigned cur_len = 0; int key; while (1) { key = grub_getkey (); if (key == '\n' || key == '\r') break; if (key == '\e') { cur_len = 0; break; } if (key == '\b') { cur_len--; grub_printf ("\b"); continue; } if (!grub_isprint (key)) continue; if (cur_len + 2 < buf_size) { buf[cur_len++] = key; grub_printf ("%c", key); } } grub_memset (buf + cur_len, 0, buf_size - cur_len); grub_xputs ("\n"); grub_refresh (); return (key != '\e'); } grub_err_t grub_auth_check_authentication (const char *userlist) { char login[1024]; struct grub_auth_user *cur = NULL; grub_err_t err; static unsigned long punishment_delay = 1; char entered[GRUB_AUTH_MAX_PASSLEN]; struct grub_auth_user *user; grub_memset (login, 0, sizeof (login)); if (is_authenticated (userlist)) { punishment_delay = 1; return GRUB_ERR_NONE; } grub_puts_ (N_("Enter username: ")); if (!grub_username_get (login, sizeof (login) - 1)) goto access_denied; grub_puts_ (N_("Enter password: ")); if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) goto access_denied; FOR_LIST_ELEMENTS (user, users) { if (grub_strcmp (login, user->name) == 0) cur = user; } if (!cur || ! cur->callback) goto access_denied; err = cur->callback (login, entered, cur->arg); if (is_authenticated (userlist)) { punishment_delay = 1; return GRUB_ERR_NONE; } access_denied: grub_sleep (punishment_delay); if (punishment_delay < GRUB_ULONG_MAX / 2) punishment_delay *= 2; return GRUB_ACCESS_DENIED; }