legacycfg.c 21 KB
Newer Older
1 2
/*
 *  GRUB  --  GRand Unified Bootloader
3
 *  Copyright (C) 2000, 2001, 2010  Free Software Foundation, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 *  GRUB is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/types.h>
#include <grub/misc.h>
#include <grub/command.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/file.h>
#include <grub/normal.h>
#include <grub/script_sh.h>
#include <grub/i18n.h>
29
#include <grub/term.h>
30
#include <grub/legacy_parse.h>
31 32
#include <grub/crypto.h>
#include <grub/auth.h>
33 34
#include <grub/disk.h>
#include <grub/partition.h>
35

36 37
GRUB_MOD_LICENSE ("GPLv3+");

38 39
/* Helper for legacy_file.  */
static grub_err_t
40 41
legacy_file_getline (char **line, int cont __attribute__ ((unused)),
		     void *data __attribute__ ((unused)))
42 43 44 45 46
{
  *line = 0;
  return GRUB_ERR_NONE;
}

47 48 49 50 51 52
static grub_err_t
legacy_file (const char *filename)
{
  grub_file_t file;
  char *entryname = NULL, *entrysrc = NULL;
  grub_menu_t menu;
53 54 55 56
  char *suffix = grub_strdup ("");

  if (!suffix)
    return grub_errno;
57

58
  file = grub_file_open (filename);
59
  if (! file)
60 61 62 63
    {
      grub_free (suffix);
      return grub_errno;
    }
64 65 66 67 68 69

  menu = grub_env_get_menu ();
  if (! menu)
    {
      menu = grub_zalloc (sizeof (*menu));
      if (! menu)
70 71 72 73
	{
	  grub_free (suffix);
	  return grub_errno;
	}
74 75 76 77 78 79 80

      grub_env_set_menu (menu);
    }

  while (1)
    {
      char *buf = grub_file_getline (file);
81
      char *parsed = NULL;
82 83 84 85

      if (!buf && grub_errno)
	{
	  grub_file_close (file);
86
	  grub_free (suffix);
87 88 89 90 91 92 93 94
	  return grub_errno;
	}

      if (!buf)
	break;

      {
	char *oldname = NULL;
95
	char *newsuffix;
96 97 98
	char *ptr;

	for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
99 100

	oldname = entryname;
101 102
	parsed = grub_legacy_parse (ptr, &entryname, &newsuffix);
	grub_free (buf);
103
	buf = NULL;
104
	if (newsuffix)
105 106 107 108 109
	  {
	    char *t;
	    
	    t = suffix;
	    suffix = grub_realloc (suffix, grub_strlen (suffix)
110
				   + grub_strlen (newsuffix) + 1);
111 112 113 114 115
	    if (!suffix)
	      {
		grub_free (t);
		grub_free (entrysrc);
		grub_free (parsed);
116
		grub_free (newsuffix);
117 118 119
		grub_free (suffix);
		return grub_errno;
	      }
120 121 122 123
	    grub_memcpy (suffix + grub_strlen (suffix), newsuffix,
			 grub_strlen (newsuffix) + 1);
	    grub_free (newsuffix);
	    newsuffix = NULL;
124
	  }
125 126 127 128 129 130 131 132 133
	if (oldname != entryname && oldname)
	  {
	    const char **args = grub_malloc (sizeof (args[0]));
	    if (!args)
	      {
		grub_file_close (file);
		return grub_errno;
	      }
	    args[0] = oldname;
134 135
	    grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
					NULL, NULL,
136
					entrysrc, 0);
137 138 139
	    grub_free (args);
	    entrysrc[0] = 0;
	    grub_free (oldname);
140 141 142 143 144
	  }
      }

      if (parsed && !entryname)
	{
145
	  grub_normal_parse_line (parsed, legacy_file_getline, NULL);
146
	  grub_print_error ();
147
	  grub_free (parsed);
148
	  parsed = NULL;
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	}
      else if (parsed)
	{
	  if (!entrysrc)
	    entrysrc = parsed;
	  else
	    {
	      char *t;

	      t = entrysrc;
	      entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc)
				       + grub_strlen (parsed) + 1);
	      if (!entrysrc)
		{
		  grub_free (t);
		  grub_free (parsed);
165
		  grub_free (suffix);
166 167
		  return grub_errno;
		}
168
	      grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed,
169 170 171 172 173 174 175 176 177 178 179 180 181 182
			   grub_strlen (parsed) + 1);
	      grub_free (parsed);
	      parsed = NULL;
	    }
	}
    }
  grub_file_close (file);

  if (entryname)
    {
      const char **args = grub_malloc (sizeof (args[0]));
      if (!args)
	{
	  grub_file_close (file);
183 184
	  grub_free (suffix);
	  grub_free (entrysrc);
185 186 187
	  return grub_errno;
	}
      args[0] = entryname;
188 189
      grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
				  NULL, NULL, entrysrc, 0);
