diff -urN yaboot.orig/Makefile yaboot/Makefile
--- yaboot.orig/Makefile	Sun Jun 24 01:07:04 2001
+++ yaboot/Makefile	Sat Jul 28 03:08:37 2001
@@ -19,6 +19,8 @@
 CONFIG_SET_COLORMAP = y
 # Enable splash screen
 CONFIG_SPLASH_SCREEN = y
+# Enable md5 passwords
+USE_MD5_PASSWORDS = y
 
 # We use fixed addresses to avoid overlap when relocating
 # and other trouble with initrd
@@ -61,6 +63,10 @@
 CFLAGS += -DCONFIG_SPLASH_SCREEN
 endif
 
+ifeq ($(USE_MD5_PASSWORDS),y)
+CFLAGS += -DUSE_MD5_PASSWORDS
+endif
+
 # Link flags
 #
 LFLAGS = -Ttext $(TEXTADDR) -Bstatic 
@@ -80,12 +86,16 @@
 OBJS = crt0.o yaboot.o cache.o prom.o file.o partition.o fs.o cfg.o \
 	setjmp.o cmdline.o fs_of.o fs_ext2.o fs_iso.o iso_util.o \
 	lib/nosys.o lib/string.o lib/strtol.o \
-	lib/vsprintf.o lib/ctype.o lib/malloc.o
+	lib/vsprintf.o lib/ctype.o lib/malloc.o lib/strstr.o
 
 ifeq ($(CONFIG_SPLASH_SCREEN),y)
 OBJS += gui/effects.o gui/colormap.o gui/video.o gui/pcx.o
 endif
 
+ifeq ($(USE_MD5_PASSWORDS),y)
+OBJS += md5.o
+endif
+
 CC = $(CROSS)gcc
 LD = $(CROSS)ld
 AS = $(CROSS)as
@@ -106,7 +116,7 @@
 	./util/elfextract yaboot yaboot.b
 
 clean:
-	rm -f yaboot util/addnote utils/elfextract $(OBJS)
+	rm -f yaboot util/addnote util/elfextract $(OBJS)
 	find . -name '*~' | xargs rm -f
 	find . -name '#*' | xargs rm -f
 	find . -name .AppleDouble | xargs rm -rf
@@ -116,7 +126,7 @@
 
 elfextract: util/elfextract.c
 	$(HOSTCC) $(HOSTCFLAGS) -o util/elfextract util/elfextract.c
-	
+
 %.o: %.c
 	$(CC) $(CFLAGS) -c -o $@ $<
 
diff -urN yaboot.orig/cmdline.c yaboot/cmdline.c
--- yaboot.orig/cmdline.c	Sun Jun 24 01:07:04 2001
+++ yaboot/cmdline.c	Sun Jun 24 01:09:11 2001
@@ -79,4 +79,4 @@
 	  }
      }
      buff[x] = 0;
