Duh...
--- lomount.c-no-reader-prog 2003-08-02 19:25:01.000000000 -0400 +++ lomount.c 2003-08-05 21:31:18.000000000 -0400 @@ -32,7 +32,9 @@ #include <sys/stat.h> #include <sys/mman.h> #include <sys/sysmacros.h> +#include <sys/wait.h> #include <regex.h> +#include <signal.h> #include "loop.h" #include "lomount.h" @@ -42,6 +44,67 @@ extern int verbose; extern char *xstrdup (const char *s); /* not: #include "sundries.h" */ extern void error (const char *fmt, ...); /* idem */ +#define EX_USAGE 1 /* idem */ +#define EX_SYSERR 2 /* idem */ + +static volatile pid_t reader_pid = -1; + +static void +child_handler (int i) { + int status; + if (reader_pid != -1 && wait(&status) == reader_pid) { + reader_pid = -1; + if (WEXITSTATUS(status) != 0) + exit(WEXITSTATUS(status)); + } +} + +static void +child_cleanup (void) { + /* we are too lazy to clean up; child_handler will do it for us * + * if we wait */ + while (reader_pid != -1) + wait(NULL); +} + +int +use_reader_prog (const char *s) { + int fd[2]; + struct sigaction sa = { + .sa_handler = child_handler, + .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 ((reader_pid = fork()) == -1) { + perror("fork"); + exit(EX_SYSERR); + } else if (reader_pid) { /* parent */ + atexit(child_cleanup); + close(fd[1]); + return fd[0]; + } else { /* child */ + close(fd[0]); + if (dup2(fd[1], STDOUT_FILENO) == -1) { + perror("dup2"); + exit(EX_SYSERR); + } + setuid(getuid()); /* set euid to ruid */ + if (execlp(s, s, NULL) == -1) { + perror(s); + exit(EX_USAGE); + } + } + + return 0; /* so gcc will shut up */ +} #ifdef LOOP_SET_FD @@ -347,8 +410,25 @@ return -1; } /* FIXME we should be checking keysize against the min/max in /proc/crypto */ - pass = xgetpass(pfd, _("Password: ")); - xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); + + if (reader_pid == -1) { + pass = xgetpass(pfd, _("Password: ")); + xstrncpy(loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE); + } else { + /* 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); + } loopinfo64.lo_encrypt_key_size = keysize; } @@ -485,20 +565,21 @@ int main(int argc, char **argv) { - char *offset, *encryption, *passfd; + char *offset, *encryption, *passfd, *passreader; int delete, off, c; int res = 0; int ro = 0; int pfd = -1; + int opt_p = 0, opt_P = 0; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); delete = off = 0; - offset = encryption = passfd = NULL; + offset = encryption = passfd = passreader = NULL; progname = argv[0]; - while ((c = getopt(argc,argv,"de:E:o:p:v")) != -1) { + while ((c = getopt(argc,argv,"de:E:o:p:P:v")) != -1) { switch (c) { case 'd': delete = 1; @@ -511,8 +592,21 @@ offset = optarg; break; case 'p': + if (opt_p || opt_P) { + fprintf(stderr, _("mount: only one -p or -P allowed")); + exit(1); + } + opt_p = 1; passfd = optarg; break; + case 'P': + if (opt_p || opt_P) { + fprintf(stderr, _("mount: only one -p or -P allowed")); + exit(1); + } + opt_P = 1; + passreader = optarg; + break; case 'v': verbose = 1; break; @@ -534,6 +628,8 @@ usage(); if (passfd && sscanf(passfd,"%d",&pfd) != 1) usage(); + if (passreader) + pfd = use_reader_prog(passreader); res = set_loop(argv[optind], argv[optind+1], off, encryption, pfd, &ro); } --- losetup.8-no-reader-prog 2003-07-15 19:06:37.000000000 -0400 +++ losetup.8 2003-08-04 19:32:27.000000000 -0400 @@ -13,6 +13,9 @@ ] [ .B \-p .I pfd +] [ +.B \-P +.I reader ] .I loop_device file .br @@ -63,6 +66,12 @@ Read the passphrase from file descriptor with number .I num instead of from the terminal. +.IP "\fB\-P \fIprog\fP" +Use the external program +.I prog +to read and process the passphrase. This is useful if you want to +hash the passphrase for use as the encryption key (highly recommended). +NOTE that the options -p and -P cannot be used together. .SH RETURN VALUE .B losetup returns 0 on success, nonzero on failure. When --- mount.8-no-reader-prog 2003-08-04 00:26:04.000000000 -0400 +++ mount.8 2003-08-04 19:32:37.000000000 -0400 @@ -321,6 +321,13 @@ .I num instead of from the terminal. .TP +.BI \-P " prog" +In case of a loop mount with encryption, use the external program +.I prog +to read and process the passphrase. This is useful if you want to +hash the passphrase for use as the encryption key (highly recommended). +NOTE that the options -p and -P cannot be used together. +.TP .B \-s Tolerate sloppy mount options rather than failing. This will ignore mount options not supported by a filesystem type. Not all filesystems --- mount.c-no-reader-prog 2003-07-15 17:38:48.000000000 -0400 +++ mount.c 2003-08-04 19:23:11.000000000 -0400 @@ -1371,6 +1371,7 @@ { "options", 1, 0, 'o' }, { "test-opts", 1, 0, 'O' }, { "pass-fd", 1, 0, 'p' }, + { "pass-reader", 1, 0, 'P' }, { "types", 1, 0, 't' }, { "bind", 0, 0, 128 }, { "replace", 0, 0, 129 }, @@ -1421,7 +1422,7 @@ int main (int argc, char *argv[]) { - int c, result = 0, specseen; + int c, result = 0, specseen, opt_p = 0, opt_P = 0; char *options = NULL, *test_opts = NULL, *spec, *node; char *volumelabel = NULL; char *uuid = NULL; @@ -1447,7 +1448,7 @@ initproctitle(argc, argv); #endif - while ((c = getopt_long (argc, argv, "afFhilL:no:O:p:rsU:vVwt:", + while ((c = getopt_long (argc, argv, "afFhilL:no:O:p:P:rsU:vVwt:", longopts, NULL)) != -1) { switch (c) { case 'a': /* mount everything in fstab */ @@ -1487,8 +1488,17 @@ test_opts = xstrdup(optarg); break; case 'p': /* fd on which to read passwd */ + if (opt_p || opt_P) + die (EX_USAGE, _("mount: only one -p or -P allowed")); + opt_p = 1; set_pfd(optarg); break; + case 'P': /* program to read the passwd */ + if (opt_p || opt_P) + die (EX_USAGE, _("mount: only one -p or -P allowed")); + opt_P = 1; + pfd = use_reader_prog(optarg); + break; case 'r': /* mount readonly */ readonly = 1; readwrite = 0;