190
      grub_free (args);
191 192
    }

193
  grub_normal_parse_line (suffix, legacy_file_getline, NULL);
194 195
  grub_print_error ();
  grub_free (suffix);
196
  grub_free (entrysrc);
197

198 199 200 201
  return GRUB_ERR_NONE;
}

static grub_err_t
202
grub_cmd_legacy_source (struct grub_command *cmd,
203 204
			int argc, char **args)
{
205
  int new_env, extractor;
206
  grub_err_t ret;
207

208
  if (argc != 1)
209
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
210

211
  extractor = (cmd->name[0] == 'e');
212 213
  new_env = (cmd->name[extractor ? (sizeof ("extract_legacy_entries_") - 1)
		       : (sizeof ("legacy_") - 1)] == 'c');
214 215 216 217 218 219 220 221

  if (new_env)
    grub_cls ();

  if (new_env && !extractor)
    grub_env_context_open ();
  if (extractor)
    grub_env_extractor_open (!new_env);
222 223

  ret = legacy_file (args[0]);
224

225 226 227 228 229
  if (new_env)
    {
      grub_menu_t menu;
      menu = grub_env_get_menu ();
      if (menu && menu->size)
230
	grub_show_menu (menu, 1, 0);
231 232 233
      if (!extractor)
	grub_env_context_close ();
    }
234 235
  if (extractor)
    grub_env_extractor_close (!new_env);
236 237 238 239

  return ret;
}

240 241 242 243 244 245 246 247 248 249
static enum
  { 
    GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD 
  } kernel_type;

static grub_err_t
grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)),
			int argc, char **args)
{
  int i;
250
#ifdef TODO
251
  int no_mem_option = 0;
252
#endif
253
  struct grub_command *cmd;
254 255
  char **cutargs;
  int cutargc;
256
  grub_err_t err = GRUB_ERR_NONE;
257
  
258 259 260 261 262
  for (i = 0; i < 2; i++)
    {
      /* FIXME: really support this.  */
      if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0)
	{
263
#ifdef TODO
264
	  no_mem_option = 1;
265
#endif
266 267 268 269 270
	  argc--;
	  args++;
	  continue;
	}

271
      /* linux16 handles both zImages and bzImages.   */
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
      if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0
			|| grub_strcmp (args[0], "--type=biglinux") == 0))
	{
	  kernel_type = LINUX;
	  argc--;
	  args++;
	  continue;
	}

      if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0)
	{
	  kernel_type = MULTIBOOT;
	  argc--;
	  args++;
	  continue;
	}

      if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0)
	{
	  kernel_type = KFREEBSD;
	  argc--;
	  args++;
	  continue;
	}

      if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0)
	{
	  kernel_type = KOPENBSD;
	  argc--;
	  args++;
	  continue;
	}

      if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0)
	{
	  kernel_type = KNETBSD;
	  argc--;
	  args++;
	  continue;
	}
    }

