--- 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);