diff options
-rw-r--r-- | sbin/geom/class/eli/geli.8 | 19 | ||||
-rw-r--r-- | sbin/geom/class/eli/geom_eli.c | 70 | ||||
-rw-r--r-- | sys/geom/eli/g_eli.h | 8 | ||||
-rw-r--r-- | sys/geom/eli/g_eli_ctl.c | 111 |
4 files changed, 204 insertions, 4 deletions
diff --git a/sbin/geom/class/eli/geli.8 b/sbin/geom/class/eli/geli.8 index 580b6e0..c2d588d 100644 --- a/sbin/geom/class/eli/geli.8 +++ b/sbin/geom/class/eli/geli.8 @@ -83,6 +83,10 @@ utility: .Op Fl s Ar sectorsize .Ar prov ... .Nm +.Cm configure +.Op Fl bB +.Ar prov ... +.Nm .Cm setkey .Op Fl pPv .Op Fl i Ar iterations @@ -196,7 +200,7 @@ Allows to verify data integrity (data authentication). The first argument to .Nm indicates an action to be performed: -.Bl -tag -width ".Cm onetime" +.Bl -tag -width ".Cm configure" .It Cm init Initialize provider which needs to be encrypted. Here you can set up the cryptographic algorithm to use, key length, etc. @@ -351,6 +355,19 @@ For more information, see the description of the .Cm init subcommand. .El +.It Cm configure +Change configuration of the given providers. +.Pp +Additional options include: +.Bl -tag -width ".Fl b" +.It Fl b +Set the BOOT flag on the given providers. +For more information, see the description of the +.Cm init +subcommand. +.It Fl B +Remove the BOOT flag from the given providers. +.El .It Cm setkey Change or setup (if not yet initialized) selected key. There is one master key, which can be encrypted with two independent user keys. diff --git a/sbin/geom/class/eli/geom_eli.c b/sbin/geom/class/eli/geom_eli.c index 3da4e83..0a82ccd 100644 --- a/sbin/geom/class/eli/geom_eli.c +++ b/sbin/geom/class/eli/geom_eli.c @@ -65,6 +65,7 @@ static char keyfile[] = "", newkeyfile[] = ""; 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); +static void eli_configure(struct gctl_req *req); static void eli_setkey(struct gctl_req *req); static void eli_delkey(struct gctl_req *req); static void eli_kill(struct gctl_req *req); @@ -82,6 +83,7 @@ static void eli_dump(struct gctl_req *req); * detach [-fl] prov ... * stop - alias for 'detach' * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ... + * configure [-bB] prov ... * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov * delkey [-afv] [-n keyno] prov * kill [-av] [prov ...] @@ -156,6 +158,14 @@ struct g_command class_commands[] = { }, "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..." }, + { "configure", G_FLAG_VERBOSE, eli_main, + { + { 'b', "boot", NULL, G_TYPE_NONE }, + { 'B', "noboot", NULL, G_TYPE_NONE }, + G_OPT_SENTINEL + }, + "[-bB] prov ..." + }, { "setkey", G_FLAG_VERBOSE, eli_main, { { 'i', "iterations", &iterations, G_TYPE_NUMBER }, @@ -242,6 +252,8 @@ eli_main(struct gctl_req *req, unsigned flags) eli_init(req); else if (strcmp(name, "attach") == 0) eli_attach(req); + else if (strcmp(name, "configure") == 0) + eli_configure(req); else if (strcmp(name, "setkey") == 0) eli_setkey(req); else if (strcmp(name, "delkey") == 0) @@ -666,6 +678,64 @@ eli_attach(struct gctl_req *req) } static void +eli_configure_detached(struct gctl_req *req, const char *prov, int boot) +{ + struct g_eli_metadata md; + + if (eli_metadata_read(req, prov, &md) == -1) + return; + + if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { + if (verbose) + printf("BOOT flag already configured for %s.\n", prov); + } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { + if (verbose) + printf("BOOT flag not configured for %s.\n", prov); + } else { + if (boot) + md.md_flags |= G_ELI_FLAG_BOOT; + else + md.md_flags &= ~G_ELI_FLAG_BOOT; + eli_metadata_store(req, prov, &md); + } + bzero(&md, sizeof(md)); +} + +static void +eli_configure(struct gctl_req *req) +{ + const char *prov; + int i, nargs, boot, noboot; + + nargs = gctl_get_int(req, "nargs"); + if (nargs == 0) { + gctl_error(req, "Too few arguments."); + return; + } + + boot = gctl_get_int(req, "boot"); + noboot = gctl_get_int(req, "noboot"); + + if (boot && noboot) { + gctl_error(req, "Options -b and -B are mutually exclusive."); + return; + } + if (!boot && !noboot) { + gctl_error(req, "No option given."); + return; + } + + /* First attached providers. */ + 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 eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) { unsigned char key[G_ELI_USERKEYLEN]; diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h index e24f314..5460eea 100644 --- a/sys/geom/eli/g_eli.h +++ b/sys/geom/eli/g_eli.h @@ -59,8 +59,9 @@ * 2 - Added G_ELI_FLAG_READONLY. * - IV is generated from offset converted to little-endian * (flag G_ELI_FLAG_NATIVE_BYTE_ORDER will be set for older versions). + * 3 - Added 'configure' subcommand. */ -#define G_ELI_VERSION 2 +#define G_ELI_VERSION 3 /* ON DISK FLAGS. */ /* Use random, onetime keys. */ @@ -228,7 +229,7 @@ eli_metadata_decode_v0(const u_char *data, struct g_eli_metadata *md) return (0); } static __inline int -eli_metadata_decode_v1v2(const u_char *data, struct g_eli_metadata *md) +eli_metadata_decode_v1v2v3(const u_char *data, struct g_eli_metadata *md) { MD5_CTX ctx; const u_char *p; @@ -264,7 +265,8 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md) break; case 1: case 2: - error = eli_metadata_decode_v1v2(data, md); + case 3: + error = eli_metadata_decode_v1v2v3(data, md); break; default: error = EINVAL; diff --git a/sys/geom/eli/g_eli_ctl.c b/sys/geom/eli/g_eli_ctl.c index e420af3..a788ba2 100644 --- a/sys/geom/eli/g_eli_ctl.c +++ b/sys/geom/eli/g_eli_ctl.c @@ -364,6 +364,115 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) } static void +g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) +{ + struct g_eli_softc *sc; + struct g_eli_metadata md; + struct g_provider *pp; + struct g_consumer *cp; + char param[16]; + const char *prov; + u_char *sector; + int *nargs, *boot, *noboot; + int error; + u_int i; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument.", "nargs"); + return; + } + if (*nargs <= 0) { + gctl_error(req, "Missing device(s)."); + return; + } + + boot = gctl_get_paraml(req, "boot", sizeof(*boot)); + if (boot == NULL) { + gctl_error(req, "No '%s' argument.", "boot"); + return; + } + noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot)); + if (noboot == NULL) { + gctl_error(req, "No '%s' argument.", "noboot"); + return; + } + if (*boot && *noboot) { + gctl_error(req, "Options -b and -B are mutually exclusive."); + return; + } + if (!*boot && !*noboot) { + gctl_error(req, "No option given."); + return; + } + + for (i = 0; i < *nargs; i++) { + snprintf(param, sizeof(param), "arg%d", i); + prov = gctl_get_asciiparam(req, param); + if (prov == NULL) { + gctl_error(req, "No 'arg%d' argument.", i); + return; + } + sc = g_eli_find_device(mp, prov); + if (sc == NULL) { + /* + * We ignore not attached providers, userland part will + * take care of them. + */ + G_ELI_DEBUG(1, "Skipping configuration of not attached " + "provider %s.", prov); + continue; + } + if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) { + G_ELI_DEBUG(1, "BOOT flag already configured for %s.", + prov); + continue; + } else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) { + G_ELI_DEBUG(1, "BOOT flag not configured for %s.", + prov); + continue; + } + if (sc->sc_flags & G_ELI_FLAG_RO) { + gctl_error(req, "Cannot change configuration of " + "read-only provider %s.", prov); + continue; + } + 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).", + prov, error); + continue; + } + + if (*boot) { + md.md_flags |= G_ELI_FLAG_BOOT; + sc->sc_flags |= G_ELI_FLAG_BOOT; + } else { + md.md_flags &= ~G_ELI_FLAG_BOOT; + sc->sc_flags &= ~G_ELI_FLAG_BOOT; + } + + 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); + if (error != 0) { + gctl_error(req, + "Cannot store metadata on %s (error=%d).", + prov, error); + } + bzero(&md, sizeof(md)); + bzero(sector, sizeof(sector)); + free(sector, M_ELI); + } +} + +static void g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp) { struct g_eli_softc *sc; @@ -710,6 +819,8 @@ g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb) g_eli_ctl_detach(req, mp); else if (strcmp(verb, "onetime") == 0) g_eli_ctl_onetime(req, mp); + else if (strcmp(verb, "configure") == 0) + g_eli_ctl_configure(req, mp); else if (strcmp(verb, "setkey") == 0) g_eli_ctl_setkey(req, mp); else if (strcmp(verb, "delkey") == 0) |