-}
\ No newline at end of file
+}
diff -urN yaboot.orig/include/md5.h yaboot/include/md5.h
--- yaboot.orig/include/md5.h	Wed Dec 31 14:00:00 1969
+++ yaboot/include/md5.h	Sat Jul 28 03:03:54 2001
@@ -0,0 +1,30 @@
+/* md5.h - an implementation of the MD5 algorithm and MD5 crypt */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* If CHECK is true, check a password for correctness. Returns 0
+   if password was correct, and a value != 0 for error, similarly
+   to strcmp.
+   If CHECK is false, crypt KEY and save the result in CRYPTED.
+   CRYPTED must have a salt.  */
+extern int md5_password (const char *key, char *crypted, int check);
+
+/* For convenience.  */
+#define check_md5_password(key,crypted)	md5_password((key), (crypted), 1)
+#define make_md5_password(key,crypted)	md5_password((key), (crypted), 0)
diff -urN yaboot.orig/lib/strstr.c yaboot/lib/strstr.c
--- yaboot.orig/lib/strstr.c	Wed Dec 31 14:00:00 1969
+++ yaboot/lib/strstr.c	Sat Jul 28 03:03:57 2001
@@ -0,0 +1,119 @@
+/* Return the offset of one string within another.
+   Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/*
+ * My personal strstr() implementation that beats most other algorithms.
+ * Until someone tells me otherwise, I assume that this is the
+ * fastest implementation of strstr() in C.
+ * I deliberately chose not to comment it.  You should have at least
+ * as much fun trying to understand it, as I had to write it :-).
+ *
+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de	*/
+
+#include <string.h>
+
+typedef unsigned chartype;
+
+#undef strstr
+
+char *
+strstr (phaystack, pneedle)
+     const char *phaystack;
+     const char *pneedle;
+{
+  register const unsigned char *haystack, *needle;
+  register chartype b, c;
+
+  haystack = (const unsigned char *) phaystack;
+  needle = (const unsigned char *) pneedle;
+
+  b = *needle;
+  if (b != '\0')
+    {
+      haystack--;				/* possible ANSI violation */
+      do
+	{
+	  c = *++haystack;
+	  if (c == '\0')
+	    goto ret0;
+	}
+      while (c != b);
+
+      c = *++needle;
+      if (c == '\0')
+	goto foundneedle;
+      ++needle;
+      goto jin;
+
+      for (;;)
+        {
+          register chartype a;
+	  register const unsigned char *rhaystack, *rneedle;
+
+	  do
+	    {
+	      a = *++haystack;
+	      if (a == '\0')
+		goto ret0;
+	      if (a == b)
+		break;
+	      a = *++haystack;
+	      if (a == '\0')
+		goto ret0;
+shloop:	    }
+          while (a != b);
+
+jin:	  a = *++haystack;
+	  if (a == '\0')
+	    goto ret0;
+
+	  if (a != c)
+	    goto shloop;
+
+	  rhaystack = haystack-- + 1;
+	  rneedle = needle;
+	  a = *rneedle;
+
+	  if (*rhaystack == a)
+	    do
+	      {
+		if (a == '\0')
+		  goto foundneedle;
+		++rhaystack;
+		a = *++needle;
+		if (*rhaystack != a)
+		  break;
+		if (a == '\0')
+		  goto foundneedle;
+		++rhaystack;
+		a = *++needle;
+	      }
+	    while (*rhaystack == a);
+
+	  needle = rneedle;		/* took the register-poor approach */
+
+	  if (a == '\0')
+	    break;
+        }
+    }
+foundneedle:
+  return (char*) haystack;
+ret0:
+  return 0;
+}
diff -urN yaboot.orig/md5.c yaboot/md5.c
--- yaboot.orig/md5.c	Wed Dec 31 14:00:00 1969
+++ yaboot/md5.c	Sat Jul 28 03:03:48 2001
@@ -0,0 +1,380 @@
+/* md5.c - an implementation of the MD5 algorithm and MD5 crypt */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000  Free Software Foundation, Inc.
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* See RFC 1321 for a description of the MD5 algorithm.
+ */
+
+#include "string.h"
+#include "md5.h"
+
+#ifdef TEST
+# include <stdio.h>
+# define USE_MD5_PASSWORDS
+# define USE_MD5
+#endif
+
+#ifdef USE_MD5_PASSWORDS
+# define USE_MD5
+#endif
+
+#ifdef USE_MD5
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+        return (((x & 0x000000ffU) << 24) |
+                ((x & 0x0000ff00U) <<  8) |
+                ((x & 0x00ff0000U) >>  8) |
+                ((x & 0xff000000U) >> 24));
+}
+
+typedef unsigned int UINT4;
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n)))))
+
+static UINT4 initstate[4] =
+{
+  0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 
+};
+
+static char s1[4] = {  7, 12, 17, 22 };
+static char s2[4] = {  5,  9, 14, 20 };
+static char s3[4] = {  4, 11, 16, 23 };
+static char s4[4] = {  6, 10, 15, 21 };
+
+static UINT4 T[64] =
+{
+  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+  0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+  0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+  0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+  0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+  0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+  0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+  0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+  0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+  0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+static const char *b64t =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static UINT4 state[4];
+static unsigned int length;
+static unsigned char buffer[64];
+
+static void
+md5_transform (const unsigned char block[64])
+{
+  int i, j;
+  UINT4 a,b,c,d,tmp;
+  const UINT4 *x = (UINT4 *) block;
+
+  a = state[0];
+  b = state[1];
+  c = state[2];
+  d = state[3];
+
+  /* Round 1 */
+  for (i = 0; i < 16; i++)
+    {
+      tmp = a + F (b, c, d) + le32_to_cpu (x[i]) + T[i];
+      tmp = ROTATE_LEFT (tmp, s1[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+  /* Round 2 */
+  for (i = 0, j = 1; i < 16; i++, j += 5)
+    {
+      tmp = a + G (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+16];
+      tmp = ROTATE_LEFT (tmp, s2[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+  /* Round 3 */
+  for (i = 0, j = 5; i < 16; i++, j += 3)
+    {
+      tmp = a + H (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+32];
+      tmp = ROTATE_LEFT (tmp, s3[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+  /* Round 4 */
+  for (i = 0, j = 0; i < 16; i++, j += 7)
+    {
+      tmp = a + I (b, c, d) + le32_to_cpu (x[j & 15]) + T[i+48];
+      tmp = ROTATE_LEFT (tmp, s4[i & 3]);
+      tmp += b;
+      a = d; d = c; c = b; b = tmp;
+    }
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+}
+
+static void
+md5_init(void)
+{
+  memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+  length = 0;
+}
+
+static void
+md5_update (const char *input, int inputlen)
+{
+  int buflen = length & 63;
+  length += inputlen;
+  if (buflen + inputlen < 64) 
+    {
+      memcpy (buffer + buflen, input, inputlen);
+      buflen += inputlen;
+      return;
+    }
+  
+  memcpy (buffer + buflen, input, 64 - buflen);
+  md5_transform (buffer);
+  input += 64 - buflen;
+  inputlen -= 64 - buflen;
+  while (inputlen >= 64)
+    {
+      md5_transform (input);
+      input += 64;
+      inputlen -= 64;
+    }
+  memcpy (buffer, input, inputlen);
+  buflen = inputlen;
+}
+
+static unsigned char *
+md5_final()
+{
+  int i, buflen = length & 63;
+
+  buffer[buflen++] = 0x80;
+  memset (buffer+buflen, 0, 64 - buflen);
+  if (buflen > 56)
+    {
+      md5_transform (buffer);
+      memset (buffer, 0, 64);
+      buflen = 0;
+    }
+  
+  *(UINT4 *) (buffer + 56) = cpu_to_le32 (8 * length);
+  *(UINT4 *) (buffer + 60) = 0;
+  md5_transform (buffer);
+
+  for (i = 0; i < 4; i++)
+    state[i] = cpu_to_le32 (state[i]);
+  return (unsigned char *) state;
+}
+
+#ifdef USE_MD5_PASSWORDS
+/* If CHECK is true, check a password for correctness. Returns 0
+   if password was correct, and a value != 0 for error, similarly
+   to strcmp.
+   If CHECK is false, crypt KEY and save the result in CRYPTED.
+   CRYPTED must have a salt.  */
+int
+md5_password (const char *key, char *crypted, int check)
+{
+  int keylen = strlen (key);
+  char *salt = crypted + 3; /* skip $1$ header */
+  char *p; 
+  int saltlen;
+  int i, n;
+  unsigned char alt_result[16];
+  unsigned char *digest;
+
+  if (check)
+    saltlen = strstr (salt, "$") - salt;
+  else
+    {
+      char *end = strstr (salt, "$");
+      if (end && end - salt < 8)
+	saltlen = end - salt;
+      else
+	saltlen = 8;
+
+      salt[saltlen] = '$';
+    }
+  
+  md5_init ();
+  md5_update (key, keylen);
+  md5_update (salt, saltlen);
+  md5_update (key, keylen);
+  digest = md5_final ();
+  memcpy (alt_result, digest, 16);
+  
+  memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+  length = 0;
+  md5_update (key, keylen);
+  md5_update (crypted, 3 + saltlen); /* include the $1$ header */
+  for (i = keylen; i > 16; i -= 16)
+    md5_update (alt_result, 16);
+  md5_update (alt_result, i);
+
+  for (i = keylen; i > 0; i >>= 1)
+    md5_update (key + ((i & 1) ? keylen : 0), 1);
+  digest = md5_final ();
+
+  for (i = 0; i < 1000; i++)
+    {
+      memcpy (alt_result, digest, 16);
+
+      memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+      length = 0;
+      if ((i & 1) != 0)
+	md5_update (key, keylen);
+      else
+	md5_update (alt_result, 16);
+      
+      if (i % 3 != 0)
+	md5_update (salt, saltlen);
+
+      if (i % 7 != 0)
+	md5_update (key, keylen);
+
+      if ((i & 1) != 0)
+	md5_update (alt_result, 16);
+      else
+	md5_update (key, keylen);
+      digest = md5_final ();
+    }
+
+  p = salt + saltlen + 1;
+  for (i = 0; i < 5; i++)
+    {
+      unsigned int w = 
+	digest[i == 4 ? 5 : 12+i] | (digest[6+i] << 8) | (digest[i] << 16);
+      for (n = 4; n-- > 0;)
+	{
+	  if (check)
+	    {
+	      if (*p++ != b64t[w & 0x3f])
+		return 1;
+	    }
+	  else
+	    {
+	      *p++ = b64t[w & 0x3f];
+	    }
+	  
+	  w >>= 6;
+	}
+    }
+  {
+    unsigned int w = digest[11];
+    for (n = 2; n-- > 0;)
+      {
+	if (check)
+	  {
+	    if (*p++ != b64t[w & 0x3f])
+	      return 1;
+	  }
+	else
+	  {
+	    *p++ = b64t[w & 0x3f];
+	  }
+	
+	w >>= 6;
+      }
+  }
+
+  if (! check)
+    *p = '\0';
+  
+  return *p;
+}
+#endif
+
+#ifdef TEST
+static char *
+md5 (const char *input) 
+{
+  memcpy ((char *) state, (char *) initstate, sizeof (initstate));
+  length = 0;
+  md5_update (input, strlen (input));
+  return md5_final ();
+}
+
+static void
+test (char *buffer, char *expected) 
+{
+  char result[16 * 3 +1];
+  unsigned char* digest = md5 (buffer);
+  int i;
+
+  for (i=0; i < 16; i++)
+    sprintf (result+2*i, "%02x", digest[i]);
+
+  if (strcmp (result, expected))
+    printf ("MD5(%s) failed: %s\n", buffer, result);
+  else
+    printf ("MD5(%s) OK\n", buffer);
+}
+
+int
+main (void)
+{
+  test ("", "d41d8cd98f00b204e9800998ecf8427e");
+  test ("a", "0cc175b9c0f1b6a831c399e269772661");
+  test ("abc", "900150983cd24fb0d6963f7d28e17f72");
+  test ("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+  test ("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	"d174ab98d277d9f5a5611c2c9f419d9f");
+  test ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	"57edf4a22be3c955ac49da2e2107b67a");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz3456",
+	"6831fa90115bb9a54fbcd4f9fee0b5c4");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz345",
+	"bc40505cc94a43b7ff3e2ac027325233");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567",
+	"fa94b73a6f072a0239b52acacfbcf9fa");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz345678901234",
+	"bd201eae17f29568927414fa326f1267");
+  test ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz34567890123",
+	"80063db1e6b70a2e91eac903f0e46b85");
+
+  if (check_md5_password ("Hello world!",
+			  "$1$saltstri$YMyguxXMBpd2TEZ.vS/3q1"))
+    printf ("Password differs\n");
+  else
+    printf ("Password OK\n");
+  return 0;
+}
+#endif
+
+#endif
diff -urN yaboot.orig/util/addnote.c yaboot/util/addnote.c
--- yaboot.orig/util/addnote.c	Sun Jun 24 01:07:05 2001
+++ yaboot/util/addnote.c	Sun Jun 24 16:25:11 2001
@@ -158,6 +158,6 @@
 
  nospace:
 	fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
-		av[0]);
+		av[1]);
 	exit(1);
 }
diff -urN yaboot.orig/yaboot.c yaboot/yaboot.c
--- yaboot.orig/yaboot.c	Sun Jun 24 01:07:04 2001
+++ yaboot/yaboot.c	Sat Jul 28 03:03:48 2001
@@ -53,6 +53,10 @@
 #include "gui.h"
 #endif /* CONFIG_SPLASH_SCREEN */
 
+#ifdef USE_MD5_PASSWORDS
+#include "md5.h"
+#endif /* USE_MD5_PASSWORDS */
+
 /* align addr on a size boundry - adjust address up if needed -- Cort */
 #define _ALIGN(addr,size)	(((addr)+size-1)&(~(size-1)))
 
@@ -160,7 +164,7 @@
 	int result;
 	void* malloc_base;
 	prom_handle root;
-	
+
  	/* OF seems to do it, but I'm not very confident */
   	memset(&__bss_start, 0, &_end - &__bss_start);
   	
@@ -493,8 +497,17 @@
 	 passwdbuff[0] = 0;
 	 cmdedit ((void (*)(void)) 0, 1);
 	 prom_printf ("\n");
+#ifdef USE_MD5_PASSWORDS
+	 if (!strncmp (password, "$1$", 3)) {
+	    if (!check_md5_password(passwdbuff, password))
+	       return;
+	 } 
+	 else if (!strcmp (password, passwdbuff))
+	    return;
+#else
 	 if (!strcmp (password, passwdbuff))
 	    return;
+#endif
 	 if (i < 2)
 	    prom_printf ("Password incorrect. Please try again...");
     }
@@ -664,9 +677,9 @@
 	 prom_interpret(imagename+1);
 	 return 0;
     }
-    
+
     strncpy(imagepath, imagename, 1024);
-    
+
     if (!label && password)
 	 check_password ("To boot a custom image you must enter the p");
 