314
  if (argc < 2)
315
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
316

317
  cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1));
318 319
  if (!cutargs)
    return grub_errno;
320
  cutargc = argc - 1;
321
  grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2));
322 323
  cutargs[0] = args[0];

324 325 326 327 328
  do
    {
      /* First try Linux.  */
      if (kernel_type == GUESS_IT || kernel_type == LINUX)
	{
329
#ifdef GRUB_MACHINE_PCBIOS
330
	  cmd = grub_command_find ("linux16");
331 332 333
#else
	  cmd = grub_command_find ("linux");
#endif
334 335
	  if (cmd)
	    {
336
	      if (!(cmd->func) (cmd, cutargc, cutargs))
337 338
		{
		  kernel_type = LINUX;
339
		  goto out;
340 341 342 343 344 345 346 347 348 349 350 351 352 353
		}
	    }
	  grub_errno = GRUB_ERR_NONE;
	}

      /* Then multiboot.  */
      if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT)
	{
	  cmd = grub_command_find ("multiboot");
	  if (cmd)
	    {
	      if (!(cmd->func) (cmd, argc, args))
		{
		  kernel_type = MULTIBOOT;
354
		  goto out;
355 356 357 358 359
		}
	    }
	  grub_errno = GRUB_ERR_NONE;
	}

360 361 362 363
      {
	int bsd_device = -1;
	int bsd_slice = -1;
	int bsd_part = -1;
364
	{
365
	  grub_device_t dev;
366
	  const char *hdbiasstr;
367 368 369
	  int hdbias = 0;
	  hdbiasstr = grub_env_get ("legacy_hdbias");
	  if (hdbiasstr)
370
	    {
371 372 373 374 375 376
	      hdbias = grub_strtoul (hdbiasstr, 0, 0);
	      grub_errno = GRUB_ERR_NONE;
	    }
	  dev = grub_device_open (0);
	  if (dev && dev->disk
	      && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID
377
	      && dev->disk->id >= 0x80 && dev->disk->id <= 0x90)
378 379 380 381 382 383
	    {
	      struct grub_partition *part = dev->disk->partition;
	      bsd_device = dev->disk->id - 0x80 - hdbias;
	      if (part && (grub_strcmp (part->partmap->name, "netbsd") == 0
			   || grub_strcmp (part->partmap->name, "openbsd") == 0
			   || grub_strcmp (part->partmap->name, "bsd") == 0))
384
		{
385 386
		  bsd_part = part->number;
		  part = part->parent;
387
		}
388 389
	      if (part && grub_strcmp (part->partmap->name, "msdos") == 0)
		bsd_slice = part->number;
390
	    }
391 392
	  if (dev)
	    grub_device_close (dev);
393
	}
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
	
	/* k*BSD didn't really work well with grub-legacy.  */
	if (kernel_type == GUESS_IT || kernel_type == KFREEBSD)
	  {
	    char buf[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")];
	    if (bsd_device != -1)
	      {
		if (bsd_slice != -1 && bsd_part != -1)
		  grub_snprintf(buf, sizeof(buf), "ad%ds%d%c", bsd_device,
				bsd_slice, 'a' + bsd_part);
		else if (bsd_slice != -1)
		  grub_snprintf(buf, sizeof(buf), "ad%ds%d", bsd_device,
				bsd_slice);
		else
		  grub_snprintf(buf, sizeof(buf), "ad%d", bsd_device);
		grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf);
	      }
	    else
	      grub_env_unset ("kFreeBSD.vfs.root.mountfrom");
	    cmd = grub_command_find ("kfreebsd");
	    if (cmd)
	      {
		if (!(cmd->func) (cmd, cutargc, cutargs))
		  {
		    kernel_type = KFREEBSD;
419
		    goto out;
420 421 422 423
		  }
	      }
	    grub_errno = GRUB_ERR_NONE;
	  }
424
	{
425 426 427
	  char **bsdargs;
	  int bsdargc;
	  char bsddevname[sizeof ("wdXXXXXXXXXXXXY")];
428 429
	  int found = 0;

430
	  if (bsd_device == -1)
431
	    {
432 433 434 435 436
	      bsdargs = cutargs;
	      bsdargc = cutargc;
	    }
	  else
	    {
437
	      char rbuf[3] = "-r";
438 439
	      bsdargc = cutargc + 2;
	      bsdargs = grub_malloc (sizeof (bsdargs[0]) * bsdargc);
440 441 442 443 444
	      if (!bsdargs)
		{
		  err = grub_errno;
		  goto out;
		}
445
	      grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0]));
