2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
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.
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.
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/>.
19 #include <grub/auth.h>
20 #include <grub/list.h>
22 #include <grub/misc.h>
24 #include <grub/normal.h>
25 #include <grub/time.h>
26 #include <grub/i18n.h>
30 struct grub_auth_user
*next
;
32 grub_auth_callback_t callback
;
37 struct grub_auth_user
*users
= NULL
;
40 grub_auth_strcmp (const char *s1
, const char *s2
)
45 end
= grub_get_time_ms () + 100;
46 ret
= grub_strcmp (s1
, s2
);
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
);
56 grub_iswordseparator (int c
)
58 return (grub_isspace (c
) || c
== ',' || c
== ';' || c
== '|' || c
== '&');
62 grub_auth_strword (const char *haystack
, const char *needle
)
64 const char *n_pos
= needle
;
67 while (grub_iswordseparator (*haystack
))
73 /* Crawl both the needle and the haystack word we're on. */
74 while(*haystack
&& !grub_iswordseparator (*haystack
))
76 if (*haystack
== *n_pos
&& ok
)
92 grub_auth_register_authentication (const char *user
,
93 grub_auth_callback_t callback
,
96 struct grub_auth_user
*cur
;
98 cur
= grub_named_list_find (GRUB_AS_NAMED_LIST (users
), user
);
100 cur
= grub_zalloc (sizeof (*cur
));
103 cur
->callback
= callback
;
107 cur
->name
= grub_strdup (user
);
113 grub_list_push (GRUB_AS_LIST_P (&users
), GRUB_AS_LIST (cur
));
115 return GRUB_ERR_NONE
;
119 grub_auth_unregister_authentication (const char *user
)
121 struct grub_auth_user
*cur
;
122 cur
= grub_named_list_find (GRUB_AS_NAMED_LIST (users
), user
);
124 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "user '%s' not found", user
);
125 if (!cur
->authenticated
)
127 grub_free (cur
->name
);
128 grub_list_remove (GRUB_AS_LIST_P (&users
), GRUB_AS_LIST (cur
));
133 cur
->callback
= NULL
;
136 return GRUB_ERR_NONE
;
140 grub_auth_authenticate (const char *user
)
142 struct grub_auth_user
*cur
;
144 cur
= grub_named_list_find (GRUB_AS_NAMED_LIST (users
), user
);
146 cur
= grub_zalloc (sizeof (*cur
));
150 cur
->authenticated
= 1;
154 cur
->name
= grub_strdup (user
);
160 grub_list_push (GRUB_AS_LIST_P (&users
), GRUB_AS_LIST (cur
));
163 return GRUB_ERR_NONE
;
167 grub_auth_deauthenticate (const char *user
)
169 struct grub_auth_user
*cur
;
170 cur
= grub_named_list_find (GRUB_AS_NAMED_LIST (users
), user
);
172 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "user '%s' not found", user
);
175 grub_free (cur
->name
);
176 grub_list_remove (GRUB_AS_LIST_P (&users
), GRUB_AS_LIST (cur
));
180 cur
->authenticated
= 0;
181 return GRUB_ERR_NONE
;
185 is_authenticated (const char *userlist
)
187 const char *superusers
;
189 auto int hook (grub_list_t item
);
190 int hook (grub_list_t item
)
193 if (!((struct grub_auth_user
*) item
)->authenticated
)
195 name
= ((struct grub_auth_user
*) item
)->name
;
197 return (userlist
&& grub_auth_strword (userlist
, name
))
198 || grub_auth_strword (superusers
, name
);
201 superusers
= grub_env_get ("superusers");
206 return grub_list_iterate (GRUB_AS_LIST (users
), hook
);
210 grub_auth_check_authentication (const char *userlist
)
213 struct grub_auth_user
*cur
= NULL
;
215 static unsigned long punishment_delay
= 1;
217 auto int hook (grub_list_t item
);
218 int hook (grub_list_t item
)
220 if (grub_auth_strcmp (login
, ((struct grub_auth_user
*) item
)->name
) == 0)
221 cur
= (struct grub_auth_user
*) item
;
225 auto int hook_any (grub_list_t item
);
226 int hook_any (grub_list_t item
)
228 if (((struct grub_auth_user
*) item
)->callback
)
229 cur
= (struct grub_auth_user
*) item
;
233 grub_memset (login
, 0, sizeof (login
));
235 if (is_authenticated (userlist
))
237 punishment_delay
= 1;
238 return GRUB_ERR_NONE
;
241 if (!grub_cmdline_get (N_("Enter username:"), login
, sizeof (login
) - 1,
245 grub_list_iterate (GRUB_AS_LIST (users
), hook
);
247 if (!cur
|| ! cur
->callback
)
249 grub_list_iterate (GRUB_AS_LIST (users
), hook_any
);
251 /* No users present at all. */
255 /* Display any of available authentication schemes. */
256 err
= cur
->callback (login
, 0);
260 err
= cur
->callback (login
, cur
->arg
);
261 if (is_authenticated (userlist
))
263 punishment_delay
= 1;
264 return GRUB_ERR_NONE
;
268 grub_sleep (punishment_delay
);
270 if (punishment_delay
< GRUB_ULONG_MAX
/ 2)
271 punishment_delay
*= 2;
273 return GRUB_ACCESS_DENIED
;