--- util-linux-2.12/mount/sundries.c-no-keygen-prog	2003-07-13 20:51:39.000000000 -0400
+++ util-linux-2.12/mount/sundries.c	2003-09-16 23:59:45.000000000 -0400
@@ -12,6 +12,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <mntent.h>		/* for MNTTYPE_SWAP */
+#include <sys/types.h>
+#include <sys/wait.h>
 #include "fstab.h"
 #include "sundries.h"
 #include "realpath.h"
@@ -285,3 +287,99 @@
      free(canonical);
      return xstrdup(path);
 }
+
+static volatile pid_t keygen_pid = -1;
+
+/* Handle a SIGCHLD -- wait for the child process */
+static void
+child_handler (int i) {
+	int status;
+	if (keygen_pid != -1 && wait(&status) == keygen_pid) {
+		keygen_pid = -1;
+		if (WEXITSTATUS(status) != 0)
+			exit(WEXITSTATUS(status));
+	}
+}
+
+/* Make sure we clean up after the child */
+static void
+child_cleanup (void) {
+	/* "Clean up" means wait. So we let child_handler do all the work */
+	while (keygen_pid != -1)
+		sleep(1);
+}
+
+/* Split a string into pieces, using delim as the delimiter.		*
+ * Returns the number of pieces.					*/
+static int
+split_args (char *args[], const char *str, const char *delim, int nargs) {
+	int i=0;
+	char *s = xstrdup(str);
+	args[0] = strtok(s, delim);
+	if (args[0] == NULL)
+		return 0;
+
+	while (++i < nargs) {
+		if ((args[i] = strtok(NULL, delim)) == NULL)
+			break;
+	}
+
+	return i;
+}
+
+#define KEYGEN_MAX_ARGS 64	/* more than anyone will need, right? */
+
+/* Call an external program to give us the encryption key for an	*
+ * encrypted device. We split the string s into a command and args on	*
+ * semicolons ('cuz you can't put spaces in the fs_mntopts field), then	*
+ * add some specific args (eg. the looped file or device, the		*
+ * encryption method used; check the caller to see the actual list).	*
+ * Returns a file descriptor from which we read the key.		*/
+int
+use_keygen_prog (const char *s, const char *addl_args[], int naddl_args) {
+	int fd[2]; 
+	struct sigaction sa;
+	sa.sa_handler = child_handler;
+	sa.sa_flags = SA_NOCLDSTOP;
+
+	if (pipe(fd) == -1) {
+		perror("pipe");
+		exit(EX_SYSERR);
+	}
+	if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+		perror("sigaction");
+		exit(EX_SYSERR);
+	}
+	if ((keygen_pid = fork()) == -1) {
+		perror("fork");
+		exit(EX_SYSERR);
+	} else if (keygen_pid) {	/* parent */
+		atexit(child_cleanup);
+		close(fd[1]);
+		return fd[0];
+	} else {		/* child */
+		char *args[KEYGEN_MAX_ARGS+1];
+		int i, n = split_args(args, s, ";", KEYGEN_MAX_ARGS - naddl_args);
+		if (!n) {
+			fprintf(stderr, _("Invalid keygen program, exiting\n"));
+			exit(EX_USAGE);
+		}
+		for(i=0; i < naddl_args; i++)
+			args[n+i] = (char *) addl_args[i];
+		args[n+naddl_args] = NULL;
+
+		close(fd[0]);
+		if (dup2(fd[1], STDOUT_FILENO) == -1) {
+			perror("dup2");
+			exit(EX_SYSERR);
+		}
+		setuid(getuid());	/* set euid to ruid */
+		if (execvp(args[0], args) == -1) {
+			perror(args[0]);
+			exit(EX_USAGE);
+		}
+	}
+
+	return 0; /* so gcc will shut up */
+}
+
--- util-linux-2.12/mount/sundries.h-no-keygen-prog	2002-10-31 20:00:50.000000000 -0500
+++ util-linux-2.12/mount/sundries.h	2003-09-16 23:59:45.000000000 -0400
@@ -25,6 +25,7 @@
 void error (const char *fmt, ...);
 int matching_type (const char *type, const char *types);
 int matching_opts (const char *options, const char *test_opts);
+int use_keygen_prog (const char *s, const char *addl_args[], int naddl_args);
 void *xmalloc (size_t size);
 char *xstrdup (const char *s);
 char *xstrndup (const char *s, int n);
--- util-linux-2.12/mount/mount.c-no-keygen-prog	2003-07-15 17:38:48.000000000 -0400
+++ util-linux-2.12/mount/mount.c	2003-09-16 23:59:45.000000000 -0400
@@ -195,7 +195,7 @@
 };
 
 static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
-  *opt_speed;
+  *opt_keygen, *opt_speed;
 
 static struct string_opt_map {
   char *tag;
@@ -206,6 +206,7 @@
   { "vfs=",	1, &opt_vfstype },
   { "offset=",	0, &opt_offset },
   { "encryption=", 0, &opt_encryption },
+  { "keygen=", 0, &opt_keygen },
   { "speed=", 0, &opt_speed },
   { NULL, 0, NULL }
 };