446
	      bsdargs[argc] = rbuf;
447 448 449 450 451 452 453 454 455
	      bsdargs[argc + 1] = bsddevname;
	      grub_snprintf (bsddevname, sizeof (bsddevname),
			     "wd%d%c", bsd_device,
			     bsd_part != -1 ? bsd_part + 'a' : 'c');
	    }
	  if (kernel_type == GUESS_IT || kernel_type == KNETBSD)
	    {
	      cmd = grub_command_find ("knetbsd");
	      if (cmd)
456
		{
457 458 459
		  if (!(cmd->func) (cmd, bsdargc, bsdargs))
		    {
		      kernel_type = KNETBSD;
460 461
		      found = 1;
		      goto free_bsdargs;
462
		    }
463
		}
464
	      grub_errno = GRUB_ERR_NONE;
465
	    }
466
	  if (kernel_type == GUESS_IT || kernel_type == KOPENBSD)
467
	    {
468 469
	      cmd = grub_command_find ("kopenbsd");
	      if (cmd)
470
		{
471 472 473
		  if (!(cmd->func) (cmd, bsdargc, bsdargs))
		    {
		      kernel_type = KOPENBSD;
474 475
		      found = 1;
		      goto free_bsdargs;
476
		    }
477
		}
478
	      grub_errno = GRUB_ERR_NONE;
479
	    }
480 481

free_bsdargs:
482 483
	  if (bsdargs != cutargs)
	    grub_free (bsdargs);
484 485
	  if (found)
	    goto out;
486
	}
487
      }
488 489 490
    }
  while (0);

491 492 493 494 495
  err = grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s",
		    args[0]);
out:
  grub_free (cutargs);
  return err;
496 497 498 499 500 501 502 503 504 505
}

static grub_err_t
grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)),
			int argc, char **args)
{
  struct grub_command *cmd;

  if (kernel_type == LINUX)
    {
506
#ifdef GRUB_MACHINE_PCBIOS
507
      cmd = grub_command_find ("initrd16");
508 509 510
#else
      cmd = grub_command_find ("initrd");
#endif
511
      if (!cmd)
512
	return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
513 514 515 516 517 518
#ifdef GRUB_MACHINE_PCBIOS
			   "initrd16"
#else
			   "initrd"
#endif
			   );
519 520 521 522 523 524 525

      return cmd->func (cmd, argc, args);
    }
  if (kernel_type == MULTIBOOT)
    {
      cmd = grub_command_find ("module");
      if (!cmd)
526 527
	return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
			   "module");
528 529 530 531 532

      return cmd->func (cmd, argc, args);
    }

  return grub_error (GRUB_ERR_BAD_ARGUMENT,
533
		     N_("you need to load the kernel first"));
534 535
}

536 537 538 539 540 541 542 543 544 545
static grub_err_t
grub_cmd_legacy_initrdnounzip (struct grub_command *mycmd __attribute__ ((unused)),
			       int argc, char **args)
{
  struct grub_command *cmd;

  if (kernel_type == LINUX)
    {
      cmd = grub_command_find ("initrd16");
      if (!cmd)
546 547
	return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
			   "initrd16");
548 549 550 551 552 553 554

      return cmd->func (cmd, argc, args);
    }
  if (kernel_type == MULTIBOOT)
    {
      char **newargs;
      grub_err_t err;
555
      char nounzipbuf[10] = "--nounzip";
556 557 558 559 560 561

      cmd = grub_command_find ("module");
      if (!cmd)
	return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
			   "module");

