Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 May 2013 21:40:01 GMT
From:      Mark Linimon <linimon@lonesome.com>
To:        freebsd-geom@FreeBSD.org
Subject:   Re: kern/178359: [geom] [patch] geom_eli: support external metadata
Message-ID:  <201305082140.r48Le1O3093438@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/178359; it has been noted by GNATS.

From: Mark Linimon <linimon@lonesome.com>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata
Date: Wed, 8 May 2013 16:35:55 -0500

 ----- Forwarded message from Andrew Romanenko <melanhit@gmail.com> -----
 
 Date: Tue, 07 May 2013 10:26:07 +0300
 From: Andrew Romanenko <melanhit@gmail.com>
 To: Scot Hetzel <swhetzel@gmail.com>
 Cc: freebsd-bugs@freebsd.org, freebsd-geom@freebsd.org
 Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata
 User-Agent: Mozilla/5.0 (X11; Linux i686;
 	rv:17.0) Gecko/20130407 Thunderbird/17.0.5
 
 On 05/06/2013 07:32 AM, Scot Hetzel wrote:
 > On Sun, May 5, 2013 at 10:51 PM, Scot Hetzel <swhetzel@gmail.com> wrote:
 >> On Sun, May 5, 2013 at 7:54 PM,  <linimon@freebsd.org> wrote:
 >>> Old Synopsis: geom_eli: support external metadata
 >>> New Synopsis: [geom] [patch] geom_eli: support external metadata
 >>>
 >>> Responsible-Changed-From-To: freebsd-bugs->freebsd-geom
 >>> Responsible-Changed-By: linimon
 >>> Responsible-Changed-When: Mon May 6 00:54:16 UTC 2013
 >>> Responsible-Changed-Why:
 >>> Over to maintainer(s).
 >>>
 >>> http://www.freebsd.org/cgi/query-pr.cgi?pr=178359
 >> I had a quick look at the patch and noticed that it is using -H for
 >> init method, but -h for the attach, configure, setkey, delkey, resume,
 >> resize, and dump methods.
 >>
 >> The patch also shows that it removes the -h option from the init
 >> method.  I looked at the -Current and release/9.1.0 sources for
 >> geom_eli.8 and they don't have the -h option.  I suspect it was a
 >> local modification that was made before this patch was created.
 >>
 > My mistake, the -h option was in the geom_eli.c file, but only in the
 > comment for the commands.  According to the original commit:
 >
 > https://svnweb.freebsd.org/base?view=revision&revision=148456
 >
 > The -h was never in the class_commands for the init method.  Not sure
 > what it was there for (maybe to display the usuage?).
 >
 >> It would be best that init, attach, configure, setkey, delkey, resume,
 >> resize, and dump methods use the same option (-h or -H) to specify the
 >> headerfile.
 >>
 > So for now it looks like using -H would be the better option for all
 > these methods.
 >
 I forgot to include patch sys/geom/eli/g_eli.c (sorry, it's my mistake).
 Finished and full version of the patch in an attachment
 
 --- sbin/geom/class/eli/geom_eli.c.orig	2013-05-03 00:00:34.551720905 +0300
 +++ sbin/geom/class/eli/geom_eli.c	2013-05-05 23:57:52.631347936 +0300
 @@ -60,7 +60,6 @@
  
  #define	GELI_BACKUP_DIR	"/var/backups/"
  #define	GELI_ENC_ALGO	"aes"
 -
  static void eli_main(struct gctl_req *req, unsigned flags);
  static void eli_init(struct gctl_req *req);
  static void eli_attach(struct gctl_req *req);
 @@ -81,23 +80,23 @@
  /*
   * Available commands:
   *
 - * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
 + * init [-bPv] [-a aalgo] [-B backupfile] [-H headerfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov
   * label - alias for 'init'
 - * attach [-dprv] [-j passfile] [-k keyfile] prov
 + * attach [-dprv] [-H headerfile] [-j passfile] [-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] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
 - * delkey [-afv] [-n keyno] prov
 + * configure [-bB] [-H headerfile] prov ...
 + * setkey [-pPv] [-H headerfile] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov
 + * delkey [-afv] [-H headerfile] [-n keyno] prov
   * suspend [-v] -a | prov ...
 - * resume [-pv] [-j passfile] [-k keyfile] prov
 + * resume [-pv] [-H headerfile] [-j passfile] [-k keyfile] prov
   * kill [-av] [prov ...]
   * backup [-v] prov file
   * restore [-fv] file prov
 - * resize [-v] -s oldsize prov
 + * resize [-v] [-H headerfile] -s oldsize prov
   * clear [-v] prov ...
 - * dump [-v] prov ...
 + * dump [-v] [-H headerfile] prov ...
   */
  struct g_command class_commands[] = {
  	{ "init", G_FLAG_VERBOSE, eli_main,
 @@ -112,9 +111,10 @@
  		{ 'l', "keylen", "0", G_TYPE_NUMBER },
  		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
  		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
 +	    "[-bPv] [-H headerfile] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov"
  	},
  	{ "label", G_FLAG_VERBOSE, eli_main,
  	    {
 @@ -128,6 +128,7 @@
  		{ 'l', "keylen", "0", G_TYPE_NUMBER },
  		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
  		{ 's', "sectorsize", "0", G_TYPE_NUMBER },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
  	    "- an alias for 'init'"
 @@ -139,9 +140,10 @@
  		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
  		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
  		{ 'r', "readonly", NULL, G_TYPE_BOOL },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-dprv] [-j passfile] [-k keyfile] prov"
 +	    "[-dprv] [-H headerfile] [-j passfile] [-k keyfile] prov"
  	},
  	{ "detach", 0, NULL,
  	    {
 @@ -174,9 +176,10 @@
  	    {
  		{ 'b', "boot", NULL, G_TYPE_BOOL },
  		{ 'B', "noboot", NULL, G_TYPE_BOOL },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-bB] prov ..."
 +	    "[-bB] [-H headerfile] prov ..."
  	},
  	{ "setkey", G_FLAG_VERBOSE, eli_main,
  	    {
 @@ -188,18 +191,20 @@
  		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
  		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
  		{ 'P', "nonewpassphrase", NULL, G_TYPE_BOOL },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
 +	    "[-pPv] [-H headerfile] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov"
  	},
  	{ "delkey", G_FLAG_VERBOSE, eli_main,
  	    {
  		{ 'a', "all", NULL, G_TYPE_BOOL },
  		{ 'f', "force", NULL, G_TYPE_BOOL },
  		{ 'n', "keyno", "-1", G_TYPE_NUMBER },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-afv] [-n keyno] prov"
 +	    "[-afv] [-H headerfile] [-n keyno] prov"
  	},
  	{ "suspend", G_FLAG_VERBOSE, NULL,
  	    {
 @@ -213,9 +218,10 @@
  		{ 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
  		{ 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI },
  		{ 'p', "nopassphrase", NULL, G_TYPE_BOOL },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-pv] [-j passfile] [-k keyfile] prov"
 +	    "[-pv] [-H headerfile] [-j passfile] [-k keyfile] prov"
  	},
  	{ "kill", G_FLAG_VERBOSE, eli_main,
  	    {
 @@ -237,15 +243,20 @@
  	{ "resize", G_FLAG_VERBOSE, eli_main,
  	    {
  		{ 's', "oldsize", NULL, G_TYPE_NUMBER },
 +		{ 'H', "header", "", G_TYPE_STRING },
  		G_OPT_SENTINEL
  	    },
 -	    "[-v] -s oldsize prov"
 +	    "[-v] [-H headerfile] -s oldsize prov"
  	},
  	{ "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
  	    "[-v] prov ..."
  	},
 -	{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
 -	    "[-v] prov ..."
 +	{ "dump", G_FLAG_VERBOSE, eli_main,
 +		{
 +		{ 'H', "header", "", G_TYPE_STRING },
 +		G_OPT_SENTINEL
 +		},
 +	    "[-v] [-H headerfile]  prov ..."
  	},
  	G_CMD_SENTINEL
  };
 @@ -653,7 +664,7 @@
  	unsigned char sector[sizeof(struct g_eli_metadata)];
  	unsigned char key[G_ELI_USERKEYLEN];
  	char backfile[MAXPATHLEN];
 -	const char *str, *prov;
 +	const char *str, *prov, *header;
  	unsigned secsize;
  	off_t mediasize;
  	intmax_t val;
 @@ -776,17 +787,39 @@
  		return;
  	}
  
 +	header = gctl_get_ascii(req, "header");
 +
 +	/* Store header if it present */
 +	if(header[0] != '\0') {
 +		error = eli_metadata_store(req, header, &md);
 +
 +		if(error != 0) {
 +			gctl_error(req, "Cannot store header %s: %s.", header,
 +					strerror(error));
 +			return;
 +		}
 +
 +		str = gctl_get_ascii(req, "backupfile");
 +		if(str[0] != '\0')
 +			if(strcmp(str, "none") != 0)
 +				printf("Warning: options -B and -H are mutualy exlusive\n");
 +
 +		return;
 +	}
 +
  	eli_metadata_encode(&md, sector);
  	bzero(&md, sizeof(md));
 +
  	error = g_metadata_store(prov, sector, sizeof(sector));
  	bzero(sector, sizeof(sector));
  	if (error != 0) {
  		gctl_error(req, "Cannot store metadata on %s: %s.", prov,
 -		    strerror(error));
 +			strerror(error));
  		return;
  	}
  	if (verbose)
  		printf("Metadata value stored on %s.\n", prov);
 +
  	/* Backup metadata to a file. */
  	str = gctl_get_ascii(req, "backupfile");
  	if (str[0] != '\0') {
 @@ -820,10 +853,14 @@
  {
  	struct g_eli_metadata md;
  	unsigned char key[G_ELI_USERKEYLEN];
 -	const char *prov;
 +	unsigned char *hd;
 +	const char *prov, *str, *header;
  	off_t mediasize;
 +	ssize_t hdsize;
  	int nargs;
  
 +	hd = NULL;
 +
  	nargs = gctl_get_int(req, "nargs");
  	if (nargs != 1) {
  		gctl_error(req, "Invalid number of arguments.");
 @@ -831,9 +868,16 @@
  	}
  	prov = gctl_get_ascii(req, "arg0");
  
 -	if (eli_metadata_read(req, prov, &md) == -1)
 +	header = gctl_get_ascii(req, "header");
 +	if (header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
 +	if (eli_metadata_read(req, str, &md) == -1)
  		return;
  
 +	hdsize = g_get_sectorsize(prov);
  	mediasize = g_get_mediasize(prov);
  	if (md.md_provsize != (uint64_t)mediasize) {
  		gctl_error(req, "Provider size mismatch.");
 @@ -845,20 +889,43 @@
  		return;
  	}
  
 +	if(header[0] != '\0') {
 +		hd = malloc(hdsize);
 +		if(hd == NULL) {
 +			gctl_error(req, "Cannot allocate %zd bytes of memory.", hdsize);
 +			return;
 +		}
 +
 +		bzero(hd, hdsize);
 +		eli_metadata_encode(&md, hd);
 +	} else {
 +		hdsize = sizeof(hd);
 +	}
 +
 +	gctl_ro_param(req, "hd", hdsize, hd);
  	gctl_ro_param(req, "key", sizeof(key), key);
  	if (gctl_issue(req) == NULL) {
  		if (verbose)
  			printf("Attached to %s.\n", prov);
  	}
  	bzero(key, sizeof(key));
 +	if(hd != NULL)
 +		free(hd);
  }
  
  static void
  eli_configure_detached(struct gctl_req *req, const char *prov, bool boot)
  {
  	struct g_eli_metadata md;
 +	const char *str, *header;
  
 -	if (eli_metadata_read(req, prov, &md) == -1)
 +	header = gctl_get_ascii(req, "header");
 +	if (header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
 +	if (eli_metadata_read(req, str, &md) == -1)
  		return;
  
  	if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) {
 @@ -872,7 +939,13 @@
  			md.md_flags |= G_ELI_FLAG_BOOT;
  		else
  			md.md_flags &= ~G_ELI_FLAG_BOOT;
 -		eli_metadata_store(req, prov, &md);
 +
 +		if(header[0] != '\0')
 +			str = header;
 +		else
 +			str = prov;
 +
 +		eli_metadata_store(req, str, &md);
  	}
  	bzero(&md, sizeof(md));
  }
 @@ -880,7 +953,7 @@
  static void
  eli_configure(struct gctl_req *req)
  {
 -	const char *prov;
 +	const char *prov, *header;
  	bool boot, noboot;
  	int i, nargs;
  
 @@ -902,14 +975,29 @@
  		return;
  	}
  
 +	header = gctl_get_ascii(req, "header");
 +
  	/* First attached providers. */
 -	gctl_issue(req);
 +	if(header[0] != '\0') {
 +		if(nargs != 1) {
 +			gctl_error(req, "Too many arguments.");
 +			return;
 +		}
 +
 +		prov = gctl_get_ascii(req, "arg0");
 +		eli_configure_detached(req, prov, boot);
 +		return;
 +	} else {
 +		gctl_issue(req);
 +	}
 +
  	/* Now the rest. */
  	for (i = 0; i < nargs; i++) {
  		prov = gctl_get_ascii(req, "arg%d", i);
  		if (!eli_is_attached(prov))
  			eli_configure_detached(req, prov, boot);
  	}
 +
  }
  
  static void
 @@ -950,6 +1038,7 @@
  eli_setkey_detached(struct gctl_req *req, const char *prov,
   struct g_eli_metadata *md)
  {
 +	const char *header, *str;
  	unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN];
  	unsigned char *mkeydst;
  	unsigned int nkey;
 @@ -1035,7 +1124,14 @@
  	}
  
  	/* Store metadata with fresh key. */
 -	eli_metadata_store(req, prov, md);
 +	header = gctl_get_ascii(req, "header");
 +	if(header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
 +	eli_metadata_store(req, str, md);
 +
  	bzero(md, sizeof(*md));
  }
  
 @@ -1043,7 +1139,7 @@
  eli_setkey(struct gctl_req *req)
  {
  	struct g_eli_metadata md;
 -	const char *prov;
 +	const char *prov, *header, *str;
  	int nargs;
  
  	nargs = gctl_get_int(req, "nargs");
 @@ -1053,10 +1149,16 @@
  	}
  	prov = gctl_get_ascii(req, "arg0");
  
 -	if (eli_metadata_read(req, prov, &md) == -1)
 +	header = gctl_get_ascii(req, "header");
 +	if(header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
 +	if (eli_metadata_read(req, str, &md) == -1)
  		return;
  
 -	if (eli_is_attached(prov))
 +	if (eli_is_attached(prov) && header[0] == '\0')
  		eli_setkey_attached(req, &md);
  	else
  		eli_setkey_detached(req, prov, &md);
 @@ -1079,12 +1181,19 @@
  eli_delkey_detached(struct gctl_req *req, const char *prov)
  {
  	struct g_eli_metadata md;
 +	const char *header, *str;
  	unsigned char *mkeydst;
  	unsigned int nkey;
  	intmax_t val;
  	bool all, force;
  
 -	if (eli_metadata_read(req, prov, &md) == -1)
 +	header = gctl_get_ascii(req, "header");
 +	if(header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
 +	if (eli_metadata_read(req, str, &md) == -1)
  		return;
  
  	all = gctl_get_int(req, "all");
 @@ -1116,6 +1225,11 @@
  		arc4rand(mkeydst, G_ELI_MKEYLEN);
  	}
  
 +	if(header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
  	eli_metadata_store(req, prov, &md);
  	bzero(&md, sizeof(md));
  }
 @@ -1123,7 +1237,7 @@
  static void
  eli_delkey(struct gctl_req *req)
  {
 -	const char *prov;
 +	const char *prov, *header;
  	int nargs;
  
  	nargs = gctl_get_int(req, "nargs");
 @@ -1133,7 +1247,9 @@
  	}
  	prov = gctl_get_ascii(req, "arg0");
  
 -	if (eli_is_attached(prov))
 +	header = gctl_get_ascii(req, "header");
 +
 +	if (eli_is_attached(prov) && header[0] == '\0')
  		eli_delkey_attached(req, prov);
  	else
  		eli_delkey_detached(req, prov);
 @@ -1144,10 +1260,14 @@
  {
  	struct g_eli_metadata md;
  	unsigned char key[G_ELI_USERKEYLEN];
 -	const char *prov;
 +	unsigned char *hd;
 +	const char *prov, *str, *header;
  	off_t mediasize;
 +	ssize_t hdsize;
  	int nargs;
  
 +	hd = NULL;
 +
  	nargs = gctl_get_int(req, "nargs");
  	if (nargs != 1) {
  		gctl_error(req, "Invalid number of arguments.");
 @@ -1155,10 +1275,18 @@
  	}
  	prov = gctl_get_ascii(req, "arg0");
  
 -	if (eli_metadata_read(req, prov, &md) == -1)
 +	header = gctl_get_ascii(req, "header");
 +	if (header[0] != '\0')
 +		str = header;
 +	else
 +		str = prov;
 +
 +	if (eli_metadata_read(req, str, &md) == -1)
  		return;
  
  	mediasize = g_get_mediasize(prov);
 +	hdsize = g_get_sectorsize(prov);
 +
  	if (md.md_provsize != (uint64_t)mediasize) {
  		gctl_error(req, "Provider size mismatch.");
  		return;
 @@ -1169,12 +1297,30 @@
  		return;
  	}
  
 +	if(header[0] != '\0') {
 +		hd = malloc(hdsize);
 +		if(hd == NULL) {
 +			gctl_error(req, "Cannot allocate %zd bytes of memory.", hdsize);
 +			return;
 +		}
 +
 +		bzero(hd, hdsize);
 +		eli_metadata_encode(&md, hd);
 +	} else {
 +		hdsize = sizeof(hd);
 +	}
 +
 +	gctl_ro_param(req, "hd", hdsize, hd);
  	gctl_ro_param(req, "key", sizeof(key), key);
 +
  	if (gctl_issue(req) == NULL) {
  		if (verbose)
  			printf("Resumed %s.\n", prov);
  	}
  	bzero(key, sizeof(key));
 +
 +	if(hd != NULL)
 +		free(hd);
  }
  
  static int
 @@ -1469,11 +1615,11 @@
  eli_resize(struct gctl_req *req)
  {
  	struct g_eli_metadata md;
 -	const char *prov;
 +	const char *prov, *header;
  	unsigned char *sector;
  	ssize_t secsize;
  	off_t mediasize, oldsize;
 -	int nargs, provfd;
 +	int nargs, provfd, error;
  
  	nargs = gctl_get_int(req, "nargs");
  	if (nargs != 1) {
 @@ -1486,14 +1632,18 @@
  	sector = NULL;
  	secsize = 0;
  
 -	provfd = g_open(prov, 1);
 -	if (provfd == -1) {
 -		gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
 -		goto out;
 +	header = gctl_get_ascii(req, "header");
 +
 +	if(header[0] == '\0') {
 +		provfd = g_open(prov, 1);
 +		if (provfd == -1) {
 +			gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
 +			goto out;
 +		}
  	}
  
 -	mediasize = g_mediasize(provfd);
 -	secsize = g_sectorsize(provfd);
 +	mediasize = g_get_mediasize(prov);
 +	secsize = g_get_sectorsize(prov);
  	if (mediasize == -1 || secsize == -1) {
  		gctl_error(req, "Cannot get information about %s: %s.", prov,
  		    strerror(errno));
 @@ -1517,16 +1667,24 @@
  	}
  
  	/* Read metadata from the 'oldsize' offset. */
 -	if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
 -		gctl_error(req, "Cannot read old metadata: %s.",
 -		    strerror(errno));
 -		goto out;
 -	}
 +	if(header[0] != '\0') {
 +		if (eli_metadata_read(req, header, &md) == -1) {
 +			gctl_error(req, "Cannot read old metadata: %s.",
 +					header);
 +			goto out;
 +		}
 +	} else {
 +		if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) {
 +			gctl_error(req, "Cannot read old metadata: %s.",
 +				strerror(errno));
 +			goto out;
 +		}
  
 -	/* Check if this sector contains geli metadata. */
 -	if (eli_metadata_decode(sector, &md) != 0) {
 -		gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
 -		goto out;
 +		/* Check if this sector contains geli metadata. */
 +		if (eli_metadata_decode(sector, &md) != 0) {
 +			gctl_error(req, "MD5 hash mismatch: no metadata for oldsize.");
 +			goto out;
 +		}
  	}
  
  	/*
 @@ -1544,15 +1702,25 @@
  	 */
  	md.md_provsize = mediasize;
  	eli_metadata_encode(&md, sector);
 -	if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
 -		gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
 -		goto out;
 -	}
 -	(void)g_flush(provfd);
  
 -	/* Now trash the old metadata. */
 -	if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
 -		goto out;
 +	if(header[0] != '\0') {
 +		error = eli_metadata_store(req, header, &md);
 +		if(error != 0) {
 +			gctl_error(req, "Cannot store header %s: %s.", header,
 +					strerror(error));
 +			goto out;
 +		}
 +	} else {
 +		if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) {
 +			gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
 +			goto out;
 +		}
 +		(void)g_flush(provfd);
 +
 +		/* Now trash the old metadata. */
 +		if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1)
 +			goto out;
 +	}
  out:
  	if (provfd >= 0)
  		(void)g_close(provfd);
 @@ -1592,7 +1760,7 @@
  eli_dump(struct gctl_req *req)
  {
  	struct g_eli_metadata md, tmpmd;
 -	const char *name;
 +	const char *name, *header;
  	int error, i, nargs;
  
  	nargs = gctl_get_int(req, "nargs");
 @@ -1601,15 +1769,40 @@
  		return;
  	}
  
 -	for (i = 0; i < nargs; i++) {
 -		name = gctl_get_ascii(req, "arg%d", i);
 -		error = g_metadata_read(name, (unsigned char *)&tmpmd,
 -		    sizeof(tmpmd), G_ELI_MAGIC);
 -		if (error != 0) {
 +	header = gctl_get_ascii(req, "header");
 +	if(header[0] != '\0') {
 +		if(nargs != 1) {
 +			gctl_error(req, "Too many arguments.");
 +			return;
 +		}
 +
 +		if (eli_metadata_read(req, header, &tmpmd) == -1)
 +			return;
 +
 +		name = gctl_get_ascii(req, "arg0");
 +
 +		if (strcmp(tmpmd.md_magic, G_ELI_MAGIC) != 0) {
 +			error = EINVAL;
  			fprintf(stderr, "Cannot read metadata from %s: %s.\n",
 -			    name, strerror(error));
 +					name, strerror(error));
  			gctl_error(req, "Not fully done.");
 -			continue;
 +			return;
 +		}
 +
 +		name = header;
 +	}
 +
 +	for (i = 0; i < nargs; i++) {
 +		if(header[0] == '\0') {
 +			name = gctl_get_ascii(req, "arg%d", i);
 +			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));
 +				gctl_error(req, "Not fully done.");
 +				continue;
 +			}
  		}
  		if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) {
  			fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n",
 --- sbin/geom/class/eli/geli.8.orig	2013-04-29 01:45:56.000000000 +0300
 +++ sbin/geom/class/eli/geli.8	2013-05-05 16:49:57.642188841 +0300
 @@ -52,6 +52,7 @@
  .Nm
  .Cm init
  .Op Fl bPv
 +.Op Fl H Ar headerfile
  .Op Fl a Ar aalgo
  .Op Fl B Ar backupfile
  .Op Fl e Ar ealgo
 @@ -67,6 +68,7 @@
  .Nm
  .Cm attach
  .Op Fl dprv
 +.Op Fl H Ar headerfile
  .Op Fl j Ar passfile
  .Op Fl k Ar keyfile
  .Ar prov
 @@ -88,10 +90,12 @@
  .Nm
  .Cm configure
  .Op Fl bB
 +.Op Fl H Ar headerfile
  .Ar prov ...
  .Nm
  .Cm setkey
  .Op Fl pPv
 +.Op Fl H Ar headerfile
  .Op Fl i Ar iterations
  .Op Fl j Ar passfile
  .Op Fl J Ar newpassfile
 @@ -102,6 +106,7 @@
  .Nm
  .Cm delkey
  .Op Fl afv
 +.Op Fl H Ar headerfile
  .Op Fl n Ar keyno
  .Ar prov
  .Nm
 @@ -125,12 +130,14 @@
  .Nm
  .Cm resume
  .Op Fl pv
 +.Op Fl H Ar headerfile
  .Op Fl j Ar passfile
  .Op Fl k Ar keyfile
  .Ar prov
  .Nm
  .Cm resize
  .Op Fl v
 +.Op Fl H Ar headerfile
  .Fl s Ar oldsize
  .Ar prov
  .Nm
 @@ -140,6 +147,7 @@
  .Nm
  .Cm dump
  .Op Fl v
 +.Op Fl H Ar headerfile
  .Ar prov ...
  .Nm
  .Cm list
 @@ -240,6 +248,8 @@
  .Pp
  Additional options include:
  .Bl -tag -width ".Fl J Ar newpassfile"
 +.It Fl H Ar headerfile
 +Store GELI metadata (header) in the external file
  .It Fl a Ar aalgo
  Enable data integrity verification (authentication) using the given algorithm.
  This will reduce size of available storage and also reduce speed.
 @@ -341,6 +351,8 @@
  option for the
  .Cm detach
  subcommand.
 +.It Fl H Ar headerfile
 +Read metadata from a file instead from a provider
  .It Fl j Ar passfile
  Specifies a file which contains the passphrase or its part.
  For more information see the description of the
 @@ -415,7 +427,9 @@
  Change configuration of the given providers.
  .Pp
  Additional options include:
 -.Bl -tag -width ".Fl b"
 +.Bl -tag -width ".Fl H Ar headerfile"
 +.It Fl H Ar headerfile
 +Handle external metadata
  .It Fl b
  Set the BOOT flag on the given providers.
  For more information, see the description of the
 @@ -437,6 +451,8 @@
  .Pp
  Additional options include:
  .Bl -tag -width ".Fl J Ar newpassfile"
 +.It Fl H Ar headerfile
 +Handle external metadata
  .It Fl i Ar iterations
  Number of iterations to use with PKCS#5v2.
  If 0 is given, PKCS#5v2 will not be used.
 @@ -472,7 +488,9 @@
  subcommand.
  .Pp
  Additional options include:
 -.Bl -tag -width ".Fl a Ar keyno"
 +.Bl -tag -width ".Fl H Ar headerfile"
 +.It Fl H Ar headerfile
 +Handle external metadata
  .It Fl a
  Destroy all keys (does not need
  .Fl f
 @@ -567,7 +585,9 @@
  utility is stored is bad idea.
  .Pp
  Additional options include:
 -.Bl -tag -width ".Fl j Ar passfile"
 +.Bl -tag -width ".Fl H Ar headerfile"
 +.It Fl H Ar headerfile
 +Handle external metadata
  .It Fl j Ar passfile
  Specifies a file which contains the passphrase or its part.
  For more information see the description of the
 @@ -593,7 +613,9 @@
  provider and the provider size is updated.
  .Pp
  Additional options include:
 -.Bl -tag -width ".Fl s Ar oldsize"
 +.Bl -tag -width ".Fl H Ar headerfile"
 +.It Fl H Ar headerfile
 +Handle external metadata
  .It Fl s Ar oldsize
  The size of the provider before it was resized.
  .El
 @@ -764,6 +786,9 @@
  # dd if=/dev/random of=/dev/da1s3a bs=1m
  # dd if=/dev/random of=/boot/keys/da1s3a.key bs=128k count=1
  # geli init -b -P -K /boot/keys/da1s3a.key da1s3a
 +# dd if=/dev/random of=/dev/ada1 bs=1m
 +# dd if=/dev/random of=/boot/keys/ada1.key bs=8 count=8
 +# geli init -b -H /boot/hd/ada1.hd -P -K /boot/keys/ada1.key ada1
  .Ed
  .Pp
  The providers are initialized, now we have to add those lines to
 @@ -782,6 +807,13 @@
  geli_da1s3a_keyfile0_load="YES"
  geli_da1s3a_keyfile0_type="da1s3a:geli_keyfile0"
  geli_da1s3a_keyfile0_name="/boot/keys/da1s3a.key"
 +
 +geli_ada1_header_load="YES"
 +geli_ada1_header_type="ada1:geli_header"
 +geli_ada1_header_name="/boot/hd/ada1.hd"
 +geli_ada1_keyfile0_load="YES"
 +geli_ada1_keyfile0_type="ada1:geli_keyfile0"
 +geli_ada1_keyfile0_name="/boot/keys/ada1.key"
  .Ed
  .Pp
  Not only configure encryption, but also data integrity verification using
 --- sys/geom/eli/g_eli_ctl.c.orig	2013-05-04 01:21:45.381136674 +0300
 +++ sys/geom/eli/g_eli_ctl.c	2013-05-05 03:20:20.180243224 +0300
 @@ -56,10 +56,11 @@
  	struct g_eli_metadata md;
  	struct g_provider *pp;
  	const char *name;
 -	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
 +	u_char *key, *hd, mkey[G_ELI_DATAIVKEYLEN];
  	int *nargs, *detach, *readonly;
  	int keysize, error;
  	u_int nkey;
 +	ssize_t hdsize;
  
  	g_topology_assert();
  
 @@ -97,11 +98,18 @@
  		gctl_error(req, "Provider %s is invalid.", name);
  		return;
  	}
 -	error = g_eli_read_metadata(mp, pp, &md);
 -	if (error != 0) {
 -		gctl_error(req, "Cannot read metadata from %s (error=%d).",
 -		    name, error);
 -		return;
 +
 +	hd = gctl_get_param(req, "hd", &hdsize);
 +
 +	if(hdsize == pp->sectorsize) {
 +		eli_metadata_decode(hd, &md);
 +	} else {
 +		error = g_eli_read_metadata(mp, pp, &md);
 +		if (error != 0) {
 +			gctl_error(req, "Cannot read metadata from %s (error=%d).",
 +				name, error);
 +			return;
 +		}
  	}
  	if (md.md_keys == 0x00) {
  		bzero(&md, sizeof(md));
 @@ -448,8 +456,8 @@
  		error = g_eli_read_metadata(mp, pp, &md);
  		if (error != 0) {
  			gctl_error(req,
 -			    "Cannot read metadata from %s (error=%d).",
 -			    prov, error);
 +				"Cannot read metadata from %s (error=%d).",
 +				prov, error);
  			continue;
  		}
  
 @@ -464,12 +472,13 @@
  		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
  		eli_metadata_encode(&md, sector);
  		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
 -		    pp->sectorsize);
 +			pp->sectorsize);
  		if (error != 0) {
  			gctl_error(req,
 -			    "Cannot store metadata on %s (error=%d).",
 -			    prov, error);
 +				"Cannot store metadata on %s (error=%d).",
 +				prov, error);
  		}
 +		
  		bzero(&md, sizeof(md));
  		bzero(sector, sizeof(sector));
  		free(sector, M_ELI);
 @@ -815,9 +824,10 @@
  	struct g_provider *pp;
  	struct g_consumer *cp;
  	const char *name;
 -	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
 +	u_char *key, *hd, mkey[G_ELI_DATAIVKEYLEN];
  	int *nargs, keysize, error;
  	u_int nkey;
 +	ssize_t hdsize;
  
  	g_topology_assert();
  
 @@ -843,12 +853,20 @@
  	}
  	cp = LIST_FIRST(&sc->sc_geom->consumer);
  	pp = cp->provider;
 -	error = g_eli_read_metadata(mp, pp, &md);
 -	if (error != 0) {
 -		gctl_error(req, "Cannot read metadata from %s (error=%d).",
 -		    name, error);
 -		return;
 +
 +	hd = gctl_get_param(req, "hd", &hdsize);
 +
 +	if(hdsize == pp->sectorsize) {
 +		eli_metadata_decode(hd, &md);
 +	} else {
 +		error = g_eli_read_metadata(mp, pp, &md);
 +		if (error != 0) {
 +			gctl_error(req, "Cannot read metadata from %s (error=%d).",
 +				name, error);
 +			return;
 +		}
  	}
 +
  	if (md.md_keys == 0x00) {
  		bzero(&md, sizeof(md));
  		gctl_error(req, "No valid keys on %s.", pp->name);
 --- sys/geom/eli/g_eli.c.orig	2013-05-07 10:08:29.000000000 +0300
 +++ sys/geom/eli/g_eli.c	2013-05-04 00:26:03.620416070 +0300
 @@ -1013,6 +1013,47 @@
  	}
  }
  
 +static int
 +g_eli_header_load(struct g_eli_metadata *md, const char *provider)
 +{
 +	unsigned char *headfile, *data;
 +	char *file, name[64];
 +	size_t size;
 +
 +	snprintf(name, sizeof(name), "%s:geli_header", provider);
 +	headfile = preload_search_by_type(name);
 +	if (headfile == NULL)
 +		return (1);
 +
 +	data = preload_fetch_addr(headfile);
 +	if (data == NULL) {
 +		G_ELI_DEBUG(0, "Cannot find header file data for %s.",
 +				name);
 +		return (1);
 +	}
 +
 +	size = preload_fetch_size(headfile);
 +	if (size == 0) {
 +		G_ELI_DEBUG(0, "Cannot find header file size for %s.",
 +				name);
 +		return (1);
 +	}
 +
 +	file = preload_search_info(headfile, MODINFO_NAME);
 +	if (file == NULL) {
 +		G_ELI_DEBUG(0, "Cannot find header file name for %s.",
 +				name);
 +		return (1);
 +	}
 +
 +	G_ELI_DEBUG(1, "Loaded header %s for %s (type: %s).", file,
 +			provider, name);
 +
 +	eli_metadata_decode(data, md);
 +
 +	return (0);
 +}
 +
  /*
   * Tasting is only made on boot.
   * We detect providers which should be attached before root is mounted.
 @@ -1036,9 +1077,11 @@
  
  	G_ELI_DEBUG(3, "Tasting %s.", pp->name);
  
 -	error = g_eli_read_metadata(mp, pp, &md);
 -	if (error != 0)
 -		return (NULL);
 +	if(g_eli_header_load(&md, pp->name) != 0) {
 +		error = g_eli_read_metadata(mp, pp, &md);
 +		if (error != 0)
 +			return (NULL);
 +	}
  	gp = NULL;
  
  	if (strcmp(md.md_magic, G_ELI_MAGIC) != 0)
 
 _______________________________________________
 freebsd-bugs@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
 To unsubscribe, send any mail to "freebsd-bugs-unsubscribe@freebsd.org"
 
 
 ----- End forwarded message -----



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201305082140.r48Le1O3093438>