| /* |
| * 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 <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <grub/auth.h> |
| #include <grub/list.h> |
| #include <grub/mm.h> |
| #include <grub/misc.h> |
| #include <grub/env.h> |
| #include <grub/normal.h> |
| |
| 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; |
| |
| int |
| grub_auth_strcmp (const char *user_input, const char *template) |
| { |
| int ok = 1; |
| const char *ptr1, *ptr2; |
| for (ptr1 = user_input, ptr2 = template; *ptr1; ptr1++) |
| if (*ptr1 == (ptr2 ? *ptr2 : ptr1[1]) && ok && ptr2 != NULL) |
| ptr2++; |
| else |
| ok = 0; |
| |
| return !ok; |
| } |
| |
| static int |
| grub_iswordseparator (int c) |
| { |
| return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&'); |
| } |
| |
| int |
| grub_auth_strword (const char *haystack, const char *needle) |
| { |
| const char *n_pos = needle; |
| int found = 0; |
| |
| while (grub_iswordseparator (*haystack)) |
| haystack++; |
| |
| while (*haystack) |
| { |
| int ok = 1; |
| /* Crawl both the needle and the haystack word we're on. */ |
| while(*haystack && !grub_iswordseparator (*haystack)) |
| { |
| if (*haystack == *n_pos && ok) |
| n_pos++; |
| else |
| ok = 0; |
| |
| haystack++; |
| } |
| |
| if (ok) |
| found = 1; |
| } |
| |
| return found; |
| } |
| |
| 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; |
| |
| auto int hook (grub_list_t item); |
| int hook (grub_list_t item) |
| { |
| const char *name; |
| if (!((struct grub_auth_user *) item)->authenticated) |
| return 0; |
| name = ((struct grub_auth_user *) item)->name; |
| |
| return (userlist && grub_auth_strword (userlist, name)) |
| || grub_auth_strword (superusers, name); |
| } |
| |
| superusers = grub_env_get ("superusers"); |
| |
| if (!superusers) |
| return 1; |
| |
| return grub_list_iterate (GRUB_AS_LIST (users), hook); |
| } |
| |
| grub_err_t |
| grub_auth_check_authentication (const char *userlist) |
| { |
| char login[1024]; |
| struct grub_auth_user *cur = NULL; |
| |
| auto int hook (grub_list_t item); |
| int hook (grub_list_t item) |
| { |
| if (grub_auth_strcmp (login, ((struct grub_auth_user *) item)->name) == 0) |
| cur = (struct grub_auth_user *) item; |
| return 0; |
| } |
| |
| auto int hook_any (grub_list_t item); |
| int hook_any (grub_list_t item) |
| { |
| if (((struct grub_auth_user *) item)->callback) |
| cur = (struct grub_auth_user *) item; |
| return 0; |
| } |
| |
| grub_memset (login, 0, sizeof (login)); |
| |
| if (is_authenticated (userlist)) |
| return GRUB_ERR_NONE; |
| |
| if (!grub_cmdline_get ("Enter username: ", login, sizeof (login) - 1, |
| 0, 0, 0)) |
| return GRUB_ACCESS_DENIED; |
| |
| grub_list_iterate (GRUB_AS_LIST (users), hook); |
| |
| if (!cur || ! cur->callback) |
| { |
| grub_list_iterate (GRUB_AS_LIST (users), hook_any); |
| |
| /* No users present at all. */ |
| if (!cur) |
| return GRUB_ACCESS_DENIED; |
| |
| /* Display any of available authentication schemes. */ |
| cur->callback (login, 0); |
| |
| return GRUB_ACCESS_DENIED; |
| } |
| cur->callback (login, cur->arg); |
| if (is_authenticated (userlist)) |
| return GRUB_ERR_NONE; |
| return GRUB_ACCESS_DENIED; |
| } |