@@ -586,7 +587,7 @@
       *type = opt_vfstype;
   }
 
-  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption);
+  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption || opt_keygen);
   *loopfile = *spec;
 
   if (*loop) {
@@ -596,6 +597,11 @@
 	printf(_("mount: skipping the setup of a loop device\n"));
     } else {
       int loopro = (*flags & MS_RDONLY);
+      /* Extra args to the keygen program. Right now there are 2:	*
+       *   - the looped file						*
+       *   - the encryption type used					*/
+      char *keygen_args[] = {*loopfile, opt_encryption};
+      const int _n_keygen_args = 2;
 
       if (!*loopdev || !**loopdev)
 	*loopdev = find_unused_loop_device();
@@ -604,6 +610,8 @@
       if (verbose)
 	printf(_("mount: going to use the loop device %s\n"), *loopdev);
       offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0;
+      if (opt_keygen)
+	pfd = use_keygen_prog(opt_keygen, keygen_args, _n_keygen_args);
       if (set_loop(*loopdev, *loopfile, offset,
 		   opt_encryption, pfd, &loopro)) {
 	if (verbose)
--- util-linux-2.12/mount/mount.8-no-keygen-prog	2003-07-13 20:59:11.000000000 -0400
+++ util-linux-2.12/mount/mount.8	2003-09-16 23:59:45.000000000 -0400
@@ -1696,6 +1696,11 @@
 .BR loop ", " offset " and " encryption ,
 that are really options to
 .BR losetup (8).
+You can also use the
+.BR keygen
+option to have mount call an external program from, which it will read the
+encryption key. Arguments to this program can be given, separated by semicolons.
+
 If no explicit loop device is mentioned
 (but just an option `\fB\-o loop\fP' is given), then
 .B mount
--- util-linux-2.12/mount/lomount.c-no-keygen-prog	2003-09-16 23:48:26.000000000 -0400
+++ util-linux-2.12/mount/lomount.c	2003-09-17 00:02:37.000000000 -0400
@@ -10,7 +10,6 @@
  * 2000-09-24 Marc Mutz <Marc@Mutz.com>
  * - added -p option to pass passphrases via fd's to losetup/mount.
  *   Used for encryption in non-interactive environments.
- *   The idea behind xgetpass() is stolen from GnuPG, v.1.0.3.
  */
 
 #define LOOPMAJOR	7
@@ -33,6 +32,7 @@
 #include <sys/mman.h>
 #include <sys/sysmacros.h>
 #include <regex.h>
+#include <signal.h>
 
 #include "loop.h"
 #include "lomount.h"
@@ -201,45 +201,6 @@
 	return 0;
 }
 
-/*
- * A function to read the passphrase either from the terminal or from
- * an open file descriptor.
- */
-static char *
-xgetpass(int pfd, const char *prompt) {
-	char *pass;
-	int buflen, i;
-
-        if (pfd < 0) /* terminal */
-		return getpass(prompt);
-
-	pass = NULL;
-	buflen = 0;
-	for (i=0; ; i++) {
-		if (i >= buflen-1) {
-				/* we're running out of space in the buffer.
-				 * Make it bigger: */
-			char *tmppass = pass;
-			buflen += 128;
-			pass = realloc(tmppass, buflen);
-			if (pass == NULL) {
-				/* realloc failed. Stop reading. */
-				error("Out of memory while reading passphrase");
-				pass = tmppass; /* the old buffer hasn't changed */
-				break;
-			}
-		}
-		if (read(pfd, pass+i, 1) != 1 || pass[i] == '\n')
-			break;
-	}
-	if (pass == NULL)
-		return "";
-	else {
-		pass[i] = 0;
-		return pass;
-	}
-}
-
 static int
 digits_only(const char *s) {
 	while (*s)
@@ -339,8 +300,25 @@
 			strlen(loopinfo64.lo_encrypt_key);
 		break;
 	default:
-		pass = xgetpass(pfd, _("Password: "));
-		xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
+		if (pfd == -1) {
+			pass = getpass(_("Password: "));
+			xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
+		} else {
+			/* If we're reading from an extenral program,	*
+			 * odds are good that a SIGCHLD will interrupt	*
+			 * this read(), and ruin our whole day. So we	*
+			 * must block it.				*/
+			sigset_t ss, oss;
+			sigemptyset(&ss);
+			sigaddset(&ss, SIGCHLD);
+			sigprocmask(SIG_BLOCK, &ss, &oss);
+			if (read(pfd, loopinfo64.lo_encrypt_key,
+				 LO_KEY_SIZE) == -1) {
+				perror("read");
+				fprintf(stderr, _("Error reading encryption key, exiting\n"));
+			}
+			sigprocmask(SIG_SETMASK, &oss, NULL);
+		}
 	}
 
 	if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
