From owner-freebsd-bugs@FreeBSD.ORG Tue May 7 07:26:18 2013 Return-Path: Delivered-To: freebsd-bugs@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 28F82149; Tue, 7 May 2013 07:26:18 +0000 (UTC) (envelope-from melanhit@gmail.com) Received: from mail-la0-x229.google.com (mail-la0-x229.google.com [IPv6:2a00:1450:4010:c03::229]) by mx1.freebsd.org (Postfix) with ESMTP id 2EA7D3EA; Tue, 7 May 2013 07:26:16 +0000 (UTC) Received: by mail-la0-f41.google.com with SMTP id fn20so237942lab.0 for ; Tue, 07 May 2013 00:26:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:message-id:date:from:user-agent:mime-version:to:cc :subject:references:in-reply-to:content-type; bh=1PTsYRjA6LJf4cmxUQCY7ee4Hy+zgzOXV+JcyJyHvkg=; b=XVtxTKVUeR5kEc1VFJO6ttfy3criowJpSBaQiEsHW6thwCrSjFaeJoqLMUrKphJNst WEl7YkFkLLOvkyA+cG6MKGdAw4Gx8RiZDAFH1GOPV7nUQOzBjWKuCGitQ7TRtC7rgCM4 HXlSsGOrBKe8e2iH/u4IoQPNBe8vR2ZV6FglkWRrE1hrLRgHFdsdjjP8Xs6ewPdnFjYn 2SqXwh1MiYwvgI2CvNr5THUFpe+P32v6wag7m0f+o5pXLHf6rbKyK/ALPHtJ+CRPHzYM prKWMWmyUGHhU+V45Ejad2vdcDcS1WkAylAgtGZlntSdg8twXAOAE5thtWhkuXdLmjqI r1Cw== X-Received: by 10.112.171.7 with SMTP id aq7mr498462lbc.130.1367911576116; Tue, 07 May 2013 00:26:16 -0700 (PDT) Received: from localhost.localdomain (95-109-241-26.dialup.umc.net.ua. [95.109.241.26]) by mx.google.com with ESMTPSA id r9sm9787095lbr.3.2013.05.07.00.26.03 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 07 May 2013 00:26:15 -0700 (PDT) Message-ID: <5188AC8F.8070900@gmail.com> Date: Tue, 07 May 2013 10:26:07 +0300 From: Andrew Romanenko User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130407 Thunderbird/17.0.5 MIME-Version: 1.0 To: Scot Hetzel Subject: Re: kern/178359: [geom] [patch] geom_eli: support external metadata References: <201305060054.r460sVBh004810@freefall.freebsd.org> In-Reply-To: Content-Type: multipart/mixed; boundary="------------070201020602040305050702" Cc: freebsd-bugs@freebsd.org, freebsd-geom@freebsd.org X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 07 May 2013 07:26:18 -0000 This is a multi-part message in MIME format. --------------070201020602040305050702 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit On 05/06/2013 07:32 AM, Scot Hetzel wrote: > On Sun, May 5, 2013 at 10:51 PM, Scot Hetzel wrote: >> On Sun, May 5, 2013 at 7:54 PM, 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 --------------070201020602040305050702 Content-Type: text/x-patch; name="geli.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="geli.patch" --- 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) --------------070201020602040305050702--