2
* GRUB -- GRand Unified Bootloader
3
* Copyright (C) 2000, 2001, 2010 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/types.h>
20
#include <grub/misc.h>
21
#include <grub/command.h>
25
#include <grub/file.h>
26
#include <grub/normal.h>
27
#include <grub/script_sh.h>
28
#include <grub/i18n.h>
29
#include <grub/term.h>
30
#include <grub/legacy_parse.h>
31
#include <grub/crypto.h>
32
#include <grub/auth.h>
33
#include <grub/disk.h>
34
#include <grub/partition.h>
37
legacy_file (const char *filename)
40
char *entryname = NULL, *entrysrc = NULL;
42
char *suffix = grub_strdup ("");
44
auto grub_err_t getline (char **line, int cont);
45
grub_err_t getline (char **line,
46
int cont __attribute__ ((unused)))
55
file = grub_file_open (filename);
59
menu = grub_env_get_menu ();
62
menu = grub_zalloc (sizeof (*menu));
66
grub_env_set_menu (menu);
71
char *buf = grub_file_getline (file);
74
if (!buf && grub_errno)
76
grub_file_close (file);
88
parsed = grub_legacy_parse (buf, &entryname, &newsuffix);
95
suffix = grub_realloc (suffix, grub_strlen (suffix)
96
+ grub_strlen (newsuffix) + 1);
100
grub_free (entrysrc);
102
grub_free (newsuffix);
106
grub_memcpy (suffix + grub_strlen (suffix), newsuffix,
107
grub_strlen (newsuffix) + 1);
108
grub_free (newsuffix);
111
if (oldname != entryname && oldname)
113
const char **args = grub_malloc (sizeof (args[0]));
116
grub_file_close (file);
120
grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL,
128
if (parsed && !entryname)
130
grub_normal_parse_line (parsed, getline);
144
entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc)
145
+ grub_strlen (parsed) + 1);
153
grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed,
154
grub_strlen (parsed) + 1);
160
grub_file_close (file);
164
const char **args = grub_malloc (sizeof (args[0]));
167
grub_file_close (file);
171
grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, entrysrc, 0);
175
grub_normal_parse_line (suffix, getline);
178
grub_free (entrysrc);
180
return GRUB_ERR_NONE;
184
grub_cmd_legacy_source (struct grub_command *cmd,
185
int argc, char **args)
187
int new_env, extractor;
191
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
193
extractor = (cmd->name[0] == 'e');
194
new_env = (cmd->name[extractor ? (sizeof ("extract_legacy_entries_") - 1)
195
: (sizeof ("legacy_") - 1)] == 'c');
200
if (new_env && !extractor)
201
grub_env_context_open ();
203
grub_env_extractor_open (!new_env);
205
ret = legacy_file (args[0]);
210
menu = grub_env_get_menu ();
211
if (menu && menu->size)
212
grub_show_menu (menu, 1);
214
grub_env_context_close ();
217
grub_env_extractor_close (!new_env);
224
GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD
228
grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)),
229
int argc, char **args)
233
int no_mem_option = 0;
235
struct grub_command *cmd;
239
for (i = 0; i < 2; i++)
241
/* FIXME: really support this. */
242
if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0)
252
/* linux16 handles both zImages and bzImages. */
253
if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0
254
|| grub_strcmp (args[0], "--type=biglinux") == 0))
262
if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0)
264
kernel_type = MULTIBOOT;
270
if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0)
272
kernel_type = KFREEBSD;
278
if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0)
280
kernel_type = KOPENBSD;
286
if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0)
288
kernel_type = KNETBSD;
296
return grub_error (GRUB_ERR_BAD_ARGUMENT, "filename required");
298
cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1));
300
grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2));
301
cutargs[0] = args[0];
305
/* First try Linux. */
306
if (kernel_type == GUESS_IT || kernel_type == LINUX)
308
cmd = grub_command_find ("linux16");
311
if (!(cmd->func) (cmd, cutargc, cutargs))
314
return GRUB_ERR_NONE;
317
grub_errno = GRUB_ERR_NONE;
320
/* Then multiboot. */
321
if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT)
323
cmd = grub_command_find ("multiboot");
326
if (!(cmd->func) (cmd, argc, args))
328
kernel_type = MULTIBOOT;
329
return GRUB_ERR_NONE;
332
grub_errno = GRUB_ERR_NONE;
343
hdbiasstr = grub_env_get ("legacy_hdbias");
346
hdbias = grub_strtoul (hdbiasstr, 0, 0);
347
grub_errno = GRUB_ERR_NONE;
349
dev = grub_device_open (0);
351
&& dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID
352
&& dev->disk->dev->id >= 0x80 && dev->disk->dev->id <= 0x90)
354
struct grub_partition *part = dev->disk->partition;
355
bsd_device = dev->disk->id - 0x80 - hdbias;
356
if (part && (grub_strcmp (part->partmap->name, "netbsd") == 0
357
|| grub_strcmp (part->partmap->name, "openbsd") == 0
358
|| grub_strcmp (part->partmap->name, "bsd") == 0))
360
bsd_part = part->number;
363
if (part && grub_strcmp (part->partmap->name, "msdos") == 0)
364
bsd_slice = part->number;
368
/* k*BSD didn't really work well with grub-legacy. */
369
if (kernel_type == GUESS_IT || kernel_type == KFREEBSD)
371
char buf[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")];
372
if (bsd_device != -1)
374
if (bsd_slice != -1 && bsd_part != -1)
375
grub_snprintf(buf, sizeof(buf), "ad%ds%d%c", bsd_device,
376
bsd_slice, 'a' + bsd_part);
377
else if (bsd_slice != -1)
378
grub_snprintf(buf, sizeof(buf), "ad%ds%d", bsd_device,
381
grub_snprintf(buf, sizeof(buf), "ad%d", bsd_device);
382
grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf);
385
grub_env_unset ("kFreeBSD.vfs.root.mountfrom");
386
cmd = grub_command_find ("kfreebsd");
389
if (!(cmd->func) (cmd, cutargc, cutargs))
391
kernel_type = KFREEBSD;
392
return GRUB_ERR_NONE;
395
grub_errno = GRUB_ERR_NONE;
400
char bsddevname[sizeof ("wdXXXXXXXXXXXXY")];
401
if (bsd_device == -1)
408
bsdargc = cutargc + 2;
409
bsdargs = grub_malloc (sizeof (bsdargs[0]) * bsdargc);
410
grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0]));
411
bsdargs[argc] = "-r";
412
bsdargs[argc + 1] = bsddevname;
413
grub_snprintf (bsddevname, sizeof (bsddevname),
414
"wd%d%c", bsd_device,
415
bsd_part != -1 ? bsd_part + 'a' : 'c');
417
if (kernel_type == GUESS_IT || kernel_type == KNETBSD)
419
cmd = grub_command_find ("knetbsd");
422
if (!(cmd->func) (cmd, bsdargc, bsdargs))
424
kernel_type = KNETBSD;
425
return GRUB_ERR_NONE;
428
grub_errno = GRUB_ERR_NONE;
430
if (kernel_type == GUESS_IT || kernel_type == KOPENBSD)
432
cmd = grub_command_find ("kopenbsd");
435
if (!(cmd->func) (cmd, bsdargc, bsdargs))
437
kernel_type = KOPENBSD;
438
return GRUB_ERR_NONE;
441
grub_errno = GRUB_ERR_NONE;
443
if (bsdargs != cutargs)
450
return grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s\n",
455
grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)),
456
int argc, char **args)
458
struct grub_command *cmd;
460
if (kernel_type == LINUX)
462
cmd = grub_command_find ("initrd16");
464
return grub_error (GRUB_ERR_BAD_ARGUMENT, "command initrd16 not found");
466
return cmd->func (cmd, argc, args);
468
if (kernel_type == MULTIBOOT)
470
cmd = grub_command_find ("module");
472
return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found");
474
return cmd->func (cmd, argc, args);
477
return grub_error (GRUB_ERR_BAD_ARGUMENT,
478
"no kernel with module support is loaded in legacy way");
482
grub_cmd_legacy_initrdnounzip (struct grub_command *mycmd __attribute__ ((unused)),
483
int argc, char **args)
485
struct grub_command *cmd;
487
if (kernel_type == LINUX)
489
cmd = grub_command_find ("initrd16");
491
return grub_error (GRUB_ERR_BAD_ARGUMENT, "command initrd16 not found");
493
return cmd->func (cmd, argc, args);
495
if (kernel_type == MULTIBOOT)
499
newargs = grub_malloc ((argc + 1) * sizeof (newargs[0]));
502
grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0]));
503
newargs[0] = "--nounzip";
504
cmd = grub_command_find ("module");
506
return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found");
508
err = cmd->func (cmd, argc + 1, newargs);
513
return grub_error (GRUB_ERR_BAD_ARGUMENT,
514
"no kernel with module support is loaded in legacy way");
518
check_password_deny (const char *user __attribute__ ((unused)),
519
const char *entered __attribute__ ((unused)),
520
void *password __attribute__ ((unused)))
522
return GRUB_ACCESS_DENIED;
525
#define MD5_HASHLEN 16
527
struct legacy_md5_password
531
grub_uint8_t hash[MD5_HASHLEN];
535
check_password_md5_real (const char *entered,
536
struct legacy_md5_password *pw)
538
int enteredlen = grub_strlen (entered);
539
unsigned char alt_result[MD5_HASHLEN];
540
unsigned char *digest;
541
grub_uint8_t ctx[GRUB_MD_MD5->contextsize];
544
GRUB_MD_MD5->init (ctx);
545
GRUB_MD_MD5->write (ctx, entered, enteredlen);
546
GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
547
GRUB_MD_MD5->write (ctx, entered, enteredlen);
548
digest = GRUB_MD_MD5->read (ctx);
549
GRUB_MD_MD5->final (ctx);
550
memcpy (alt_result, digest, MD5_HASHLEN);
552
GRUB_MD_MD5->init (ctx);
553
GRUB_MD_MD5->write (ctx, entered, enteredlen);
554
GRUB_MD_MD5->write (ctx, pw->salt, pw->saltlen); /* include the $1$ header */
555
for (i = enteredlen; i > 16; i -= 16)
556
GRUB_MD_MD5->write (ctx, alt_result, 16);
557
GRUB_MD_MD5->write (ctx, alt_result, i);
559
for (i = enteredlen; i > 0; i >>= 1)
560
GRUB_MD_MD5->write (ctx, entered + ((i & 1) ? enteredlen : 0), 1);
561
digest = GRUB_MD_MD5->read (ctx);
562
GRUB_MD_MD5->final (ctx);
564
for (i = 0; i < 1000; i++)
566
memcpy (alt_result, digest, 16);
568
GRUB_MD_MD5->init (ctx);
570
GRUB_MD_MD5->write (ctx, entered, enteredlen);
572
GRUB_MD_MD5->write (ctx, alt_result, 16);
575
GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
578
GRUB_MD_MD5->write (ctx, entered, enteredlen);
581
GRUB_MD_MD5->write (ctx, alt_result, 16);
583
GRUB_MD_MD5->write (ctx, entered, enteredlen);
584
digest = GRUB_MD_MD5->read (ctx);
585
GRUB_MD_MD5->final (ctx);
588
return (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0);
592
check_password_md5 (const char *user,
596
if (!check_password_md5_real (entered, password))
597
return GRUB_ACCESS_DENIED;
599
grub_auth_authenticate (user);
601
return GRUB_ERR_NONE;
611
if (c >= '0' && c <= '9')
613
if (c >= 'A' && c <= 'Z')
615
if (c >= 'a' && c <= 'z')
620
static struct legacy_md5_password *
621
parse_legacy_md5 (int argc, char **args)
623
const char *salt, *saltend;
624
struct legacy_md5_password *pw = NULL;
628
if (grub_memcmp (args[0], "--md5", sizeof ("--md5")) != 0)
632
if (grub_strlen(args[1]) <= 3)
635
saltend = grub_strchr (salt + 3, '$');
638
pw = grub_malloc (sizeof (*pw));
643
for (i = 0; i < 5; i++)
648
for (n = 0; n < 4; n++)
650
int ww = ib64t(*p++);
655
pw->hash[i == 4 ? 5 : 12+i] = w & 0xff;
656
pw->hash[6+i] = (w >> 8) & 0xff;
657
pw->hash[i] = (w >> 16) & 0xff;
662
for (n = 0; n < 2; n++)
664
int ww = ib64t(*p++);
674
pw->saltlen = saltend - salt;
675
pw->salt = (grub_uint8_t *) grub_strndup (salt, pw->saltlen);
687
grub_cmd_legacy_password (struct grub_command *mycmd __attribute__ ((unused)),
688
int argc, char **args)
690
struct legacy_md5_password *pw = NULL;
693
return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected");
694
if (args[0][0] != '-' || args[0][1] != '-')
695
return grub_normal_set_password ("legacy", args[0]);
697
pw = parse_legacy_md5 (argc, args);
700
return grub_auth_register_authentication ("legacy", check_password_md5, pw);
702
/* This is to imitate minor difference between grub-legacy in GRUB2.
703
If 2 password commands are executed in a row and second one fails
704
on GRUB2 the password of first one is used, whereas in grub-legacy
705
authenthication is denied. In case of no password command was executed
706
early both versions deny any access. */
707
return grub_auth_register_authentication ("legacy", check_password_deny,
712
grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)),
713
int argc, char **args)
715
struct legacy_md5_password *pw = NULL;
716
char entered[GRUB_AUTH_MAX_PASSLEN];
719
return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected");
720
grub_printf ("Enter password:");
721
if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
722
return GRUB_ACCESS_DENIED;
724
if (args[0][0] != '-' || args[0][1] != '-')
726
char correct[GRUB_AUTH_MAX_PASSLEN];
728
grub_memset (correct, 0, sizeof (correct));
729
grub_strncpy (correct, args[0], sizeof (correct));
731
if (grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) != 0)
732
return GRUB_ACCESS_DENIED;
733
return GRUB_ERR_NONE;
736
pw = parse_legacy_md5 (argc, args);
739
return GRUB_ACCESS_DENIED;
741
if (!check_password_md5_real (entered, pw))
742
return GRUB_ACCESS_DENIED;
744
return GRUB_ERR_NONE;
747
static grub_command_t cmd_source, cmd_configfile;
748
static grub_command_t cmd_source_extract, cmd_configfile_extract;
749
static grub_command_t cmd_kernel, cmd_initrd, cmd_initrdnounzip;
750
static grub_command_t cmd_password, cmd_check_password;
752
GRUB_MOD_INIT(legacycfg)
755
= grub_register_command ("legacy_source",
756
grub_cmd_legacy_source,
758
N_("Parse legacy config in same context"));
760
= grub_register_command ("legacy_configfile",
761
grub_cmd_legacy_source,
763
N_("Parse legacy config in new context"));
765
= grub_register_command ("extract_legacy_entries_source",
766
grub_cmd_legacy_source,
768
N_("Parse legacy config in same context taking onl entries"));
769
cmd_configfile_extract
770
= grub_register_command ("extract_legacy_entries_configfile",
771
grub_cmd_legacy_source,
773
N_("Parse legacy config in new context taking onl entries"));
775
cmd_kernel = grub_register_command ("legacy_kernel",
776
grub_cmd_legacy_kernel,
777
N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
778
N_("Simulate grub-legacy kernel command"));
780
cmd_initrd = grub_register_command ("legacy_initrd",
781
grub_cmd_legacy_initrd,
782
N_("FILE [ARG ...]"),
783
N_("Simulate grub-legacy initrd command"));
784
cmd_initrdnounzip = grub_register_command ("legacy_initrd_nounzip",
785
grub_cmd_legacy_initrdnounzip,
786
N_("FILE [ARG ...]"),
787
N_("Simulate grub-legacy modulenounzip command"));
789
cmd_password = grub_register_command ("legacy_password",
790
grub_cmd_legacy_password,
791
N_("[--md5] PASSWD [FILE]"),
792
N_("Simulate grub-legacy password command"));
794
cmd_check_password = grub_register_command ("legacy_check_password",
795
grub_cmd_legacy_check_password,
796
N_("[--md5] PASSWD [FILE]"),
797
N_("Simulate grub-legacy password command in menuentry mode"));
801
GRUB_MOD_FINI(legacycfg)
803
grub_unregister_command (cmd_source);
804
grub_unregister_command (cmd_configfile);
805
grub_unregister_command (cmd_source_extract);
806
grub_unregister_command (cmd_configfile_extract);
808
grub_unregister_command (cmd_kernel);
809
grub_unregister_command (cmd_initrd);
810
grub_unregister_command (cmd_initrdnounzip);
812
grub_unregister_command (cmd_password);
813
grub_unregister_command (cmd_check_password);