562 563 564 565
      newargs = grub_malloc ((argc + 1) * sizeof (newargs[0]));
      if (!newargs)
	return grub_errno;
      grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0]));
566
      newargs[0] = nounzipbuf;
567 568 569 570 571 572 573

      err = cmd->func (cmd, argc + 1, newargs);
      grub_free (newargs);
      return err;
    }

  return grub_error (GRUB_ERR_BAD_ARGUMENT,
574
		     N_("you need to load the kernel first"));
575 576
}

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
static grub_err_t
check_password_deny (const char *user __attribute__ ((unused)),
		     const char *entered  __attribute__ ((unused)),
		     void *password __attribute__ ((unused)))
{
  return GRUB_ACCESS_DENIED;
}

#define MD5_HASHLEN 16

struct legacy_md5_password
{
  grub_uint8_t *salt;
  int saltlen;
  grub_uint8_t hash[MD5_HASHLEN];
};

static int
check_password_md5_real (const char *entered,
			 struct legacy_md5_password *pw)
{
598
  grub_size_t enteredlen = grub_strlen (entered);
599 600
  unsigned char alt_result[MD5_HASHLEN];
  unsigned char *digest;
601
  grub_uint8_t *ctx;
602
  grub_size_t i;
603 604 605 606 607
  int ret;

  ctx = grub_zalloc (GRUB_MD_MD5->contextsize);
  if (!ctx)
    return 0;
608 609 610 611 612 613 614

  GRUB_MD_MD5->init (ctx);
  GRUB_MD_MD5->write (ctx, entered, enteredlen);
  GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
  GRUB_MD_MD5->write (ctx, entered, enteredlen);
  digest = GRUB_MD_MD5->read (ctx);
  GRUB_MD_MD5->final (ctx);
615
  grub_memcpy (alt_result, digest, MD5_HASHLEN);
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
  
  GRUB_MD_MD5->init (ctx);
  GRUB_MD_MD5->write (ctx, entered, enteredlen);
  GRUB_MD_MD5->write (ctx, pw->salt, pw->saltlen); /* include the $1$ header */
  for (i = enteredlen; i > 16; i -= 16)
    GRUB_MD_MD5->write (ctx, alt_result, 16);
  GRUB_MD_MD5->write (ctx, alt_result, i);

  for (i = enteredlen; i > 0; i >>= 1)
    GRUB_MD_MD5->write (ctx, entered + ((i & 1) ? enteredlen : 0), 1);
  digest = GRUB_MD_MD5->read (ctx);
  GRUB_MD_MD5->final (ctx);

  for (i = 0; i < 1000; i++)
    {
631
      grub_memcpy (alt_result, digest, 16);
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652

      GRUB_MD_MD5->init (ctx);
      if ((i & 1) != 0)
	GRUB_MD_MD5->write (ctx, entered, enteredlen);
      else
	GRUB_MD_MD5->write (ctx, alt_result, 16);
      
      if (i % 3 != 0)
	GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);

      if (i % 7 != 0)
	GRUB_MD_MD5->write (ctx, entered, enteredlen);

      if ((i & 1) != 0)
	GRUB_MD_MD5->write (ctx, alt_result, 16);
      else
	GRUB_MD_MD5->write (ctx, entered, enteredlen);
      digest = GRUB_MD_MD5->read (ctx);
      GRUB_MD_MD5->final (ctx);
    }

653 654 655
  ret = (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0);
  grub_free (ctx);
  return ret;
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
}

