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
, GRUB_FILE_TYPE_CONFIG
);
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",
136 entrysrc
, 0, NULL
, NULL
);
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, NULL
,
194 grub_normal_parse_line (suffix
, legacy_file_getline
, NULL
);
197 grub_free (entrysrc
);
199 return GRUB_ERR_NONE
;
203 grub_cmd_legacy_source (struct grub_command
*cmd
,
204 int argc
, char **args
)
206 int new_env
, extractor
;
210 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
212 extractor
= (cmd
->name
[0] == 'e');
213 new_env
= (cmd
->name
[extractor
? (sizeof ("extract_legacy_entries_") - 1)
214 : (sizeof ("legacy_") - 1)] == 'c');
219 if (new_env
&& !extractor
)
220 grub_env_context_open ();
222 grub_env_extractor_open (!new_env
);
224 ret
= legacy_file (args
[0]);
229 menu
= grub_env_get_menu ();
230 if (menu
&& menu
->size
)
231 grub_show_menu (menu
, 1, 0);
233 grub_env_context_close ();
236 grub_env_extractor_close (!new_env
);
243 GUESS_IT
, LINUX
, MULTIBOOT
, KFREEBSD
, KNETBSD
, KOPENBSD
247 grub_cmd_legacy_kernel (struct grub_command
*mycmd
__attribute__ ((unused
)),
248 int argc
, char **args
)
252 int no_mem_option
= 0;
254 struct grub_command
*cmd
;
257 grub_err_t err
= GRUB_ERR_NONE
;
259 for (i
= 0; i
< 2; i
++)
261 /* FIXME: really support this. */
262 if (argc
>= 1 && grub_strcmp (args
[0], "--no-mem-option") == 0)
272 /* linux16 handles both zImages and bzImages. */
273 if (argc
>= 1 && (grub_strcmp (args
[0], "--type=linux") == 0
274 || grub_strcmp (args
[0], "--type=biglinux") == 0))
282 if (argc
>= 1 && grub_strcmp (args
[0], "--type=multiboot") == 0)
284 kernel_type
= MULTIBOOT
;
290 if (argc
>= 1 && grub_strcmp (args
[0], "--type=freebsd") == 0)
292 kernel_type
= KFREEBSD
;
298 if (argc
>= 1 && grub_strcmp (args
[0], "--type=openbsd") == 0)
300 kernel_type
= KOPENBSD
;
306 if (argc
>= 1 && grub_strcmp (args
[0], "--type=netbsd") == 0)
308 kernel_type
= KNETBSD
;
316 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("filename expected"));
318 cutargs
= grub_malloc (sizeof (cutargs
[0]) * (argc
- 1));
322 grub_memcpy (cutargs
+ 1, args
+ 2, sizeof (cutargs
[0]) * (argc
- 2));
323 cutargs
[0] = args
[0];
327 /* First try Linux. */
328 if (kernel_type
== GUESS_IT
|| kernel_type
== LINUX
)
330 #ifdef GRUB_MACHINE_PCBIOS
331 cmd
= grub_command_find ("linux16");
333 cmd
= grub_command_find ("linux");
337 if (!(cmd
->func
) (cmd
, cutargc
, cutargs
))
343 grub_errno
= GRUB_ERR_NONE
;
346 /* Then multiboot. */
347 if (kernel_type
== GUESS_IT
|| kernel_type
== MULTIBOOT
)
349 cmd
= grub_command_find ("multiboot");
352 if (!(cmd
->func
) (cmd
, argc
, args
))
354 kernel_type
= MULTIBOOT
;
358 grub_errno
= GRUB_ERR_NONE
;
367 const char *hdbiasstr
;
369 hdbiasstr
= grub_env_get ("legacy_hdbias");
372 hdbias
= grub_strtoul (hdbiasstr
, 0, 0);
373 grub_errno
= GRUB_ERR_NONE
;
375 dev
= grub_device_open (0);
377 && dev
->disk
->dev
->id
== GRUB_DISK_DEVICE_BIOSDISK_ID
378 && dev
->disk
->id
>= 0x80 && dev
->disk
->id
<= 0x90)
380 struct grub_partition
*part
= dev
->disk
->partition
;
381 bsd_device
= dev
->disk
->id
- 0x80 - hdbias
;
382 if (part
&& (grub_strcmp (part
->partmap
->name
, "netbsd") == 0
383 || grub_strcmp (part
->partmap
->name
, "openbsd") == 0
384 || grub_strcmp (part
->partmap
->name
, "bsd") == 0))
386 bsd_part
= part
->number
;
389 if (part
&& grub_strcmp (part
->partmap
->name
, "msdos") == 0)
390 bsd_slice
= part
->number
;
393 grub_device_close (dev
);
396 /* k*BSD didn't really work well with grub-legacy. */
397 if (kernel_type
== GUESS_IT
|| kernel_type
== KFREEBSD
)
399 char buf
[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")];
400 if (bsd_device
!= -1)
402 if (bsd_slice
!= -1 && bsd_part
!= -1)
403 grub_snprintf(buf
, sizeof(buf
), "ad%ds%d%c", bsd_device
,
404 bsd_slice
, 'a' + bsd_part
);
405 else if (bsd_slice
!= -1)
406 grub_snprintf(buf
, sizeof(buf
), "ad%ds%d", bsd_device
,
409 grub_snprintf(buf
, sizeof(buf
), "ad%d", bsd_device
);
410 grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf
);
413 grub_env_unset ("kFreeBSD.vfs.root.mountfrom");
414 cmd
= grub_command_find ("kfreebsd");
417 if (!(cmd
->func
) (cmd
, cutargc
, cutargs
))
419 kernel_type
= KFREEBSD
;
423 grub_errno
= GRUB_ERR_NONE
;
428 char bsddevname
[sizeof ("wdXXXXXXXXXXXXY")];
431 if (bsd_device
== -1)
439 bsdargc
= cutargc
+ 2;
440 bsdargs
= grub_malloc (sizeof (bsdargs
[0]) * bsdargc
);
446 grub_memcpy (bsdargs
, args
, argc
* sizeof (bsdargs
[0]));
447 bsdargs
[argc
] = rbuf
;
448 bsdargs
[argc
+ 1] = bsddevname
;
449 grub_snprintf (bsddevname
, sizeof (bsddevname
),
450 "wd%d%c", bsd_device
,
451 bsd_part
!= -1 ? bsd_part
+ 'a' : 'c');
453 if (kernel_type
== GUESS_IT
|| kernel_type
== KNETBSD
)
455 cmd
= grub_command_find ("knetbsd");
458 if (!(cmd
->func
) (cmd
, bsdargc
, bsdargs
))
460 kernel_type
= KNETBSD
;
465 grub_errno
= GRUB_ERR_NONE
;
467 if (kernel_type
== GUESS_IT
|| kernel_type
== KOPENBSD
)
469 cmd
= grub_command_find ("kopenbsd");
472 if (!(cmd
->func
) (cmd
, bsdargc
, bsdargs
))
474 kernel_type
= KOPENBSD
;
479 grub_errno
= GRUB_ERR_NONE
;
483 if (bsdargs
!= cutargs
)
492 err
= grub_error (GRUB_ERR_BAD_OS
, "couldn't load file %s",
500 grub_cmd_legacy_initrd (struct grub_command
*mycmd
__attribute__ ((unused
)),
501 int argc
, char **args
)
503 struct grub_command
*cmd
;
505 if (kernel_type
== LINUX
)
507 #ifdef GRUB_MACHINE_PCBIOS
508 cmd
= grub_command_find ("initrd16");
510 cmd
= grub_command_find ("initrd");
513 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
514 #ifdef GRUB_MACHINE_PCBIOS
521 return cmd
->func (cmd
, argc
? 1 : 0, args
);
523 if (kernel_type
== MULTIBOOT
)
525 cmd
= grub_command_find ("module");
527 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
530 return cmd
->func (cmd
, argc
, args
);
533 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
534 N_("you need to load the kernel first"));
538 grub_cmd_legacy_initrdnounzip (struct grub_command
*mycmd
__attribute__ ((unused
)),
539 int argc
, char **args
)
541 struct grub_command
*cmd
;
543 if (kernel_type
== LINUX
)
545 cmd
= grub_command_find ("initrd16");
547 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
550 return cmd
->func (cmd
, argc
, args
);
552 if (kernel_type
== MULTIBOOT
)
556 char nounzipbuf
[10] = "--nounzip";
558 cmd
= grub_command_find ("module");
560 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("can't find command `%s'"),
563 newargs
= grub_malloc ((argc
+ 1) * sizeof (newargs
[0]));
566 grub_memcpy (newargs
+ 1, args
, argc
* sizeof (newargs
[0]));
567 newargs
[0] = nounzipbuf
;
569 err
= cmd
->func (cmd
, argc
+ 1, newargs
);
574 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
575 N_("you need to load the kernel first"));
579 check_password_deny (const char *user
__attribute__ ((unused
)),
580 const char *entered
__attribute__ ((unused
)),
581 void *password
__attribute__ ((unused
)))
583 return GRUB_ACCESS_DENIED
;
586 #define MD5_HASHLEN 16
588 struct legacy_md5_password
592 grub_uint8_t hash
[MD5_HASHLEN
];
596 check_password_md5_real (const char *entered
,
597 struct legacy_md5_password
*pw
)
599 grub_size_t enteredlen
= grub_strlen (entered
);
600 unsigned char alt_result
[MD5_HASHLEN
];
601 unsigned char *digest
;
606 ctx
= grub_zalloc (GRUB_MD_MD5
->contextsize
);
610 GRUB_MD_MD5
->init (ctx
);
611 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
612 GRUB_MD_MD5
->write (ctx
, pw
->salt
+ 3, pw
->saltlen
- 3);
613 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
614 digest
= GRUB_MD_MD5
->read (ctx
);
615 GRUB_MD_MD5
->final (ctx
);
616 grub_memcpy (alt_result
, digest
, MD5_HASHLEN
);
618 GRUB_MD_MD5
->init (ctx
);
619 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
620 GRUB_MD_MD5
->write (ctx
, pw
->salt
, pw
->saltlen
); /* include the $1$ header */
621 for (i
= enteredlen
; i
> 16; i
-= 16)
622 GRUB_MD_MD5
->write (ctx
, alt_result
, 16);
623 GRUB_MD_MD5
->write (ctx
, alt_result
, i
);
625 for (i
= enteredlen
; i
> 0; i
>>= 1)
626 GRUB_MD_MD5
->write (ctx
, entered
+ ((i
& 1) ? enteredlen
: 0), 1);
627 digest
= GRUB_MD_MD5
->read (ctx
);
628 GRUB_MD_MD5
->final (ctx
);
630 for (i
= 0; i
< 1000; i
++)
632 grub_memcpy (alt_result
, digest
, 16);
634 GRUB_MD_MD5
->init (ctx
);
636 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
638 GRUB_MD_MD5
->write (ctx
, alt_result
, 16);
641 GRUB_MD_MD5
->write (ctx
, pw
->salt
+ 3, pw
->saltlen
- 3);
644 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
647 GRUB_MD_MD5
->write (ctx
, alt_result
, 16);
649 GRUB_MD_MD5
->write (ctx
, entered
, enteredlen
);
650 digest
= GRUB_MD_MD5
->read (ctx
);
651 GRUB_MD_MD5
->final (ctx
);
654 ret
= (grub_crypto_memcmp (digest
, pw
->hash
, MD5_HASHLEN
) == 0);
660 check_password_md5 (const char *user
,
664 if (!check_password_md5_real (entered
, password
))
665 return GRUB_ACCESS_DENIED
;
667 grub_auth_authenticate (user
);
669 return GRUB_ERR_NONE
;
679 if (c
>= '0' && c
<= '9')
681 if (c
>= 'A' && c
<= 'Z')
683 if (c
>= 'a' && c
<= 'z')
688 static struct legacy_md5_password
*
689 parse_legacy_md5 (int argc
, char **args
)
691 const char *salt
, *saltend
;
692 struct legacy_md5_password
*pw
= NULL
;
696 if (grub_memcmp (args
[0], "--md5", sizeof ("--md5")) != 0)
700 if (grub_strlen(args
[1]) <= 3)
703 saltend
= grub_strchr (salt
+ 3, '$');
706 pw
= grub_malloc (sizeof (*pw
));
711 for (i
= 0; i
< 5; i
++)
716 for (n
= 0; n
< 4; n
++)
718 int ww
= ib64t(*p
++);
723 pw
->hash
[i
== 4 ? 5 : 12+i
] = w
& 0xff;
724 pw
->hash
[6+i
] = (w
>> 8) & 0xff;
725 pw
->hash
[i
] = (w
>> 16) & 0xff;
730 for (n
= 0; n
< 2; n
++)
732 int ww
= ib64t(*p
++);
742 pw
->saltlen
= saltend
- salt
;
743 pw
->salt
= (grub_uint8_t
*) grub_strndup (salt
, pw
->saltlen
);
755 grub_cmd_legacy_password (struct grub_command
*mycmd
__attribute__ ((unused
)),
756 int argc
, char **args
)
758 struct legacy_md5_password
*pw
= NULL
;
761 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
762 if (args
[0][0] != '-' || args
[0][1] != '-')
763 return grub_normal_set_password ("legacy", args
[0]);
765 pw
= parse_legacy_md5 (argc
, args
);
768 return grub_auth_register_authentication ("legacy", check_password_md5
, pw
);
770 /* This is to imitate minor difference between grub-legacy in GRUB2.
771 If 2 password commands are executed in a row and second one fails
772 on GRUB2 the password of first one is used, whereas in grub-legacy
773 authenthication is denied. In case of no password command was executed
774 early both versions deny any access. */
775 return grub_auth_register_authentication ("legacy", check_password_deny
,
780 grub_legacy_check_md5_password (int argc
, char **args
,
783 struct legacy_md5_password
*pw
= NULL
;
786 if (args
[0][0] != '-' || args
[0][1] != '-')
788 char correct
[GRUB_AUTH_MAX_PASSLEN
];
790 grub_memset (correct
, 0, sizeof (correct
));
791 grub_strncpy (correct
, args
[0], sizeof (correct
));
793 return grub_crypto_memcmp (entered
, correct
, GRUB_AUTH_MAX_PASSLEN
) == 0;
796 pw
= parse_legacy_md5 (argc
, args
);
801 ret
= check_password_md5_real (entered
, pw
);
807 grub_cmd_legacy_check_password (struct grub_command
*mycmd
__attribute__ ((unused
)),
808 int argc
, char **args
)
810 char entered
[GRUB_AUTH_MAX_PASSLEN
];
813 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("one argument expected"));
814 grub_puts_ (N_("Enter password: "));
815 if (!grub_password_get (entered
, GRUB_AUTH_MAX_PASSLEN
))
816 return GRUB_ACCESS_DENIED
;
818 if (!grub_legacy_check_md5_password (argc
, args
,
820 return GRUB_ACCESS_DENIED
;
822 return GRUB_ERR_NONE
;
825 static grub_command_t cmd_source
, cmd_configfile
;
826 static grub_command_t cmd_source_extract
, cmd_configfile_extract
;
827 static grub_command_t cmd_kernel
, cmd_initrd
, cmd_initrdnounzip
;
828 static grub_command_t cmd_password
, cmd_check_password
;
830 GRUB_MOD_INIT(legacycfg
)
833 = grub_register_command ("legacy_source",
834 grub_cmd_legacy_source
,
836 /* TRANSLATORS: "legacy config" means
837 "config as used by grub-legacy". */
838 N_("Parse legacy config in same context"));
840 = grub_register_command ("legacy_configfile",
841 grub_cmd_legacy_source
,
843 N_("Parse legacy config in new context"));
845 = grub_register_command ("extract_legacy_entries_source",
846 grub_cmd_legacy_source
,
848 N_("Parse legacy config in same context taking only menu entries"));
849 cmd_configfile_extract
850 = grub_register_command ("extract_legacy_entries_configfile",
851 grub_cmd_legacy_source
,
853 N_("Parse legacy config in new context taking only menu entries"));
855 cmd_kernel
= grub_register_command ("legacy_kernel",
856 grub_cmd_legacy_kernel
,
857 N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
858 N_("Simulate grub-legacy `kernel' command"));
860 cmd_initrd
= grub_register_command ("legacy_initrd",
861 grub_cmd_legacy_initrd
,
862 N_("FILE [ARG ...]"),
863 N_("Simulate grub-legacy `initrd' command"));
864 cmd_initrdnounzip
= grub_register_command ("legacy_initrd_nounzip",
865 grub_cmd_legacy_initrdnounzip
,
866 N_("FILE [ARG ...]"),
867 N_("Simulate grub-legacy `modulenounzip' command"));
869 cmd_password
= grub_register_command ("legacy_password",
870 grub_cmd_legacy_password
,
871 N_("[--md5] PASSWD [FILE]"),
872 N_("Simulate grub-legacy `password' command"));
874 cmd_check_password
= grub_register_command ("legacy_check_password",
875 grub_cmd_legacy_check_password
,
876 N_("[--md5] PASSWD [FILE]"),
877 N_("Simulate grub-legacy `password' command in menu entry mode"));
881 GRUB_MOD_FINI(legacycfg
)
883 grub_unregister_command (cmd_source
);
884 grub_unregister_command (cmd_configfile
);
885 grub_unregister_command (cmd_source_extract
);
886 grub_unregister_command (cmd_configfile_extract
);
888 grub_unregister_command (cmd_kernel
);
889 grub_unregister_command (cmd_initrd
);
890 grub_unregister_command (cmd_initrdnounzip
);
892 grub_unregister_command (cmd_password
);
893 grub_unregister_command (cmd_check_password
);