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>
36 GRUB_MOD_LICENSE ("GPLv3+");
38 /* Helper for legacy_file. */
40 legacy_file_getline (char **line
, int cont
__attribute__ ((unused
)),
41 void *data
__attribute__ ((unused
)))
48 legacy_file (const char *filename
)
51 char *entryname
= NULL
, *entrysrc
= NULL
;
53 char *suffix
= grub_strdup ("");
58 file
= grub_file_open (filename
);
65 menu
= grub_env_get_menu ();
68 menu
= grub_zalloc (sizeof (*menu
));
75 grub_env_set_menu (menu
);
80 char *buf
= grub_file_getline (file
);
83 if (!buf
&& grub_errno
)
85 grub_file_close (file
);
98 for (ptr
= buf
; *ptr
&& grub_isspace (*ptr
); ptr
++);
101 parsed
= grub_legacy_parse (ptr
, &entryname
, &newsuffix
);
109 suffix
= grub_realloc (suffix
, grub_strlen (suffix
)
110 + grub_strlen (newsuffix
) + 1);
114 grub_free (entrysrc
);
116 grub_free (newsuffix
);
120 grub_memcpy (suffix
+ grub_strlen (suffix
), newsuffix
,
121 grub_strlen (newsuffix
) + 1);
122 grub_free (newsuffix
);
125 if (oldname
!= entryname
&& oldname
)
127 const char **args
= grub_malloc (sizeof (args
[0]));
130 grub_file_close (file
);
134 grub_normal_add_menu_entry (1, args
, NULL
, NULL
, "legacy",
143 if (parsed
&& !entryname
)
145 grub_normal_parse_line (parsed
, legacy_file_getline
, NULL
);
159 entrysrc
= grub_realloc (entrysrc
, grub_strlen (entrysrc
)
160 + grub_strlen (parsed
) + 1);
168 grub_memcpy (entrysrc
+ grub_strlen (entrysrc
), parsed
,
169 grub_strlen (parsed
) + 1);
175 grub_file_close (file
);
179 const char **args
= grub_malloc (sizeof (args
[0]));
182 grub_file_close (file
);
184 grub_free (entrysrc
);
188 grub_normal_add_menu_entry (1, args
, NULL
, NULL
, NULL
,
189 NULL
, NULL
, entrysrc
, 0);
193 grub_normal_parse_line (suffix
, legacy_file_getline
, NULL
);
196 grub_free (entrysrc
);
198 return GRUB_ERR_NONE
;
202 grub_cmd_legacy_source (struct grub_command
*cmd
,
203 int argc
, char **args
)
205 int new_env
, extractor
;
209 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
211 extractor
= (cmd
->name
[0] == 'e');
212 new_env
= (cmd
->name
[extractor
? (sizeof ("extract_legacy_entries_") - 1)
213 : (sizeof ("legacy_") - 1)] == 'c');
218 if (new_env
&& !extractor
)
219 grub_env_context_open ();
221 grub_env_extractor_open (!new_env
);
223 ret
= legacy_file (args
[0]);
228 menu
= grub_env_get_menu ();
229 if (menu
&& menu
->size
)
230 grub_show_menu (menu
, 1, 0);
232 grub_env_context_close ();
235 grub_env_extractor_close (!new_env
);
242 GUESS_IT
, LINUX
, MULTIBOOT
, KFREEBSD
, KNETBSD
, KOPENBSD
246 grub_cmd_legacy_kernel (struct grub_command
*mycmd
__attribute__ ((unused
)),
247 int argc
, char **args
)
251 int no_mem_option
= 0;
253 struct grub_command
*cmd
;
257 for (i
= 0; i
< 2; i
++)
259 /* FIXME: really support this. */
260 if (argc
>= 1 && grub_strcmp (args
[0], "--no-mem-option") == 0)
270 /* linux16 handles both zImages and bzImages. */
271 if (argc
>= 1 && (grub_strcmp (args
[0], "--type=linux") == 0
272 || grub_strcmp (args
[0], "--type=biglinux") == 0))
280 if (argc
>= 1 && grub_strcmp (args
[0], "--type=multiboot") == 0)
282 kernel_type
= MULTIBOOT
;
288 if (argc
>= 1 && grub_strcmp (args
[0], "--type=freebsd") == 0)
290 kernel_type
= KFREEBSD
;
296 if (argc
>= 1 && grub_strcmp (args
[0], "--type=openbsd") == 0)
298 kernel_type
= KOPENBSD
;
304 if (argc
>= 1 && grub_strcmp (args
[0], "--type=netbsd") == 0)
306 kernel_type
= KNETBSD
;
314 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
316 cutargs
= grub_malloc (sizeof (cutargs
[0]) * (argc
- 1));
318 grub_memcpy (cutargs
+ 1, args
+ 2, sizeof (cutargs
[0]) * (argc
- 2));
319 cutargs
[0] = args
[0];
323 /* First try Linux. */
324 if (kernel_type
== GUESS_IT
|| kernel_type
== LINUX
)
326 #ifdef GRUB_MACHINE_PCBIOS
327 cmd
= grub_command_find ("linux16");
329 cmd
= grub_command_find ("linux");
333 if (!(cmd
->func
) (cmd
, cutargc
, cutargs
))
336 return GRUB_ERR_NONE
;
339 grub_errno
= GRUB_ERR_NONE
;
342 /* Then multiboot. */
343 if (kernel_type
== GUESS_IT
|| kernel_type
== MULTIBOOT
)
345 cmd
= grub_command_find ("multiboot");
348 if (!(cmd
->func
) (cmd
, argc
, args
))
350 kernel_type
= MULTIBOOT
;
351 return GRUB_ERR_NONE
;
354 grub_errno
= GRUB_ERR_NONE
;
363 const char *hdbiasstr
;
365 hdbiasstr
= grub_env_get ("legacy_hdbias");
368 hdbias
= grub_strtoul (hdbiasstr
, 0, 0);
369 grub_errno
= GRUB_ERR_NONE
;
371 dev
= grub_device_open (0);
373 && dev
->disk
->dev
->id
== GRUB_DISK_DEVICE_BIOSDISK_ID
374 && dev
->disk
->id
>= 0x80 && dev
->disk
->id
<= 0x90)
376 struct grub_partition
*part
= dev
->disk
->partition
;
377 bsd_device
= dev
->disk
->id
- 0x80 - hdbias
;
378 if (part
&& (grub_strcmp (part
->partmap
->name
, "netbsd") == 0
379 || grub_strcmp (part
->partmap
->name
, "openbsd") == 0
380 || grub_strcmp (part
->partmap
->name
, "bsd") == 0))
382 bsd_part
= part
->number
;
385 if (part
&& grub_strcmp (part
->partmap
->name
, "msdos") == 0)
386 bsd_slice
= part
->number
;
389 grub_device_close (dev
);
392 /* k*BSD didn't really work well with grub-legacy. */
393 if (kernel_type
== GUESS_IT
|| kernel_type
== KFREEBSD
)
395 char buf
[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")];
396 if (bsd_device
!= -1)
398 if (bsd_slice
!= -1 && bsd_part
!= -1)
399 grub_snprintf(buf
, sizeof(buf
), "ad%ds%d%c", bsd_device
,
400 bsd_slice
, 'a' + bsd_part
);
401 else if (bsd_slice
!= -1)
402 grub_snprintf(buf
, sizeof(buf
), "ad%ds%d", bsd_device
,
405 grub_snprintf(buf
, sizeof(buf
), "ad%d", bsd_device
);
406 grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf
);
409 grub_env_unset ("kFreeBSD.vfs.root.mountfrom");
410 cmd
= grub_command_find ("kfreebsd");
413 if (!(cmd
->func
) (cmd
, cutargc
, cutargs
))
415 kernel_type
= KFREEBSD
;
416 return GRUB_ERR_NONE
;
419 grub_errno
= GRUB_ERR_NONE
;
424 char bsddevname
[sizeof ("wdXXXXXXXXXXXXY")];
425 if (bsd_device
== -1)
433 bsdargc
= cutargc
+ 2;
434 bsdargs
= grub_malloc (sizeof (bsdargs
[0]) * bsdargc
);
435 grub_memcpy (bsdargs
, args
, argc
* sizeof (bsdargs
[0]));
436 bsdargs
[argc
] = rbuf
;
437 bsdargs
[argc
+ 1] = bsddevname
;
438 grub_snprintf (bsddevname
, sizeof (bsddevname
),
439 "wd%d%c", bsd_device
,
440 bsd_part
!= -1 ? bsd_part
+ 'a' : 'c');
442 if (kernel_type
== GUESS_IT
|| kernel_type
== KNETBSD
)
444 cmd
= grub_command_find ("knetbsd");
447 if (!(cmd
->func
) (cmd
, bsdargc
, bsdargs
))
449 kernel_type
= KNETBSD
;
450 return GRUB_ERR_NONE
;
453 grub_errno
= GRUB_ERR_NONE
;
455 if (kernel_type
== GUESS_IT
|| kernel_type
== KOPENBSD
)
457 cmd
= grub_command_find ("kopenbsd");
460 if (!(cmd
->func
) (cmd
, bsdargc
, bsdargs
))
462 kernel_type
= KOPENBSD
;
463 return GRUB_ERR_NONE
;
466 grub_errno
= GRUB_ERR_NONE
;
468 if (bsdargs
!= cutargs
)
475 return grub_error (GRUB_ERR_BAD_OS
, "couldn't load file %s",
480 grub_cmd_legacy_initrd (struct grub_command
*mycmd
__attribute__ ((unused
)),
481 int argc
, char **args
)
483 struct grub_command
*cmd
;
485 if (kernel_type
== LINUX
)
487 #ifdef GRUB_MACHINE_PCBIOS
488 cmd
= grub_command_find ("initrd16");
490 cmd
= grub_command_find ("initrd");
493 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
494 #ifdef GRUB_MACHINE_PCBIOS
501 return cmd
->func (cmd
, argc
, args
);
503 if (kernel_type
== MULTIBOOT
)
505 cmd
= grub_command_find ("module");
507 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
510 return cmd
->func (cmd
, argc
, args
);
513 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
514 N_("you need to load the kernel first"));
518 grub_cmd_legacy_initrdnounzip (struct grub_command
*mycmd
__attribute__ ((unused
)),
519 int argc
, char **args
)
521 struct grub_command
*cmd
;
523 if (kernel_type
== LINUX
)
525 cmd
= grub_command_find ("initrd16");
527 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
530 return cmd
->func (cmd
, argc
, args
);
532 if (kernel_type
== MULTIBOOT
)
536 char nounzipbuf
[10] = "--nounzip";
537 newargs
= grub_malloc ((argc
+ 1) * sizeof (newargs
[0]));
540 grub_memcpy (newargs
+ 1, args
, argc
* sizeof (newargs
[0]));
541 newargs
[0] = nounzipbuf
;
542 cmd
= grub_command_find ("module");
544 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
547 err
= cmd
->func (cmd
, argc
+ 1, newargs
);
552 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
553 N_("you need to load the kernel first"));
557 check_password_deny (const char *user
__attribute__ ((unused
)),
558 const char *entered
__attribute__ ((unused
)),
559 void *password
__attribute__ ((unused
)))
561 return GRUB_ACCESS_DENIED
;
564 #define MD5_HASHLEN 16
566 struct legacy_md5_password
570 grub_uint8_t hash
[MD5_HASHLEN
];
574 check_password_md5_real (const char *entered
,
575 struct legacy_md5_password
*pw
)
577 grub_size_t enteredlen
= grub_strlen (entered
);
578 unsigned char alt_result
[MD5_HASHLEN
];
579 unsigned char *digest
;
584 ctx
= grub_zalloc (GRUB_MD_MD5
->contextsize
);
588 GRUB_MD_MD5
->init (ctx
);
589 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
590 GRUB_MD_MD5
->write (ctx
, pw
->salt
+ 3, pw
->saltlen
- 3);
591 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
592 digest
= GRUB_MD_MD5
->read (ctx
);
593 GRUB_MD_MD5
->final (ctx
);
594 grub_memcpy (alt_result
, digest
, MD5_HASHLEN
);
596 GRUB_MD_MD5
->init (ctx
);
597 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
598 GRUB_MD_MD5
->write (ctx
, pw
->salt
, pw
->saltlen
); /* include the $1$ header */
599 for (i
= enteredlen
; i
> 16; i
-= 16)
600 GRUB_MD_MD5
->write (ctx
, alt_result
, 16);
601 GRUB_MD_MD5
->write (ctx
, alt_result
, i
);
603 for (i
= enteredlen
; i
> 0; i
>>= 1)
604 GRUB_MD_MD5
->write (ctx
, entered
+ ((i
& 1) ? enteredlen
: 0), 1);
605 digest
= GRUB_MD_MD5
->read (ctx
);
606 GRUB_MD_MD5
->final (ctx
);
608 for (i
= 0; i
< 1000; i
++)
610 grub_memcpy (alt_result
, digest
, 16);
612 GRUB_MD_MD5
->init (ctx
);
614 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
616 GRUB_MD_MD5
->write (ctx
, alt_result
, 16);
619 GRUB_MD_MD5
->write (ctx
, pw
->salt
+ 3, pw
->saltlen
- 3);
622 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
625 GRUB_MD_MD5
->write (ctx
, alt_result
, 16);
627 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
628 digest
= GRUB_MD_MD5
->read (ctx
);
629 GRUB_MD_MD5
->final (ctx
);
632 ret
= (grub_crypto_memcmp (digest
, pw
->hash
, MD5_HASHLEN
) == 0);
638 check_password_md5 (const char *user
,
642 if (!check_password_md5_real (entered
, password
))
643 return GRUB_ACCESS_DENIED
;
645 grub_auth_authenticate (user
);
647 return GRUB_ERR_NONE
;
657 if (c
>= '0' && c
<= '9')
659 if (c
>= 'A' && c
<= 'Z')
661 if (c
>= 'a' && c
<= 'z')
666 static struct legacy_md5_password
*
667 parse_legacy_md5 (int argc
, char **args
)
669 const char *salt
, *saltend
;
670 struct legacy_md5_password
*pw
= NULL
;
674 if (grub_memcmp (args
[0], "--md5", sizeof ("--md5")) != 0)
678 if (grub_strlen(args
[1]) <= 3)
681 saltend
= grub_strchr (salt
+ 3, '$');
684 pw
= grub_malloc (sizeof (*pw
));
689 for (i
= 0; i
< 5; i
++)
694 for (n
= 0; n
< 4; n
++)
696 int ww
= ib64t(*p
++);
701 pw
->hash
[i
== 4 ? 5 : 12+i
] = w
& 0xff;
702 pw
->hash
[6+i
] = (w
>> 8) & 0xff;
703 pw
->hash
[i
] = (w
>> 16) & 0xff;
708 for (n
= 0; n
< 2; n
++)
710 int ww
= ib64t(*p
++);
720 pw
->saltlen
= saltend
- salt
;
721 pw
->salt
= (grub_uint8_t
*) grub_strndup (salt
, pw
->saltlen
);
733 grub_cmd_legacy_password (struct grub_command
*mycmd
__attribute__ ((unused
)),
734 int argc
, char **args
)
736 struct legacy_md5_password
*pw
= NULL
;
739 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
740 if (args
[0][0] != '-' || args
[0][1] != '-')
741 return grub_normal_set_password ("legacy", args
[0]);
743 pw
= parse_legacy_md5 (argc
, args
);
746 return grub_auth_register_authentication ("legacy", check_password_md5
, pw
);
748 /* This is to imitate minor difference between grub-legacy in GRUB2.
749 If 2 password commands are executed in a row and second one fails
750 on GRUB2 the password of first one is used, whereas in grub-legacy
751 authenthication is denied. In case of no password command was executed
752 early both versions deny any access. */
753 return grub_auth_register_authentication ("legacy", check_password_deny
,
758 grub_legacy_check_md5_password (int argc
, char **args
,
761 struct legacy_md5_password
*pw
= NULL
;
764 if (args
[0][0] != '-' || args
[0][1] != '-')
766 char correct
[GRUB_AUTH_MAX_PASSLEN
];
768 grub_memset (correct
, 0, sizeof (correct
));
769 grub_strncpy (correct
, args
[0], sizeof (correct
));
771 return grub_crypto_memcmp (entered
, correct
, GRUB_AUTH_MAX_PASSLEN
) == 0;
774 pw
= parse_legacy_md5 (argc
, args
);
779 ret
= check_password_md5_real (entered
, pw
);
785 grub_cmd_legacy_check_password (struct grub_command
*mycmd
__attribute__ ((unused
)),
786 int argc
, char **args
)
788 char entered
[GRUB_AUTH_MAX_PASSLEN
];
791 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
792 grub_puts_ (N_("Enter password: "));
793 if (!grub_password_get (entered
, GRUB_AUTH_MAX_PASSLEN
))
794 return GRUB_ACCESS_DENIED
;
796 if (!grub_legacy_check_md5_password (argc
, args
,
798 return GRUB_ACCESS_DENIED
;
800 return GRUB_ERR_NONE
;
803 static grub_command_t cmd_source
, cmd_configfile
;
804 static grub_command_t cmd_source_extract
, cmd_configfile_extract
;
805 static grub_command_t cmd_kernel
, cmd_initrd
, cmd_initrdnounzip
;
806 static grub_command_t cmd_password
, cmd_check_password
;
808 GRUB_MOD_INIT(legacycfg
)
811 = grub_register_command ("legacy_source",
812 grub_cmd_legacy_source
,
814 /* TRANSLATORS: "legacy config" means
815 "config as used by grub-legacy". */
816 N_("Parse legacy config in same context"));
818 = grub_register_command ("legacy_configfile",
819 grub_cmd_legacy_source
,
821 N_("Parse legacy config in new context"));
823 = grub_register_command ("extract_legacy_entries_source",
824 grub_cmd_legacy_source
,
826 N_("Parse legacy config in same context taking only menu entries"));
827 cmd_configfile_extract
828 = grub_register_command ("extract_legacy_entries_configfile",
829 grub_cmd_legacy_source
,
831 N_("Parse legacy config in new context taking only menu entries"));
833 cmd_kernel
= grub_register_command ("legacy_kernel",
834 grub_cmd_legacy_kernel
,
835 N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
836 N_("Simulate grub-legacy `kernel' command"));
838 cmd_initrd
= grub_register_command ("legacy_initrd",
839 grub_cmd_legacy_initrd
,
840 N_("FILE [ARG ...]"),
841 N_("Simulate grub-legacy `initrd' command"));
842 cmd_initrdnounzip
= grub_register_command ("legacy_initrd_nounzip",
843 grub_cmd_legacy_initrdnounzip
,
844 N_("FILE [ARG ...]"),
845 N_("Simulate grub-legacy `modulenounzip' command"));
847 cmd_password
= grub_register_command ("legacy_password",
848 grub_cmd_legacy_password
,
849 N_("[--md5] PASSWD [FILE]"),
850 N_("Simulate grub-legacy `password' command"));
852 cmd_check_password
= grub_register_command ("legacy_check_password",
853 grub_cmd_legacy_check_password
,
854 N_("[--md5] PASSWD [FILE]"),
855 N_("Simulate grub-legacy `password' command in menu entry mode"));
859 GRUB_MOD_FINI(legacycfg
)
861 grub_unregister_command (cmd_source
);
862 grub_unregister_command (cmd_configfile
);
863 grub_unregister_command (cmd_source_extract
);
864 grub_unregister_command (cmd_configfile_extract
);
866 grub_unregister_command (cmd_kernel
);
867 grub_unregister_command (cmd_initrd
);
868 grub_unregister_command (cmd_initrdnounzip
);
870 grub_unregister_command (cmd_password
);
871 grub_unregister_command (cmd_check_password
);