static grub_err_t
check_password_md5 (const char *user,
		    const char *entered,
		    void *password)
{
  if (!check_password_md5_real (entered, password))
    return GRUB_ACCESS_DENIED;

  grub_auth_authenticate (user);

  return GRUB_ERR_NONE;
}

static inline int
ib64t (char c)
{
  if (c == '.')
    return 0;
  if (c == '/')
    return 1;
  if (c >= '0' && c <= '9')
    return c - '0' + 2;
  if (c >= 'A' && c <= 'Z')
    return c - 'A' + 12;
  if (c >= 'a' && c <= 'z')
    return c - 'a' + 38;
  return -1;
}

687 688
static struct legacy_md5_password *
parse_legacy_md5 (int argc, char **args)
689 690 691 692
{
  const char *salt, *saltend;
  struct legacy_md5_password *pw = NULL;
  int i;
693
  const char *p;
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745

  if (grub_memcmp (args[0], "--md5", sizeof ("--md5")) != 0)
    goto fail;
  if (argc == 1)
    goto fail;
  if (grub_strlen(args[1]) <= 3)
    goto fail;
  salt = args[1];
  saltend = grub_strchr (salt + 3, '$');
  if (!saltend)
    goto fail;
  pw = grub_malloc (sizeof (*pw));
  if (!pw)
    goto fail;

  p = saltend + 1;
  for (i = 0; i < 5; i++)
    {
      int n;
      grub_uint32_t w = 0;

      for (n = 0; n < 4; n++)
	{
	  int ww = ib64t(*p++);
	  if (ww == -1)
	    goto fail;
	  w |= ww << (n * 6);
	}
      pw->hash[i == 4 ? 5 : 12+i] = w & 0xff;
      pw->hash[6+i] = (w >> 8) & 0xff;
      pw->hash[i] = (w >> 16) & 0xff;
    }
  {
    int n;
    grub_uint32_t w = 0;
    for (n = 0; n < 2; n++)
      {
	int ww = ib64t(*p++);
	if (ww == -1)
	  goto fail;
	w |= ww << (6 * n);
      }
    if (w >= 0x100)
      goto fail;
    pw->hash[11] = w;
  }

  pw->saltlen = saltend - salt;
  pw->salt = (grub_uint8_t *) grub_strndup (salt, pw->saltlen);
  if (!pw->salt)
    goto fail;

746
  return pw;
747 748 749

 fail:
  grub_free (pw);
750 751 752 753 754 755 756 757 758 759
  return NULL;
}

static grub_err_t
grub_cmd_legacy_password (struct grub_command *mycmd __attribute__ ((unused)),
			  int argc, char **args)
{
  struct legacy_md5_password *pw = NULL;

  if (argc == 0)
760
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
  if (args[0][0] != '-' || args[0][1] != '-')
    return grub_normal_set_password ("legacy", args[0]);

  pw = parse_legacy_md5 (argc, args);

  if (pw)
    return grub_auth_register_authentication ("legacy", check_password_md5, pw);
  else
    /* This is to imitate minor difference between grub-legacy in GRUB2.
       If 2 password commands are executed in a row and second one fails
       on GRUB2 the password of first one is used, whereas in grub-legacy
       authenthication is denied. In case of no password command was executed
       early both versions deny any access.  */
    return grub_auth_register_authentication ("legacy", check_password_deny,
					      NULL);
}

778 779 780
int
grub_legacy_check_md5_password (int argc, char **args,
				char *entered)
781 782
{
  struct legacy_md5_password *pw = NULL;
783
  int ret;
784 785 786 787 788 789 790 791

  if (args[0][0] != '-' || args[0][1] != '-')
    {
      char correct[GRUB_AUTH_MAX_PASSLEN];

      grub_memset (correct, 0, sizeof (correct));
      grub_strncpy (correct, args[0], sizeof (correct));

792
      return grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) == 0;
793 794 795 796 797
    }

  pw = parse_legacy_md5 (argc, args);

  if (!pw)
