]> git.proxmox.com Git - grub2.git/blame - normal/auth.c
2009-12-20 Carles Pina i Estany <carles@pina.cat>
[grub2.git] / normal / auth.c
CommitLineData
e7e1f93f 1/*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <grub/auth.h>
20#include <grub/list.h>
21#include <grub/mm.h>
22#include <grub/misc.h>
23#include <grub/env.h>
24#include <grub/normal.h>
7aea29a3 25#include <grub/time.h>
7f39d92f 26#include <grub/i18n.h>
e7e1f93f 27
28struct grub_auth_user
29{
30 struct grub_auth_user *next;
31 char *name;
32 grub_auth_callback_t callback;
33 void *arg;
34 int authenticated;
35};
36
37struct grub_auth_user *users = NULL;
38
39int
3fd6f044 40grub_auth_strcmp (const char *s1, const char *s2)
e7e1f93f 41{
3fd6f044
RM
42 int ret;
43 grub_uint64_t end;
ec8bb77d 44
3fd6f044 45 end = grub_get_time_ms () + 100;
7aea29a3 46 ret = grub_strcmp (s1, s2);
ec8bb77d 47
3fd6f044
RM
48 /* This prevents an attacker from deriving information about the
49 password from the time it took to execute this function. */
50 while (grub_get_time_ms () < end);
e7e1f93f 51
3fd6f044 52 return ret;
e7e1f93f 53}
54
ff747d50 55static int
56grub_iswordseparator (int c)
57{
58 return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
59}
60
e7e1f93f 61int
62grub_auth_strword (const char *haystack, const char *needle)
63{
64 const char *n_pos = needle;
65 int found = 0;
66
67 while (grub_iswordseparator (*haystack))
68 haystack++;
69
70 while (*haystack)
71 {
72 int ok = 1;
73 /* Crawl both the needle and the haystack word we're on. */
74 while(*haystack && !grub_iswordseparator (*haystack))
75 {
76 if (*haystack == *n_pos && ok)
77 n_pos++;
78 else
79 ok = 0;
80
81 haystack++;
82 }
83
84 if (ok)
85 found = 1;
86 }
87
88 return found;
89}
90
91grub_err_t
92grub_auth_register_authentication (const char *user,
93 grub_auth_callback_t callback,
94 void *arg)
95{
96 struct grub_auth_user *cur;
97
98 cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
99 if (!cur)
100 cur = grub_zalloc (sizeof (*cur));
101 if (!cur)
102 return grub_errno;
103 cur->callback = callback;
104 cur->arg = arg;
105 if (! cur->name)
106 {
107 cur->name = grub_strdup (user);
108 if (!cur->name)
109 {
110 grub_free (cur);
111 return grub_errno;
112 }
113 grub_list_push (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
114 }
115 return GRUB_ERR_NONE;
116}
117
118grub_err_t
119grub_auth_unregister_authentication (const char *user)
120{
121 struct grub_auth_user *cur;
122 cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
123 if (!cur)
124 return grub_error (GRUB_ERR_BAD_ARGUMENT, "user '%s' not found", user);
125 if (!cur->authenticated)
126 {
127 grub_free (cur->name);
128 grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
129 grub_free (cur);
130 }
131 else
132 {
133 cur->callback = NULL;
134 cur->arg = NULL;
135 }
136 return GRUB_ERR_NONE;
137}
138
139grub_err_t
140grub_auth_authenticate (const char *user)
141{
142 struct grub_auth_user *cur;
143
144 cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
145 if (!cur)
146 cur = grub_zalloc (sizeof (*cur));
147 if (!cur)
148 return grub_errno;
149
150 cur->authenticated = 1;
151
152 if (! cur->name)
153 {
154 cur->name = grub_strdup (user);
155 if (!cur->name)
156 {
157 grub_free (cur);
158 return grub_errno;
159 }
160 grub_list_push (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
161 }
162
163 return GRUB_ERR_NONE;
164}
165
166grub_err_t
167grub_auth_deauthenticate (const char *user)
168{
169 struct grub_auth_user *cur;
170 cur = grub_named_list_find (GRUB_AS_NAMED_LIST (users), user);
171 if (!cur)
172 return grub_error (GRUB_ERR_BAD_ARGUMENT, "user '%s' not found", user);
173 if (!cur->callback)
174 {
175 grub_free (cur->name);
176 grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur));
177 grub_free (cur);
178 }
179 else
180 cur->authenticated = 0;
181 return GRUB_ERR_NONE;
182}
183
184static int
185is_authenticated (const char *userlist)
186{
187 const char *superusers;
188
189 auto int hook (grub_list_t item);
190 int hook (grub_list_t item)
191 {
192 const char *name;
193 if (!((struct grub_auth_user *) item)->authenticated)
194 return 0;
195 name = ((struct grub_auth_user *) item)->name;
196
197 return (userlist && grub_auth_strword (userlist, name))
198 || grub_auth_strword (superusers, name);
199 }
200
201 superusers = grub_env_get ("superusers");
202
203 if (!superusers)
204 return 1;
205
206 return grub_list_iterate (GRUB_AS_LIST (users), hook);
207}
208
209grub_err_t
210grub_auth_check_authentication (const char *userlist)
211{
212 char login[1024];
213 struct grub_auth_user *cur = NULL;
214 grub_err_t err;
4089b167 215 static unsigned long punishment_delay = 1;
e7e1f93f 216
217 auto int hook (grub_list_t item);
218 int hook (grub_list_t item)
219 {
220 if (grub_auth_strcmp (login, ((struct grub_auth_user *) item)->name) == 0)
221 cur = (struct grub_auth_user *) item;
222 return 0;
223 }
224
225 auto int hook_any (grub_list_t item);
226 int hook_any (grub_list_t item)
227 {
228 if (((struct grub_auth_user *) item)->callback)
229 cur = (struct grub_auth_user *) item;
230 return 0;
231 }
232
233 grub_memset (login, 0, sizeof (login));
234
235 if (is_authenticated (userlist))
3fd6f044
RM
236 {
237 punishment_delay = 1;
238 return GRUB_ERR_NONE;
239 }
e7e1f93f 240
7f39d92f 241 if (!grub_cmdline_get (N_("Enter username:"), login, sizeof (login) - 1,
e7e1f93f 242 0, 0, 0))
3fd6f044 243 goto access_denied;
e7e1f93f 244
245 grub_list_iterate (GRUB_AS_LIST (users), hook);
246
247 if (!cur || ! cur->callback)
248 {
249 grub_list_iterate (GRUB_AS_LIST (users), hook_any);
250
251 /* No users present at all. */
252 if (!cur)
3fd6f044 253 goto access_denied;
e7e1f93f 254
255 /* Display any of available authentication schemes. */
256 err = cur->callback (login, 0);
257
3fd6f044 258 goto access_denied;
e7e1f93f 259 }
260 err = cur->callback (login, cur->arg);
261 if (is_authenticated (userlist))
3fd6f044
RM
262 {
263 punishment_delay = 1;
264 return GRUB_ERR_NONE;
265 }
266
267 access_denied:
268 grub_sleep (punishment_delay);
269
270 if (punishment_delay < GRUB_ULONG_MAX / 2)
271 punishment_delay *= 2;
272
e7e1f93f 273 return GRUB_ACCESS_DENIED;
274}