Hi Alex! I've implemented the Q> --pass-fd <num> alias Q> -p <num> option for both mount(8) and losetup(8). It expects a number (<num>) as argument and instructs mount/losetup to read the passphrase from file descriptor <num> instead of from the terminal. man pages have been updated, too. I have tested the xgetpass() routine both with a passphrase below 128 bytes and with the to-do-list I sent you some days ago with every newline removed, like Q> cat my-ikp-todo.txt | tr -d $'\n' | \ Q> losetup -e blowfish -p 0 /dev/loop0 crypto-file It works! Also, it teaches losetup long options, see losetup.8 for more. The patch applies to util-linux-2.10o, patched with the patch from 2.2.17.3. It will conflict with Gisle's and my previous stuff, no doubt. but AFAICS, only in the switch statement, where my patch is trivial: Just Q> getpass("...")->xgetpass(pfd,"...") everywhere. Please consider applying. if it makes too much noise when patching, I'll rediff against 17.4 when that is out. Marc PS: I have also fixed the loop vs. remount bug described in my todo list. A patch to Andries has been sent and he applied it. It is a two-liner in mount.c:try_mount_one() and thus will not collide with the kerneli-util-linux patches. But the difference in remount loop semantics is _great_. -- Marc Mutz <Marc@xxxxxxxx> http://marc.mutz.com/Encryption-HOWTO/ University of Bielefeld, Dep. of Mathematics / Dep. of Physics PGP-keyID's: 0xd46ce9ab (RSA), 0x7ae55b9e (DSS/DH)
diff -urN util-linux-2.10o.i3/mount/lomount.c util-linux-2.10o.i3-getpass/mount/lomount.c --- util-linux-2.10o.i3/mount/lomount.c Sun Sep 24 16:46:02 2000 +++ util-linux-2.10o.i3-getpass/mount/lomount.c Sun Sep 24 23:26:00 2000 @@ -6,6 +6,11 @@ * - added Native Language Support * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx> * - fixed strerr(errno) in gettext calls + * 2000-09-24 Marc Mutz <Marc@xxxxxxxx> + * - added long option names and the --pass-fd 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 (http://www.gnupg.org/). */ #define PROC_DEVICES "/proc/devices" @@ -176,9 +181,47 @@ 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) +{ + if (pfd < 0) /* terminal */ + return (getpass(prompt)); + else { /* file descriptor */ + char *pass = NULL; + int buflen, i; + + 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 _now_. */ + error("not enough 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; + } + } +} + int set_loop (const char *device, const char *file, int offset, - const char *encryption, int *loopro) { + const char *encryption, int pfd, int *loopro) { struct loop_info loopinfo; int fd, ffd, mode, i; char *pass; @@ -227,14 +270,16 @@ loopinfo.lo_encrypt_key_size = 0; break; case LO_CRYPT_XOR: - pass = getpass (_("Password: ")); + /* WARNING: xgetpass() can return massive amounts of data, + * not only 128 bytes like the original getpass(3) */ + pass = xgetpass (pfd,_("Password: ")); strncpy (loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE); loopinfo.lo_encrypt_key[LO_KEY_SIZE - 1] = 0; loopinfo.lo_encrypt_key_size = strlen(loopinfo.lo_encrypt_key); break; case LO_CRYPT_DES: printf(_("WARNING: Use of DES is depreciated.\n")); - pass = getpass (_("Password: ")); + pass = xgetpass (pfd,_("Password: ")); strncpy (loopinfo.lo_encrypt_key, pass, 8); loopinfo.lo_encrypt_key[8] = 0; loopinfo.lo_encrypt_key_size = 8; @@ -252,7 +297,7 @@ break; case LO_CRYPT_FISH2: case LO_CRYPT_BLOW: - pass = getpass("Password :"); + pass = xgetpass(pfd,_("Password :")); MDcalc((byte *)loopinfo.lo_encrypt_key,pass,strlen(pass)); loopinfo.lo_encrypt_key_size=20; /* 160 Bit key */ break; @@ -262,7 +307,7 @@ case LO_CRYPT_MARS: case LO_CRYPT_RC6: case LO_CRYPT_DFC: - pass = getpass("Password :"); + pass = xgetpass(pfd,_("Password :")); MDcalc((byte *)loopinfo.lo_encrypt_key,pass,strlen(pass)); loopinfo.lo_encrypt_key_size=16; /* 128 Bit key */ break; @@ -319,7 +364,7 @@ int set_loop (const char *device, const char *file, int offset, - const char *encryption, int *loopro) { + const char *encryption, int pfd, int *loopro) { mutter(); return 1; } @@ -348,20 +393,34 @@ int verbose = 0; static char *progname; +static struct option longopts[] = { + { "delete", 0, 0, 'd' }, + { "detach", 0, 0, 'd' }, + { "encryption", 1, 0, 'e' }, + { "help", 0, 0, 'h' }, + { "offset", 1, 0, 'o' }, + { "pass-fd", 1, 0, 'p' }, + { "verbose", 0, 0, 'v' }, + { NULL, 0, 0, 0 } +}; + + static void usage(void) { - struct crypt_type_struct *c; fprintf(stderr, _("usage:\n\ %s loop_device # give info\n\ %s -d loop_device # delete\n\ - %s [ -e encryption ] [ -o offset ] loop_device file # setup\n"), + %s [ options ] loop_device file # setup\n\ + where options include\n\ + --offset <num>, -o <num>\n\ + start at offset <num> into file.\n\ + --pass-fd <num>, -p <num>\n\ + read passphrase from file descriptor <num>\n\ + instead of the terminal.\n\ + --encryption <cipher>, -e <cipher>\n\ + encrypt with <cipher>.\n\ + Check /proc/cipher for available ciphers."), progname, progname, progname); - fprintf(stderr, " where encryption is one of:\n"); - c = &crypt_type_tbl[0]; - while(c->name) { - fprintf(stderr, " %s\n", c->name); - c++; - } exit(1); } @@ -394,8 +453,9 @@ int main(int argc, char **argv) { - char *offset, *encryption; + char *offset, *encryption, *passfd; int delete,off,c; + int pfd = -1; int res = 0; int ro = 0; @@ -404,9 +464,10 @@ textdomain(PACKAGE); delete = off = 0; - offset = encryption = NULL; + offset = encryption = passfd = NULL; progname = argv[0]; - while ((c = getopt(argc,argv,"de:o:v")) != EOF) { + while ((c = getopt_long(argc,argv,"de:ho:p:v", + longopts, NULL)) != EOF) { switch (c) { case 'd': delete = 1; @@ -417,6 +478,9 @@ case 'o': offset = optarg; break; + case 'p': + passfd = optarg; + break; case 'v': verbose = 1; break; @@ -425,7 +489,7 @@ } } if (argc == 1) usage(); - if ((delete && (argc != optind+1 || encryption || offset)) || + if ((delete && (argc != optind+1 || encryption || offset || passfd)) || (!delete && (argc < optind+1 || argc > optind+2))) usage(); if (argc == optind+1) { @@ -436,7 +500,9 @@ } else { if (offset && sscanf(offset,"%d",&off) != 1) usage(); - res = set_loop(argv[optind],argv[optind+1],off,encryption,&ro); + if (passfd && sscanf(passfd,"%d",&pfd) != 1) + usage(); + res = set_loop(argv[optind],argv[optind+1],off,encryption,pfd,&ro); } return res; } diff -urN util-linux-2.10o.i3/mount/lomount.h util-linux-2.10o.i3-getpass/mount/lomount.h --- util-linux-2.10o.i3/mount/lomount.h Fri Jul 9 04:56:39 1999 +++ util-linux-2.10o.i3-getpass/mount/lomount.h Sun Sep 24 17:20:01 2000 @@ -1,4 +1,4 @@ extern int verbose; -extern int set_loop (const char *, const char *, int, const char *, int *); +extern int set_loop (const char *, const char *, int, const char *, int, int *); extern int del_loop (const char *); extern char * find_unused_loop_device (void); diff -urN util-linux-2.10o.i3/mount/losetup.8 util-linux-2.10o.i3-getpass/mount/losetup.8 --- util-linux-2.10o.i3/mount/losetup.8 Sun Sep 24 16:46:02 2000 +++ util-linux-2.10o.i3-getpass/mount/losetup.8 Sun Sep 24 23:01:14 2000 @@ -10,6 +10,9 @@ ] [ .B \-o .I offset +] [ +.B \-p +.I num ] .I loop_device file .br @@ -26,9 +29,9 @@ \fIloop_device\fP argument is given, the status of the corresponding loop device is shown. .SH OPTIONS -.IP \fB\-d\fP +.IP "\fB\-\-delete, \-\-detach, \-d\fP" detach the file or device associated with the specified loop device. -.IP "\fB\-e \fIencryption\fP" +.IP "\fB\-\-encryption, \-e \fIencryption\fP" .RS enable data encryption. The following keywords are recognized: .IP \fBNONE\fP @@ -79,9 +82,12 @@ enabled in the Crypto API. .PD .RE -.IP "\fB\-o \fIoffset\fP" +.IP "\fB\-\-offset, \-o \fIoffset\fP" the data start is moved \fIoffset\fP bytes into the specified file or device. +.IP "\fB\-\-pass-fd, \-p \fInum\fP" +read the passphrase from file descriptor \fInum\fP instead of the +terminal. .SH RETURN VALUE .B losetup returns 0 on success, nonzero on failure. When diff -urN util-linux-2.10o.i3/mount/mount.8 util-linux-2.10o.i3-getpass/mount/mount.8 --- util-linux-2.10o.i3/mount/mount.8 Sun Jul 30 22:26:41 2000 +++ util-linux-2.10o.i3-getpass/mount/mount.8 Sun Sep 24 23:19:47 2000 @@ -252,6 +252,12 @@ .B \-v Verbose mode. .TP +.B \-p "\fInum\fP" +If the mount requires a passphrase to be entered, read it from file +descriptor +.IR num\fP +instead of from the terminal. +.TP .B \-a Mount all filesystems (of the given types) mentioned in .IR fstab . @@ -1240,7 +1246,10 @@ .BR loop ", " offset " and " encryption , that are really options to .BR losetup (8). -If no explicit loop device is mentioned +If the mount requires a passphrase, you will be prompted for one unless +you specify a file descriptor to read from instead with the +.BR \-\-pass-fd +option. If no explicit loop device is mentioned (but just an option `\fB\-o loop\fP' is given), then .B mount will try to find some unused loop device and use that. diff -urN util-linux-2.10o.i3/mount/mount.c util-linux-2.10o.i3-getpass/mount/mount.c --- util-linux-2.10o.i3/mount/mount.c Fri Aug 11 14:50:10 2000 +++ util-linux-2.10o.i3-getpass/mount/mount.c Sun Sep 24 23:24:09 2000 @@ -105,6 +105,9 @@ /* True if ruid != euid. */ static int suid = 0; +/* Contains the fd no. to read the passphrase from, if any */ +static int pfd = -1; + /* Map from -o and fstab option strings to the flag argument to mount(2). */ struct opt_map { const char *opt; /* option name */ @@ -536,7 +539,7 @@ if (verbose) printf(_("mount: going to use the loop device %s\n"), *loopdev); offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0; - if (set_loop (*loopdev, *loopfile, offset, opt_encryption, &loopro)) { + if (set_loop (*loopdev, *loopfile, offset, opt_encryption, pfd, &loopro)) { if (verbose) printf(_("mount: failed setting up loop device\n")); return EX_FAIL; @@ -1226,6 +1229,7 @@ { "read-write", 0, 0, 'w' }, { "rw", 0, 0, 'w' }, { "options", 1, 0, 'o' }, + { "pass-fd", 1, 0, 'p' }, { "types", 1, 0, 't' }, { "bind", 0, 0, 128 }, { "replace", 0, 0, 129 }, @@ -1259,7 +1263,7 @@ "or by label, using -L label or by uuid, using -U uuid .\n" "Union or stack mounts are specified using one of\n" " --replace, --after, --before, --over\n" - "Other options: [-nfFrsvw] [-o options].\n" + "Other options: [-nfFrsvw] [-o options] [-p num].\n" "For many more details, say man 8 mount .\n" )); unlock_mtab(); @@ -1271,6 +1275,7 @@ int c, result = 0, specseen; char *options = NULL, *spec, *node; char *volumelabel = NULL; + char *passfd = NULL; char *uuid = NULL; string_list types = NULL; struct mntentchn *mc; @@ -1291,7 +1296,7 @@ initproctitle(argc, argv); #endif - while ((c = getopt_long (argc, argv, "afFhlL:no:rsU:vVwt:", + while ((c = getopt_long (argc, argv, "afFhlL:no:p:rsU:vVwt:", longopts, NULL)) != EOF) { switch (c) { case 'a': /* mount everything in fstab */ @@ -1321,6 +1326,9 @@ else options = xstrdup(optarg); break; + case 'p': /* read passphrase from given fd */ + passfd = optarg; + break; case 'r': /* mount readonly */ readonly = 1; readwrite = 0; @@ -1405,6 +1413,9 @@ printf(_("mount: mounting %s\n"), spec); } else spec = NULL; /* just for gcc */ + + if (passfd && sscanf(passfd,"%d",&pfd) != 1) + die (EX_USAGE, _("mount: argument to --pass-fd or -p must be a number")); switch (argc+specseen) { case 0: