GELI passphrase and/or key via command line or environment

vwe at freebsd.org vwe at freebsd.org
Fri Sep 9 10:00:58 UTC 2011


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
-------------- next part --------------
--- 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", &sectorsize, 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", &sectorsize, 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;
+}
+


More information about the freebsd-geom mailing list