>Number:         178359
>Category:       kern
>Synopsis:       geom_eli: support external metadata
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun May 05 23:10:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Andrew Romanenko
>Release:        FreeBSD 9.1-STABLE i386
>Organization:
UA BSD
>Environment:
System: FreeBSD ion.uabsd.org 9.1-STABLE FreeBSD 9.1-STABLE #0 r250121: Wed May 
1 23:38:36 EEST 2013 [email protected]:/usr/obj/usr/src/sys/GENERIC i386


        
>Description:
        Add support external metadata for geom eli.
        For i386 all works fine.
        Need check manpage for grammatical errors (i don't spell english very 
well)
>How-To-Repeat:
        
>Fix:

        

--- geli.patch begins here ---
--- 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);
--- geli.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to