798 799
    return 0;

800 801 802
  ret = check_password_md5_real (entered, pw);
  grub_free (pw);
  return ret;
803 804 805 806 807 808 809 810 811 812 813 814
}

static grub_err_t
grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)),
				int argc, char **args)
{
  char entered[GRUB_AUTH_MAX_PASSLEN];

  if (argc == 0)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  grub_puts_ (N_("Enter password: "));
  if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
815 816
    return GRUB_ACCESS_DENIED;

817 818
  if (!grub_legacy_check_md5_password (argc, args,
				       entered))
819 820 821
    return GRUB_ACCESS_DENIED;

  return GRUB_ERR_NONE;
822 823
}

824 825 826 827
static grub_command_t cmd_source, cmd_configfile;
static grub_command_t cmd_source_extract, cmd_configfile_extract;
static grub_command_t cmd_kernel, cmd_initrd, cmd_initrdnounzip;
static grub_command_t cmd_password, cmd_check_password;
828 829 830

GRUB_MOD_INIT(legacycfg)
{
831 832 833 834
  cmd_source
    = grub_register_command ("legacy_source",
			     grub_cmd_legacy_source,
			     N_("FILE"),
835 836
			     /* TRANSLATORS: "legacy config" means
				"config as used by grub-legacy".  */
837 838 839 840 841 842 843 844 845 846
			     N_("Parse legacy config in same context"));
  cmd_configfile
    = grub_register_command ("legacy_configfile",
			     grub_cmd_legacy_source,
			     N_("FILE"),
			     N_("Parse legacy config in new context"));
  cmd_source_extract
    = grub_register_command ("extract_legacy_entries_source",
			     grub_cmd_legacy_source,
			     N_("FILE"),
847
			     N_("Parse legacy config in same context taking only menu entries"));
848 849 850 851
  cmd_configfile_extract
    = grub_register_command ("extract_legacy_entries_configfile",
			     grub_cmd_legacy_source,
			     N_("FILE"),
852
			     N_("Parse legacy config in new context taking only menu entries"));
853

854 855 856
  cmd_kernel = grub_register_command ("legacy_kernel",
				      grub_cmd_legacy_kernel,
				      N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
857
				      N_("Simulate grub-legacy `kernel' command"));
858 859 860 861

  cmd_initrd = grub_register_command ("legacy_initrd",
				      grub_cmd_legacy_initrd,
				      N_("FILE [ARG ...]"),
862
				      N_("Simulate grub-legacy `initrd' command"));
863 864 865
  cmd_initrdnounzip = grub_register_command ("legacy_initrd_nounzip",
					     grub_cmd_legacy_initrdnounzip,
					     N_("FILE [ARG ...]"),
866
					     N_("Simulate grub-legacy `modulenounzip' command"));
867

868 869 870
  cmd_password = grub_register_command ("legacy_password",
					grub_cmd_legacy_password,
					N_("[--md5] PASSWD [FILE]"),
871
					N_("Simulate grub-legacy `password' command"));
872 873 874 875

  cmd_check_password = grub_register_command ("legacy_check_password",
					      grub_cmd_legacy_check_password,
					      N_("[--md5] PASSWD [FILE]"),
876
					      N_("Simulate grub-legacy `password' command in menu entry mode"));
877

878 879 880 881 882 883
}

GRUB_MOD_FINI(legacycfg)
{
  grub_unregister_command (cmd_source);
  grub_unregister_command (cmd_configfile);
884 885 886
  grub_unregister_command (cmd_source_extract);
  grub_unregister_command (cmd_configfile_extract);

887 888
  grub_unregister_command (cmd_kernel);
  grub_unregister_command (cmd_initrd);
889
  grub_unregister_command (cmd_initrdnounzip);
890

891
  grub_unregister_command (cmd_password);
892
  grub_unregister_command (cmd_check_password);
893
}