From owner-freebsd-geom@FreeBSD.ORG Fri Sep 9 10:00:58 2011 Return-Path: Delivered-To: freebsd-geom@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7E631106566B for ; Fri, 9 Sep 2011 10:00:58 +0000 (UTC) (envelope-from vwe@freebsd.org) Received: from Mail.elbekies.net (mail.elbekies.net [217.6.211.146]) by mx1.freebsd.org (Postfix) with ESMTP id EBA308FC08 for ; Fri, 9 Sep 2011 10:00:57 +0000 (UTC) X-Envelope-From: vwe@freebsd.org X-Envelope-From: vwe@freebsd.org Received: from bel.soho.vwsoft.com (p57A0B9BE.dip.t-dialin.net [87.160.185.190]) by Mail.elbekies.net (Postfix) with ESMTPA id 47C392E05B; Fri, 9 Sep 2011 11:41:15 +0200 (CEST) Received: from [192.168.16.4] (dardanos.sz.vwsoft.com [192.168.16.4]) by bel.soho.vwsoft.com (Postfix) with ESMTP id 563CB33C78; Fri, 9 Sep 2011 11:29:42 +0200 (CEST) Message-ID: <4E69DD4C.2000502@freebsd.org> Date: Fri, 09 Sep 2011 11:33:00 +0200 From: vwe@freebsd.org User-Agent: Mozilla/5.0 (X11; FreeBSD i386; rv:5.0) Gecko/20110702 Thunderbird/5.0 MIME-Version: 1.0 To: grarpamp References: In-Reply-To: Content-Type: multipart/mixed; boundary="------------020503080803090602030800" X-VWSoft-MailScanner: Found to be clean X-MailScanner-To: freebsd-geom@freebsd.org, grarpamp@gmail.com X-MailScanner-ID: 47C392E05B.AB522 X-Elbekies-MailScanner: Found to be clean X-MailScanner-From: vwe@freebsd.org MailScanner-NULL-Check: 1316166091.27145@kxYMs4XgtJH0EM5i91x9xw Cc: freebsd-geom@freebsd.org Subject: Re: GELI passphrase and/or key via command line or environment X-BeenThere: freebsd-geom@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: GEOM-specific discussions and implementations List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Sep 2011 10:00:58 -0000 This is a multi-part message in MIME format. --------------020503080803090602030800 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit On 01/-10/63 20:59, grarpamp wrote: > For both init and attach (and even elsewhere where > applicable), I'd like to be able to specify the passphrase > and key material via the command line and/or the environment. > Yes, we have -J/j and -K/k, but they only permit the use of files > or standard in. And of course standard in is not an arbitrary > file descriptor and as such is only usable once. So it cannot > be used with both jay and kay. I use both jay and kay, and want > to do so programmatically without blocking on keyboard input. > In the current implementation, I cannot achieve this. > > I'm well aware of all security implications of command line > and environment usage. > > Please offer your consideration of this feature request :) > Thanks. > Hi! I think since the -j/-J flags to geli(8) have been introduced, you may play some tricks with the shell to redirect input (on stable/8 and later systems). For stable/7 systems the attached patch should do what you're looking for. Please be aware, the (well tested) patch does a bit more than just giving you the ability to read the passphrase from stdin (new -t cli flag) but also makes some corrections if you're trying to backup and restore an eli provider. That does not work well if the sizes do not match and the attached patch fixes that also. I haven't tested for that bug on stable/8 systems but I guess that bug hasn't been fixed yet. HTH Volker --------------020503080803090602030800 Content-Type: text/plain; name="geom_eli.c.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="geom_eli.c.diff" --- sbin/geom/class/eli/geom_eli.c.orig 2009-06-17 17:26:12.000000000 +0200 +++ sbin/geom/class/eli/geom_eli.c 2009-11-10 09:26:25.000000000 +0100 @@ -73,18 +73,20 @@ static void eli_restore(struct gctl_req *req); static void eli_clear(struct gctl_req *req); static void eli_dump(struct gctl_req *req); +static char *eli_get_passwd(struct gctl_req *, const char *, char *, size_t); +static char *eli_get_stdin_passwd(void); /* * Available commands: * - * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov + * init [-bhPtv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov * label - alias for 'init' - * attach [-dprv] [-k keyfile] prov + * attach [-dprtv] [-k keyfile] prov * detach [-fl] prov ... * stop - alias for 'detach' * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ... * configure [-bB] prov ... - * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov + * setkey [-ptPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov * delkey [-afv] [-n keyno] prov * kill [-av] [prov ...] * backup [-v] prov file @@ -103,9 +105,10 @@ { 'l', "keylen", &keylen, G_TYPE_NUMBER }, { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, + { 't', "password-from-stdin", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - NULL, "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" + NULL, "[-btPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" }, { "label", G_FLAG_VERBOSE, eli_main, { @@ -117,6 +120,7 @@ { 'l', "keylen", &keylen, G_TYPE_NUMBER }, { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, + { 't', "password-from-stdin", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, NULL, "- an alias for 'init'" @@ -127,9 +131,10 @@ { 'k', "keyfile", keyfile, G_TYPE_STRING }, { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, { 'r', "readonly", NULL, G_TYPE_BOOL }, + { 't', "password-from-stdin", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - NULL, "[-dprv] [-k keyfile] prov" + NULL, "[-dtprv] [-k keyfile] prov" }, { "detach", 0, NULL, { @@ -174,9 +179,10 @@ { 'n', "keyno", &keyno, G_TYPE_NUMBER }, { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, + { 't', "password-from-stdin", NULL, G_TYPE_BOOL }, G_OPT_SENTINEL }, - NULL, "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" + NULL, "[-ptPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" }, { "delkey", G_FLAG_VERBOSE, eli_main, { @@ -359,9 +365,9 @@ return (NULL); } for (;;) { - p = readpassphrase( - new ? "Enter new passphrase:" : "Enter passphrase:", - buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); + p = eli_get_passwd(req, + new ? "Enter new passphrase: " : "Enter passphrase: ", + buf1, sizeof(buf1)); if (p == NULL) { bzero(buf1, sizeof(buf1)); gctl_error(req, "Cannot read passphrase: %s.", @@ -369,10 +375,9 @@ return (NULL); } - if (new) { - p = readpassphrase("Reenter new passphrase: ", - buf2, sizeof(buf2), - RPP_ECHO_OFF | RPP_REQUIRE_TTY); + if (new && ! gctl_get_int(req, "password-from-stdin")) { + p = eli_get_passwd(req, "Reenter new passphrase: ", + buf2, sizeof(buf2)); if (p == NULL) { bzero(buf1, sizeof(buf1)); gctl_error(req, @@ -383,7 +388,11 @@ if (strcmp(buf1, buf2) != 0) { bzero(buf2, sizeof(buf2)); - fprintf(stderr, "They didn't match.\n"); + gctl_error(req, "Passphrases didn't match."); + /* Exit immediately if reading passwords from stdin. */ + if (gctl_get_int(req, "password-from-stdin")) { + return (NULL); + } continue; } bzero(buf2, sizeof(buf2)); @@ -444,7 +453,7 @@ return (-1); } if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { - gctl_error(req, "Cannot read metadata from %s: %s.", + gctl_error(req, "Cannot read metadata file %s: %s.", prov, strerror(errno)); close(fd); return (-1); @@ -1167,6 +1176,12 @@ gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); goto out; } + if (md.md_provsize != mediasize) { + printf( "warning: size %llu does not match %llu\n", + md.md_provsize, mediasize); + md.md_provsize = mediasize; + eli_metadata_encode(&md, sector); + } /* Write metadata from the provider. */ if (pwrite(provfd, sector, secsize, mediasize - secsize) != (ssize_t)secsize) { @@ -1225,8 +1240,11 @@ for (i = 0; i < nargs; i++) { name = gctl_get_ascii(req, "arg%d", i); + error = eli_metadata_read(req, name, &tmpmd); + /* error = g_metadata_read(name, (unsigned char *)&tmpmd, sizeof(tmpmd), G_ELI_MAGIC); + */ if (error != 0) { fprintf(stderr, "Cannot read metadata from %s: %s.\n", name, strerror(error)); @@ -1244,3 +1262,43 @@ printf("\n"); } } + + +static char * +eli_get_passwd(struct gctl_req *req, const char *prompt, char *buf, size_t bufsiz) +{ + char *p = NULL; + + if (gctl_get_int(req, "password-from-stdin")) { + p = eli_get_stdin_passwd(); + strlcpy(buf, p, bufsiz); + } else { + p = readpassphrase(prompt, buf, bufsiz, RPP_ECHO_OFF | RPP_REQUIRE_TTY); + } + + return p; +} + +static char * +eli_get_stdin_passwd(void) +{ + static char buf[BUFSIZ]; + size_t len; + + bzero(buf, sizeof(buf)); + + /* + * if no error is reported from fgets() and string at least contains + * the newline that ends the password, then replace the newline with + * a null terminator. + */ + if (fgets(buf, sizeof(buf), stdin) != NULL) { + if ((len = strlen(buf)) > 0) { + if (buf[len-1] == '\n') + buf[len - 1] = 0; + } + } + + return buf; +} + --------------020503080803090602030800--