1c58794deSPawel Jakub Dawidek /*- 21e09ff3dSPawel Jakub Dawidek * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net> 3c58794deSPawel Jakub Dawidek * All rights reserved. 4c58794deSPawel Jakub Dawidek * 5c58794deSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 6c58794deSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 7c58794deSPawel Jakub Dawidek * are met: 8c58794deSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 9c58794deSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 10c58794deSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 11c58794deSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 12c58794deSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 13c58794deSPawel Jakub Dawidek * 14c58794deSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15c58794deSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c58794deSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c58794deSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18c58794deSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c58794deSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c58794deSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c58794deSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c58794deSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c58794deSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c58794deSPawel Jakub Dawidek * SUCH DAMAGE. 25c58794deSPawel Jakub Dawidek */ 26c58794deSPawel Jakub Dawidek 27c58794deSPawel Jakub Dawidek #include <sys/cdefs.h> 28c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 29c58794deSPawel Jakub Dawidek 30c58794deSPawel Jakub Dawidek #include <sys/param.h> 31c58794deSPawel Jakub Dawidek #include <sys/systm.h> 32c58794deSPawel Jakub Dawidek #include <sys/kernel.h> 33c58794deSPawel Jakub Dawidek #include <sys/module.h> 34c58794deSPawel Jakub Dawidek #include <sys/lock.h> 35c58794deSPawel Jakub Dawidek #include <sys/mutex.h> 36c58794deSPawel Jakub Dawidek #include <sys/bio.h> 37c58794deSPawel Jakub Dawidek #include <sys/sysctl.h> 38c58794deSPawel Jakub Dawidek #include <sys/malloc.h> 39c58794deSPawel Jakub Dawidek #include <sys/kthread.h> 40c58794deSPawel Jakub Dawidek #include <sys/proc.h> 41c58794deSPawel Jakub Dawidek #include <sys/sched.h> 42c58794deSPawel Jakub Dawidek #include <sys/uio.h> 43c58794deSPawel Jakub Dawidek 44c58794deSPawel Jakub Dawidek #include <vm/uma.h> 45c58794deSPawel Jakub Dawidek 46c58794deSPawel Jakub Dawidek #include <geom/geom.h> 47c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h> 48c58794deSPawel Jakub Dawidek 49c58794deSPawel Jakub Dawidek 50c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI); 51c58794deSPawel Jakub Dawidek 52c58794deSPawel Jakub Dawidek 53c58794deSPawel Jakub Dawidek static void 54c58794deSPawel Jakub Dawidek g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) 55c58794deSPawel Jakub Dawidek { 56c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 57c58794deSPawel Jakub Dawidek struct g_provider *pp; 58c58794deSPawel Jakub Dawidek const char *name; 59c58794deSPawel Jakub Dawidek u_char *key, mkey[G_ELI_DATAIVKEYLEN]; 6085059016SPawel Jakub Dawidek int *nargs, *detach, *readonly; 61c58794deSPawel Jakub Dawidek int keysize, error; 62c58794deSPawel Jakub Dawidek u_int nkey; 63c58794deSPawel Jakub Dawidek 64c58794deSPawel Jakub Dawidek g_topology_assert(); 65c58794deSPawel Jakub Dawidek 66c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 67c58794deSPawel Jakub Dawidek if (nargs == NULL) { 68c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 69c58794deSPawel Jakub Dawidek return; 70c58794deSPawel Jakub Dawidek } 71c58794deSPawel Jakub Dawidek if (*nargs != 1) { 72c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 73c58794deSPawel Jakub Dawidek return; 74c58794deSPawel Jakub Dawidek } 75c58794deSPawel Jakub Dawidek 76c58794deSPawel Jakub Dawidek detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 77c58794deSPawel Jakub Dawidek if (detach == NULL) { 78c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "detach"); 79c58794deSPawel Jakub Dawidek return; 80c58794deSPawel Jakub Dawidek } 81c58794deSPawel Jakub Dawidek 8285059016SPawel Jakub Dawidek readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly)); 8385059016SPawel Jakub Dawidek if (readonly == NULL) { 8485059016SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "readonly"); 8585059016SPawel Jakub Dawidek return; 8685059016SPawel Jakub Dawidek } 8785059016SPawel Jakub Dawidek 88c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 89c58794deSPawel Jakub Dawidek if (name == NULL) { 90c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 91c58794deSPawel Jakub Dawidek return; 92c58794deSPawel Jakub Dawidek } 93c58794deSPawel Jakub Dawidek if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 94c58794deSPawel Jakub Dawidek name += strlen("/dev/"); 95c58794deSPawel Jakub Dawidek pp = g_provider_by_name(name); 96c58794deSPawel Jakub Dawidek if (pp == NULL) { 97c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 98c58794deSPawel Jakub Dawidek return; 99c58794deSPawel Jakub Dawidek } 100c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 101c58794deSPawel Jakub Dawidek if (error != 0) { 102c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 103c58794deSPawel Jakub Dawidek name, error); 104c58794deSPawel Jakub Dawidek return; 105c58794deSPawel Jakub Dawidek } 106c58794deSPawel Jakub Dawidek if (md.md_keys == 0x00) { 107c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 108c58794deSPawel Jakub Dawidek gctl_error(req, "No valid keys on %s.", pp->name); 109c58794deSPawel Jakub Dawidek return; 110c58794deSPawel Jakub Dawidek } 111c58794deSPawel Jakub Dawidek 112c58794deSPawel Jakub Dawidek key = gctl_get_param(req, "key", &keysize); 113c58794deSPawel Jakub Dawidek if (key == NULL || keysize != G_ELI_USERKEYLEN) { 114c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 115c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "key"); 116c58794deSPawel Jakub Dawidek return; 117c58794deSPawel Jakub Dawidek } 118c58794deSPawel Jakub Dawidek 119c58794deSPawel Jakub Dawidek error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); 120c58794deSPawel Jakub Dawidek bzero(key, keysize); 121c58794deSPawel Jakub Dawidek if (error == -1) { 122c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 123c58794deSPawel Jakub Dawidek gctl_error(req, "Wrong key for %s.", pp->name); 124c58794deSPawel Jakub Dawidek return; 125c58794deSPawel Jakub Dawidek } else if (error > 0) { 126c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 127c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).", 128c58794deSPawel Jakub Dawidek pp->name, error); 129c58794deSPawel Jakub Dawidek return; 130c58794deSPawel Jakub Dawidek } 131c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); 132c58794deSPawel Jakub Dawidek 13385059016SPawel Jakub Dawidek if (*detach && *readonly) { 13485059016SPawel Jakub Dawidek bzero(&md, sizeof(md)); 135dec53cddSPawel Jakub Dawidek gctl_error(req, "Options -d and -r are mutually exclusive."); 13685059016SPawel Jakub Dawidek return; 13785059016SPawel Jakub Dawidek } 138c58794deSPawel Jakub Dawidek if (*detach) 139c58794deSPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_WO_DETACH; 14085059016SPawel Jakub Dawidek if (*readonly) 14185059016SPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_RO; 142c58794deSPawel Jakub Dawidek g_eli_create(req, mp, pp, &md, mkey, nkey); 143c58794deSPawel Jakub Dawidek bzero(mkey, sizeof(mkey)); 144c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 145c58794deSPawel Jakub Dawidek } 146c58794deSPawel Jakub Dawidek 147c58794deSPawel Jakub Dawidek static struct g_eli_softc * 148c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov) 149c58794deSPawel Jakub Dawidek { 150c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 151c58794deSPawel Jakub Dawidek struct g_geom *gp; 152c58794deSPawel Jakub Dawidek struct g_provider *pp; 153c58794deSPawel Jakub Dawidek struct g_consumer *cp; 154c58794deSPawel Jakub Dawidek 155c58794deSPawel Jakub Dawidek if (strncmp(prov, "/dev/", strlen("/dev/")) == 0) 156c58794deSPawel Jakub Dawidek prov += strlen("/dev/"); 157c58794deSPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 158c58794deSPawel Jakub Dawidek sc = gp->softc; 159c58794deSPawel Jakub Dawidek if (sc == NULL) 160c58794deSPawel Jakub Dawidek continue; 161c58794deSPawel Jakub Dawidek pp = LIST_FIRST(&gp->provider); 162c58794deSPawel Jakub Dawidek if (pp != NULL && strcmp(pp->name, prov) == 0) 163c58794deSPawel Jakub Dawidek return (sc); 164c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&gp->consumer); 165c58794deSPawel Jakub Dawidek if (cp != NULL && cp->provider != NULL && 166c58794deSPawel Jakub Dawidek strcmp(cp->provider->name, prov) == 0) { 167c58794deSPawel Jakub Dawidek return (sc); 168c58794deSPawel Jakub Dawidek } 169c58794deSPawel Jakub Dawidek } 170c58794deSPawel Jakub Dawidek return (NULL); 171c58794deSPawel Jakub Dawidek } 172c58794deSPawel Jakub Dawidek 173c58794deSPawel Jakub Dawidek static void 174c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp) 175c58794deSPawel Jakub Dawidek { 176c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 177c58794deSPawel Jakub Dawidek int *force, *last, *nargs, error; 178c58794deSPawel Jakub Dawidek const char *prov; 179c58794deSPawel Jakub Dawidek char param[16]; 1807d54b385SPawel Jakub Dawidek int i; 181c58794deSPawel Jakub Dawidek 182c58794deSPawel Jakub Dawidek g_topology_assert(); 183c58794deSPawel Jakub Dawidek 184c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 185c58794deSPawel Jakub Dawidek if (nargs == NULL) { 186c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 187c58794deSPawel Jakub Dawidek return; 188c58794deSPawel Jakub Dawidek } 189c58794deSPawel Jakub Dawidek if (*nargs <= 0) { 190c58794deSPawel Jakub Dawidek gctl_error(req, "Missing device(s)."); 191c58794deSPawel Jakub Dawidek return; 192c58794deSPawel Jakub Dawidek } 193c58794deSPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force)); 194c58794deSPawel Jakub Dawidek if (force == NULL) { 195c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force"); 196c58794deSPawel Jakub Dawidek return; 197c58794deSPawel Jakub Dawidek } 198c58794deSPawel Jakub Dawidek last = gctl_get_paraml(req, "last", sizeof(*last)); 199c58794deSPawel Jakub Dawidek if (last == NULL) { 200c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "last"); 201c58794deSPawel Jakub Dawidek return; 202c58794deSPawel Jakub Dawidek } 203c58794deSPawel Jakub Dawidek 2047d54b385SPawel Jakub Dawidek for (i = 0; i < *nargs; i++) { 2057d54b385SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%d", i); 206c58794deSPawel Jakub Dawidek prov = gctl_get_asciiparam(req, param); 207c58794deSPawel Jakub Dawidek if (prov == NULL) { 2087d54b385SPawel Jakub Dawidek gctl_error(req, "No 'arg%d' argument.", i); 209c58794deSPawel Jakub Dawidek return; 210c58794deSPawel Jakub Dawidek } 211c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, prov); 212c58794deSPawel Jakub Dawidek if (sc == NULL) { 213c58794deSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", prov); 214c58794deSPawel Jakub Dawidek return; 215c58794deSPawel Jakub Dawidek } 216c58794deSPawel Jakub Dawidek if (*last) { 217c58794deSPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_RW_DETACH; 218c58794deSPawel Jakub Dawidek sc->sc_geom->access = g_eli_access; 219c58794deSPawel Jakub Dawidek } else { 2205ad4a7c7SPawel Jakub Dawidek error = g_eli_destroy(sc, *force ? TRUE : FALSE); 221c58794deSPawel Jakub Dawidek if (error != 0) { 222c58794deSPawel Jakub Dawidek gctl_error(req, 223c58794deSPawel Jakub Dawidek "Cannot destroy device %s (error=%d).", 224c58794deSPawel Jakub Dawidek sc->sc_name, error); 225c58794deSPawel Jakub Dawidek return; 226c58794deSPawel Jakub Dawidek } 227c58794deSPawel Jakub Dawidek } 228c58794deSPawel Jakub Dawidek } 229c58794deSPawel Jakub Dawidek } 230c58794deSPawel Jakub Dawidek 231c58794deSPawel Jakub Dawidek static void 232c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) 233c58794deSPawel Jakub Dawidek { 234c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 235c58794deSPawel Jakub Dawidek struct g_provider *pp; 236c58794deSPawel Jakub Dawidek const char *name; 237c58794deSPawel Jakub Dawidek intmax_t *keylen, *sectorsize; 238c58794deSPawel Jakub Dawidek u_char mkey[G_ELI_DATAIVKEYLEN]; 23946e34470SPawel Jakub Dawidek int *nargs, *detach, *notrim; 240c58794deSPawel Jakub Dawidek 241c58794deSPawel Jakub Dawidek g_topology_assert(); 242c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 243c58794deSPawel Jakub Dawidek 244c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 245c58794deSPawel Jakub Dawidek if (nargs == NULL) { 246c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 247c58794deSPawel Jakub Dawidek return; 248c58794deSPawel Jakub Dawidek } 249c58794deSPawel Jakub Dawidek if (*nargs != 1) { 250c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 251c58794deSPawel Jakub Dawidek return; 252c58794deSPawel Jakub Dawidek } 253c58794deSPawel Jakub Dawidek 254c58794deSPawel Jakub Dawidek strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 255c58794deSPawel Jakub Dawidek md.md_version = G_ELI_VERSION; 256c58794deSPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_ONETIME; 25746e34470SPawel Jakub Dawidek 25846e34470SPawel Jakub Dawidek detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 25946e34470SPawel Jakub Dawidek if (detach != NULL && *detach) 260c58794deSPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_WO_DETACH; 26146e34470SPawel Jakub Dawidek notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim)); 26246e34470SPawel Jakub Dawidek if (notrim != NULL && *notrim) 26346e34470SPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_NODELETE; 264c58794deSPawel Jakub Dawidek 265c84efdcaSPawel Jakub Dawidek md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 266eaa3b919SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "aalgo"); 267c58794deSPawel Jakub Dawidek if (name == NULL) { 268eaa3b919SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "aalgo"); 269c58794deSPawel Jakub Dawidek return; 270c58794deSPawel Jakub Dawidek } 271a478ea74SPawel Jakub Dawidek if (*name != '\0') { 272eaa3b919SPawel Jakub Dawidek md.md_aalgo = g_eli_str2aalgo(name); 273c84efdcaSPawel Jakub Dawidek if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 274c84efdcaSPawel Jakub Dawidek md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 275eaa3b919SPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_AUTH; 276c84efdcaSPawel Jakub Dawidek } else { 277c84efdcaSPawel Jakub Dawidek /* 278c84efdcaSPawel Jakub Dawidek * For backward compatibility, check if the -a option 279c84efdcaSPawel Jakub Dawidek * was used to provide encryption algorithm. 280c84efdcaSPawel Jakub Dawidek */ 281c84efdcaSPawel Jakub Dawidek md.md_ealgo = g_eli_str2ealgo(name); 282c84efdcaSPawel Jakub Dawidek if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 283c84efdcaSPawel Jakub Dawidek md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 284c84efdcaSPawel Jakub Dawidek gctl_error(req, 285c84efdcaSPawel Jakub Dawidek "Invalid authentication algorithm."); 286c84efdcaSPawel Jakub Dawidek return; 287c84efdcaSPawel Jakub Dawidek } else { 288c84efdcaSPawel Jakub Dawidek gctl_error(req, "warning: The -e option, not " 289c84efdcaSPawel Jakub Dawidek "the -a option is now used to specify " 290c84efdcaSPawel Jakub Dawidek "encryption algorithm to use."); 291c84efdcaSPawel Jakub Dawidek } 292c84efdcaSPawel Jakub Dawidek } 293eaa3b919SPawel Jakub Dawidek } 294eaa3b919SPawel Jakub Dawidek 295c84efdcaSPawel Jakub Dawidek if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 296c84efdcaSPawel Jakub Dawidek md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 297eaa3b919SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "ealgo"); 298eaa3b919SPawel Jakub Dawidek if (name == NULL) { 299eaa3b919SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "ealgo"); 300eaa3b919SPawel Jakub Dawidek return; 301eaa3b919SPawel Jakub Dawidek } 302eaa3b919SPawel Jakub Dawidek md.md_ealgo = g_eli_str2ealgo(name); 303eaa3b919SPawel Jakub Dawidek if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 304eaa3b919SPawel Jakub Dawidek md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 305eaa3b919SPawel Jakub Dawidek gctl_error(req, "Invalid encryption algorithm."); 306c58794deSPawel Jakub Dawidek return; 307c58794deSPawel Jakub Dawidek } 308c84efdcaSPawel Jakub Dawidek } 309c58794deSPawel Jakub Dawidek 310c58794deSPawel Jakub Dawidek keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen)); 311c58794deSPawel Jakub Dawidek if (keylen == NULL) { 312c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "keylen"); 313c58794deSPawel Jakub Dawidek return; 314c58794deSPawel Jakub Dawidek } 315eaa3b919SPawel Jakub Dawidek md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen); 316c58794deSPawel Jakub Dawidek if (md.md_keylen == 0) { 317c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "keylen"); 318c58794deSPawel Jakub Dawidek return; 319c58794deSPawel Jakub Dawidek } 320c58794deSPawel Jakub Dawidek 321c58794deSPawel Jakub Dawidek /* Not important here. */ 322c58794deSPawel Jakub Dawidek md.md_provsize = 0; 323c58794deSPawel Jakub Dawidek /* Not important here. */ 324c58794deSPawel Jakub Dawidek bzero(md.md_salt, sizeof(md.md_salt)); 325c58794deSPawel Jakub Dawidek 326c58794deSPawel Jakub Dawidek md.md_keys = 0x01; 327c58794deSPawel Jakub Dawidek arc4rand(mkey, sizeof(mkey), 0); 328c58794deSPawel Jakub Dawidek 329c58794deSPawel Jakub Dawidek /* Not important here. */ 330c58794deSPawel Jakub Dawidek bzero(md.md_hash, sizeof(md.md_hash)); 331c58794deSPawel Jakub Dawidek 332c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 333c58794deSPawel Jakub Dawidek if (name == NULL) { 334c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 335c58794deSPawel Jakub Dawidek return; 336c58794deSPawel Jakub Dawidek } 337c58794deSPawel Jakub Dawidek if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 338c58794deSPawel Jakub Dawidek name += strlen("/dev/"); 339c58794deSPawel Jakub Dawidek pp = g_provider_by_name(name); 340c58794deSPawel Jakub Dawidek if (pp == NULL) { 341c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 342c58794deSPawel Jakub Dawidek return; 343c58794deSPawel Jakub Dawidek } 344c58794deSPawel Jakub Dawidek 345c58794deSPawel Jakub Dawidek sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize)); 346c58794deSPawel Jakub Dawidek if (sectorsize == NULL) { 347c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "sectorsize"); 348c58794deSPawel Jakub Dawidek return; 349c58794deSPawel Jakub Dawidek } 350c58794deSPawel Jakub Dawidek if (*sectorsize == 0) 351c58794deSPawel Jakub Dawidek md.md_sectorsize = pp->sectorsize; 352c58794deSPawel Jakub Dawidek else { 353c58794deSPawel Jakub Dawidek if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) { 354c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid sector size."); 355c58794deSPawel Jakub Dawidek return; 356c58794deSPawel Jakub Dawidek } 35797a669a3SPawel Jakub Dawidek if (*sectorsize > PAGE_SIZE) { 35897a669a3SPawel Jakub Dawidek gctl_error(req, "warning: Using sectorsize bigger than " 35997a669a3SPawel Jakub Dawidek "the page size!"); 36097a669a3SPawel Jakub Dawidek } 361c58794deSPawel Jakub Dawidek md.md_sectorsize = *sectorsize; 362c58794deSPawel Jakub Dawidek } 363c58794deSPawel Jakub Dawidek 364c58794deSPawel Jakub Dawidek g_eli_create(req, mp, pp, &md, mkey, -1); 365c58794deSPawel Jakub Dawidek bzero(mkey, sizeof(mkey)); 366c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 367c58794deSPawel Jakub Dawidek } 368c58794deSPawel Jakub Dawidek 369c58794deSPawel Jakub Dawidek static void 3708abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) 3718abd1ad1SPawel Jakub Dawidek { 3728abd1ad1SPawel Jakub Dawidek struct g_eli_softc *sc; 3738abd1ad1SPawel Jakub Dawidek struct g_eli_metadata md; 3748abd1ad1SPawel Jakub Dawidek struct g_provider *pp; 3758abd1ad1SPawel Jakub Dawidek struct g_consumer *cp; 3768abd1ad1SPawel Jakub Dawidek char param[16]; 3778abd1ad1SPawel Jakub Dawidek const char *prov; 3788abd1ad1SPawel Jakub Dawidek u_char *sector; 379*d8736625SAllan Jude int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot; 38046e34470SPawel Jakub Dawidek int zero, error, changed; 3818abd1ad1SPawel Jakub Dawidek u_int i; 3828abd1ad1SPawel Jakub Dawidek 3838abd1ad1SPawel Jakub Dawidek g_topology_assert(); 3848abd1ad1SPawel Jakub Dawidek 38546e34470SPawel Jakub Dawidek changed = 0; 38646e34470SPawel Jakub Dawidek zero = 0; 38746e34470SPawel Jakub Dawidek 3888abd1ad1SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 3898abd1ad1SPawel Jakub Dawidek if (nargs == NULL) { 3908abd1ad1SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 3918abd1ad1SPawel Jakub Dawidek return; 3928abd1ad1SPawel Jakub Dawidek } 3938abd1ad1SPawel Jakub Dawidek if (*nargs <= 0) { 3948abd1ad1SPawel Jakub Dawidek gctl_error(req, "Missing device(s)."); 3958abd1ad1SPawel Jakub Dawidek return; 3968abd1ad1SPawel Jakub Dawidek } 3978abd1ad1SPawel Jakub Dawidek 3988abd1ad1SPawel Jakub Dawidek boot = gctl_get_paraml(req, "boot", sizeof(*boot)); 39946e34470SPawel Jakub Dawidek if (boot == NULL) 40046e34470SPawel Jakub Dawidek boot = &zero; 4018abd1ad1SPawel Jakub Dawidek noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot)); 40246e34470SPawel Jakub Dawidek if (noboot == NULL) 40346e34470SPawel Jakub Dawidek noboot = &zero; 4048abd1ad1SPawel Jakub Dawidek if (*boot && *noboot) { 4058abd1ad1SPawel Jakub Dawidek gctl_error(req, "Options -b and -B are mutually exclusive."); 4068abd1ad1SPawel Jakub Dawidek return; 4078abd1ad1SPawel Jakub Dawidek } 40846e34470SPawel Jakub Dawidek if (*boot || *noboot) 40946e34470SPawel Jakub Dawidek changed = 1; 41046e34470SPawel Jakub Dawidek 41146e34470SPawel Jakub Dawidek trim = gctl_get_paraml(req, "trim", sizeof(*trim)); 41246e34470SPawel Jakub Dawidek if (trim == NULL) 41346e34470SPawel Jakub Dawidek trim = &zero; 41446e34470SPawel Jakub Dawidek notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim)); 41546e34470SPawel Jakub Dawidek if (notrim == NULL) 41646e34470SPawel Jakub Dawidek notrim = &zero; 41746e34470SPawel Jakub Dawidek if (*trim && *notrim) { 41846e34470SPawel Jakub Dawidek gctl_error(req, "Options -t and -T are mutually exclusive."); 41946e34470SPawel Jakub Dawidek return; 42046e34470SPawel Jakub Dawidek } 42146e34470SPawel Jakub Dawidek if (*trim || *notrim) 42246e34470SPawel Jakub Dawidek changed = 1; 42346e34470SPawel Jakub Dawidek 424*d8736625SAllan Jude geliboot = gctl_get_paraml(req, "geliboot", sizeof(*geliboot)); 425*d8736625SAllan Jude if (geliboot == NULL) 426*d8736625SAllan Jude geliboot = &zero; 427*d8736625SAllan Jude nogeliboot = gctl_get_paraml(req, "nogeliboot", sizeof(*nogeliboot)); 428*d8736625SAllan Jude if (nogeliboot == NULL) 429*d8736625SAllan Jude nogeliboot = &zero; 430*d8736625SAllan Jude if (*geliboot && *nogeliboot) { 431*d8736625SAllan Jude gctl_error(req, "Options -g and -G are mutually exclusive."); 432*d8736625SAllan Jude return; 433*d8736625SAllan Jude } 434*d8736625SAllan Jude if (*geliboot || *nogeliboot) 435*d8736625SAllan Jude changed = 1; 436*d8736625SAllan Jude 43746e34470SPawel Jakub Dawidek if (!changed) { 4388abd1ad1SPawel Jakub Dawidek gctl_error(req, "No option given."); 4398abd1ad1SPawel Jakub Dawidek return; 4408abd1ad1SPawel Jakub Dawidek } 4418abd1ad1SPawel Jakub Dawidek 4428abd1ad1SPawel Jakub Dawidek for (i = 0; i < *nargs; i++) { 4438abd1ad1SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%d", i); 4448abd1ad1SPawel Jakub Dawidek prov = gctl_get_asciiparam(req, param); 4458abd1ad1SPawel Jakub Dawidek if (prov == NULL) { 4468abd1ad1SPawel Jakub Dawidek gctl_error(req, "No 'arg%d' argument.", i); 4478abd1ad1SPawel Jakub Dawidek return; 4488abd1ad1SPawel Jakub Dawidek } 4498abd1ad1SPawel Jakub Dawidek sc = g_eli_find_device(mp, prov); 4508abd1ad1SPawel Jakub Dawidek if (sc == NULL) { 4518abd1ad1SPawel Jakub Dawidek /* 4528abd1ad1SPawel Jakub Dawidek * We ignore not attached providers, userland part will 4538abd1ad1SPawel Jakub Dawidek * take care of them. 4548abd1ad1SPawel Jakub Dawidek */ 4558abd1ad1SPawel Jakub Dawidek G_ELI_DEBUG(1, "Skipping configuration of not attached " 4568abd1ad1SPawel Jakub Dawidek "provider %s.", prov); 4578abd1ad1SPawel Jakub Dawidek continue; 4588abd1ad1SPawel Jakub Dawidek } 4598abd1ad1SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_RO) { 4608abd1ad1SPawel Jakub Dawidek gctl_error(req, "Cannot change configuration of " 4618abd1ad1SPawel Jakub Dawidek "read-only provider %s.", prov); 4628abd1ad1SPawel Jakub Dawidek continue; 4638abd1ad1SPawel Jakub Dawidek } 46446e34470SPawel Jakub Dawidek 46546e34470SPawel Jakub Dawidek if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) { 46646e34470SPawel Jakub Dawidek G_ELI_DEBUG(1, "BOOT flag already configured for %s.", 46746e34470SPawel Jakub Dawidek prov); 46846e34470SPawel Jakub Dawidek continue; 46946e34470SPawel Jakub Dawidek } else if (*noboot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) { 47046e34470SPawel Jakub Dawidek G_ELI_DEBUG(1, "BOOT flag not configured for %s.", 47146e34470SPawel Jakub Dawidek prov); 47246e34470SPawel Jakub Dawidek continue; 47346e34470SPawel Jakub Dawidek } 47446e34470SPawel Jakub Dawidek 47546e34470SPawel Jakub Dawidek if (*notrim && (sc->sc_flags & G_ELI_FLAG_NODELETE)) { 47646e34470SPawel Jakub Dawidek G_ELI_DEBUG(1, "TRIM disable flag already configured for %s.", 47746e34470SPawel Jakub Dawidek prov); 47846e34470SPawel Jakub Dawidek continue; 47946e34470SPawel Jakub Dawidek } else if (*trim && !(sc->sc_flags & G_ELI_FLAG_NODELETE)) { 48046e34470SPawel Jakub Dawidek G_ELI_DEBUG(1, "TRIM disable flag not configured for %s.", 48146e34470SPawel Jakub Dawidek prov); 48246e34470SPawel Jakub Dawidek continue; 48346e34470SPawel Jakub Dawidek } 48446e34470SPawel Jakub Dawidek 485*d8736625SAllan Jude if (*geliboot && (sc->sc_flags & G_ELI_FLAG_GELIBOOT)) { 486*d8736625SAllan Jude G_ELI_DEBUG(1, "GELIBOOT flag already configured for %s.", 487*d8736625SAllan Jude prov); 488*d8736625SAllan Jude continue; 489*d8736625SAllan Jude } else if (*nogeliboot && !(sc->sc_flags & G_ELI_FLAG_GELIBOOT)) { 490*d8736625SAllan Jude G_ELI_DEBUG(1, "GELIBOOT flag not configured for %s.", 491*d8736625SAllan Jude prov); 492*d8736625SAllan Jude continue; 493*d8736625SAllan Jude } 494*d8736625SAllan Jude 49546e34470SPawel Jakub Dawidek if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) { 49646e34470SPawel Jakub Dawidek /* 49746e34470SPawel Jakub Dawidek * ONETIME providers don't write metadata to 49846e34470SPawel Jakub Dawidek * disk, so don't try reading it. This means 49946e34470SPawel Jakub Dawidek * we're bit-flipping uninitialized memory in md 50046e34470SPawel Jakub Dawidek * below, but that's OK; we don't do anything 50146e34470SPawel Jakub Dawidek * with it later. 50246e34470SPawel Jakub Dawidek */ 5038abd1ad1SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 5048abd1ad1SPawel Jakub Dawidek pp = cp->provider; 5058abd1ad1SPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 5068abd1ad1SPawel Jakub Dawidek if (error != 0) { 5078abd1ad1SPawel Jakub Dawidek gctl_error(req, 5088abd1ad1SPawel Jakub Dawidek "Cannot read metadata from %s (error=%d).", 5098abd1ad1SPawel Jakub Dawidek prov, error); 5108abd1ad1SPawel Jakub Dawidek continue; 5118abd1ad1SPawel Jakub Dawidek } 51246e34470SPawel Jakub Dawidek } 5138abd1ad1SPawel Jakub Dawidek 5148abd1ad1SPawel Jakub Dawidek if (*boot) { 5158abd1ad1SPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_BOOT; 5168abd1ad1SPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_BOOT; 51746e34470SPawel Jakub Dawidek } else if (*noboot) { 5188abd1ad1SPawel Jakub Dawidek md.md_flags &= ~G_ELI_FLAG_BOOT; 5198abd1ad1SPawel Jakub Dawidek sc->sc_flags &= ~G_ELI_FLAG_BOOT; 5208abd1ad1SPawel Jakub Dawidek } 5218abd1ad1SPawel Jakub Dawidek 52246e34470SPawel Jakub Dawidek if (*notrim) { 52346e34470SPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_NODELETE; 52446e34470SPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_NODELETE; 52546e34470SPawel Jakub Dawidek } else if (*trim) { 52646e34470SPawel Jakub Dawidek md.md_flags &= ~G_ELI_FLAG_NODELETE; 52746e34470SPawel Jakub Dawidek sc->sc_flags &= ~G_ELI_FLAG_NODELETE; 52846e34470SPawel Jakub Dawidek } 52946e34470SPawel Jakub Dawidek 530*d8736625SAllan Jude if (*geliboot) { 531*d8736625SAllan Jude md.md_flags |= G_ELI_FLAG_GELIBOOT; 532*d8736625SAllan Jude sc->sc_flags |= G_ELI_FLAG_GELIBOOT; 533*d8736625SAllan Jude } else if (*nogeliboot) { 534*d8736625SAllan Jude md.md_flags &= ~G_ELI_FLAG_GELIBOOT; 535*d8736625SAllan Jude sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT; 536*d8736625SAllan Jude } 537*d8736625SAllan Jude 53846e34470SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_ONETIME) { 53946e34470SPawel Jakub Dawidek /* There's no metadata on disk so we are done here. */ 54046e34470SPawel Jakub Dawidek continue; 54146e34470SPawel Jakub Dawidek } 54246e34470SPawel Jakub Dawidek 5438abd1ad1SPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 5448abd1ad1SPawel Jakub Dawidek eli_metadata_encode(&md, sector); 5458abd1ad1SPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 5468abd1ad1SPawel Jakub Dawidek pp->sectorsize); 5478abd1ad1SPawel Jakub Dawidek if (error != 0) { 5488abd1ad1SPawel Jakub Dawidek gctl_error(req, 5498abd1ad1SPawel Jakub Dawidek "Cannot store metadata on %s (error=%d).", 5508abd1ad1SPawel Jakub Dawidek prov, error); 5518abd1ad1SPawel Jakub Dawidek } 5528abd1ad1SPawel Jakub Dawidek bzero(&md, sizeof(md)); 5537ac2e588SXin LI bzero(sector, pp->sectorsize); 5548abd1ad1SPawel Jakub Dawidek free(sector, M_ELI); 5558abd1ad1SPawel Jakub Dawidek } 5568abd1ad1SPawel Jakub Dawidek } 5578abd1ad1SPawel Jakub Dawidek 5588abd1ad1SPawel Jakub Dawidek static void 559c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp) 560c58794deSPawel Jakub Dawidek { 561c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 562c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 563c58794deSPawel Jakub Dawidek struct g_provider *pp; 564c58794deSPawel Jakub Dawidek struct g_consumer *cp; 565c58794deSPawel Jakub Dawidek const char *name; 566c58794deSPawel Jakub Dawidek u_char *key, *mkeydst, *sector; 567c58794deSPawel Jakub Dawidek intmax_t *valp; 5687a5c26fcSPawel Jakub Dawidek int keysize, nkey, error; 569c58794deSPawel Jakub Dawidek 570c58794deSPawel Jakub Dawidek g_topology_assert(); 571c58794deSPawel Jakub Dawidek 572c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 573c58794deSPawel Jakub Dawidek if (name == NULL) { 574c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 575c58794deSPawel Jakub Dawidek return; 576c58794deSPawel Jakub Dawidek } 577c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, name); 578c58794deSPawel Jakub Dawidek if (sc == NULL) { 579c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 580c58794deSPawel Jakub Dawidek return; 581c58794deSPawel Jakub Dawidek } 58285059016SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_RO) { 58385059016SPawel Jakub Dawidek gctl_error(req, "Cannot change keys for read-only provider."); 58485059016SPawel Jakub Dawidek return; 58585059016SPawel Jakub Dawidek } 586c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 587c58794deSPawel Jakub Dawidek pp = cp->provider; 588c58794deSPawel Jakub Dawidek 589c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 590c58794deSPawel Jakub Dawidek if (error != 0) { 591c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 592c58794deSPawel Jakub Dawidek name, error); 593c58794deSPawel Jakub Dawidek return; 594c58794deSPawel Jakub Dawidek } 595c58794deSPawel Jakub Dawidek 596c58794deSPawel Jakub Dawidek valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 597c58794deSPawel Jakub Dawidek if (valp == NULL) { 598c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "keyno"); 599c58794deSPawel Jakub Dawidek return; 600c58794deSPawel Jakub Dawidek } 601c58794deSPawel Jakub Dawidek if (*valp != -1) 602c58794deSPawel Jakub Dawidek nkey = *valp; 603c58794deSPawel Jakub Dawidek else 604c58794deSPawel Jakub Dawidek nkey = sc->sc_nkey; 605c58794deSPawel Jakub Dawidek if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 606c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "keyno"); 607c58794deSPawel Jakub Dawidek return; 608c58794deSPawel Jakub Dawidek } 609c58794deSPawel Jakub Dawidek 6107a5c26fcSPawel Jakub Dawidek valp = gctl_get_paraml(req, "iterations", sizeof(*valp)); 6117a5c26fcSPawel Jakub Dawidek if (valp == NULL) { 6127a5c26fcSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "iterations"); 6137a5c26fcSPawel Jakub Dawidek return; 6147a5c26fcSPawel Jakub Dawidek } 6157a5c26fcSPawel Jakub Dawidek /* Check if iterations number should and can be changed. */ 6167a5c26fcSPawel Jakub Dawidek if (*valp != -1) { 6177a5c26fcSPawel Jakub Dawidek if (bitcount32(md.md_keys) != 1) { 6187a5c26fcSPawel Jakub Dawidek gctl_error(req, "To be able to use '-i' option, only " 6197a5c26fcSPawel Jakub Dawidek "one key can be defined."); 6207a5c26fcSPawel Jakub Dawidek return; 6217a5c26fcSPawel Jakub Dawidek } 6227a5c26fcSPawel Jakub Dawidek if (md.md_keys != (1 << nkey)) { 6237a5c26fcSPawel Jakub Dawidek gctl_error(req, "Only already defined key can be " 6247a5c26fcSPawel Jakub Dawidek "changed when '-i' option is used."); 6257a5c26fcSPawel Jakub Dawidek return; 6267a5c26fcSPawel Jakub Dawidek } 6277a5c26fcSPawel Jakub Dawidek md.md_iterations = *valp; 6287a5c26fcSPawel Jakub Dawidek } 6297a5c26fcSPawel Jakub Dawidek 630c58794deSPawel Jakub Dawidek key = gctl_get_param(req, "key", &keysize); 631c58794deSPawel Jakub Dawidek if (key == NULL || keysize != G_ELI_USERKEYLEN) { 632c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 633c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "key"); 634c58794deSPawel Jakub Dawidek return; 635c58794deSPawel Jakub Dawidek } 636c58794deSPawel Jakub Dawidek 637c58794deSPawel Jakub Dawidek mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 638c58794deSPawel Jakub Dawidek md.md_keys |= (1 << nkey); 639c58794deSPawel Jakub Dawidek 640eaa3b919SPawel Jakub Dawidek bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey)); 641c58794deSPawel Jakub Dawidek 642c58794deSPawel Jakub Dawidek /* Encrypt Master Key with the new key. */ 643eaa3b919SPawel Jakub Dawidek error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst); 6447ac2e588SXin LI bzero(key, keysize); 645c58794deSPawel Jakub Dawidek if (error != 0) { 646c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 647c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot encrypt Master Key (error=%d).", error); 648c58794deSPawel Jakub Dawidek return; 649c58794deSPawel Jakub Dawidek } 650c58794deSPawel Jakub Dawidek 651c58794deSPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 652c58794deSPawel Jakub Dawidek /* Store metadata with fresh key. */ 653c58794deSPawel Jakub Dawidek eli_metadata_encode(&md, sector); 654c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 655c58794deSPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 656c58794deSPawel Jakub Dawidek pp->sectorsize); 6577ac2e588SXin LI bzero(sector, pp->sectorsize); 658c58794deSPawel Jakub Dawidek free(sector, M_ELI); 659c58794deSPawel Jakub Dawidek if (error != 0) { 660c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot store metadata on %s (error=%d).", 661c58794deSPawel Jakub Dawidek pp->name, error); 662c58794deSPawel Jakub Dawidek return; 663c58794deSPawel Jakub Dawidek } 664c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name); 665c58794deSPawel Jakub Dawidek } 666c58794deSPawel Jakub Dawidek 667c58794deSPawel Jakub Dawidek static void 668c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) 669c58794deSPawel Jakub Dawidek { 670c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 671c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 672c58794deSPawel Jakub Dawidek struct g_provider *pp; 673c58794deSPawel Jakub Dawidek struct g_consumer *cp; 674c58794deSPawel Jakub Dawidek const char *name; 675c58794deSPawel Jakub Dawidek u_char *mkeydst, *sector; 676c58794deSPawel Jakub Dawidek intmax_t *valp; 677c58794deSPawel Jakub Dawidek size_t keysize; 678c58794deSPawel Jakub Dawidek int error, nkey, *all, *force; 679c58794deSPawel Jakub Dawidek u_int i; 680c58794deSPawel Jakub Dawidek 681c58794deSPawel Jakub Dawidek g_topology_assert(); 682c58794deSPawel Jakub Dawidek 683c58794deSPawel Jakub Dawidek nkey = 0; /* fixes causeless gcc warning */ 684c58794deSPawel Jakub Dawidek 685c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 686c58794deSPawel Jakub Dawidek if (name == NULL) { 687c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 688c58794deSPawel Jakub Dawidek return; 689c58794deSPawel Jakub Dawidek } 690c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, name); 691c58794deSPawel Jakub Dawidek if (sc == NULL) { 692c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 693c58794deSPawel Jakub Dawidek return; 694c58794deSPawel Jakub Dawidek } 69585059016SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_RO) { 69685059016SPawel Jakub Dawidek gctl_error(req, "Cannot delete keys for read-only provider."); 69785059016SPawel Jakub Dawidek return; 69885059016SPawel Jakub Dawidek } 699c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 700c58794deSPawel Jakub Dawidek pp = cp->provider; 701c58794deSPawel Jakub Dawidek 702c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 703c58794deSPawel Jakub Dawidek if (error != 0) { 704c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 705c58794deSPawel Jakub Dawidek name, error); 706c58794deSPawel Jakub Dawidek return; 707c58794deSPawel Jakub Dawidek } 708c58794deSPawel Jakub Dawidek 709c58794deSPawel Jakub Dawidek all = gctl_get_paraml(req, "all", sizeof(*all)); 710c58794deSPawel Jakub Dawidek if (all == NULL) { 711c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "all"); 712c58794deSPawel Jakub Dawidek return; 713c58794deSPawel Jakub Dawidek } 714c58794deSPawel Jakub Dawidek 715c58794deSPawel Jakub Dawidek if (*all) { 716c58794deSPawel Jakub Dawidek mkeydst = md.md_mkeys; 717c58794deSPawel Jakub Dawidek keysize = sizeof(md.md_mkeys); 718c58794deSPawel Jakub Dawidek } else { 719c58794deSPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force)); 720c58794deSPawel Jakub Dawidek if (force == NULL) { 721c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force"); 722c58794deSPawel Jakub Dawidek return; 723c58794deSPawel Jakub Dawidek } 724c58794deSPawel Jakub Dawidek 725c58794deSPawel Jakub Dawidek valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 726c58794deSPawel Jakub Dawidek if (valp == NULL) { 727c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "keyno"); 728c58794deSPawel Jakub Dawidek return; 729c58794deSPawel Jakub Dawidek } 730c58794deSPawel Jakub Dawidek if (*valp != -1) 731c58794deSPawel Jakub Dawidek nkey = *valp; 732c58794deSPawel Jakub Dawidek else 733c58794deSPawel Jakub Dawidek nkey = sc->sc_nkey; 734c58794deSPawel Jakub Dawidek if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 735c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "keyno"); 736c58794deSPawel Jakub Dawidek return; 737c58794deSPawel Jakub Dawidek } 738c58794deSPawel Jakub Dawidek if (!(md.md_keys & (1 << nkey)) && !*force) { 739c58794deSPawel Jakub Dawidek gctl_error(req, "Master Key %u is not set.", nkey); 740c58794deSPawel Jakub Dawidek return; 741c58794deSPawel Jakub Dawidek } 742c58794deSPawel Jakub Dawidek md.md_keys &= ~(1 << nkey); 743c58794deSPawel Jakub Dawidek if (md.md_keys == 0 && !*force) { 744c58794deSPawel Jakub Dawidek gctl_error(req, "This is the last Master Key. Use '-f' " 745c58794deSPawel Jakub Dawidek "flag if you really want to remove it."); 746c58794deSPawel Jakub Dawidek return; 747c58794deSPawel Jakub Dawidek } 748c58794deSPawel Jakub Dawidek mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 749c58794deSPawel Jakub Dawidek keysize = G_ELI_MKEYLEN; 750c58794deSPawel Jakub Dawidek } 751c58794deSPawel Jakub Dawidek 752c58794deSPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 753c58794deSPawel Jakub Dawidek for (i = 0; i <= g_eli_overwrites; i++) { 754c58794deSPawel Jakub Dawidek if (i == g_eli_overwrites) 755c58794deSPawel Jakub Dawidek bzero(mkeydst, keysize); 756c58794deSPawel Jakub Dawidek else 757c58794deSPawel Jakub Dawidek arc4rand(mkeydst, keysize, 0); 758c58794deSPawel Jakub Dawidek /* Store metadata with destroyed key. */ 759c58794deSPawel Jakub Dawidek eli_metadata_encode(&md, sector); 760c58794deSPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 761c58794deSPawel Jakub Dawidek pp->sectorsize); 762c58794deSPawel Jakub Dawidek if (error != 0) { 763c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot store metadata on %s " 764c58794deSPawel Jakub Dawidek "(error=%d).", pp->name, error); 765c58794deSPawel Jakub Dawidek } 766f0256e71SPawel Jakub Dawidek /* 767f0256e71SPawel Jakub Dawidek * Flush write cache so we don't overwrite data N times in cache 768f0256e71SPawel Jakub Dawidek * and only once on disk. 769f0256e71SPawel Jakub Dawidek */ 770350e8df8SPawel Jakub Dawidek (void)g_io_flush(cp); 771c58794deSPawel Jakub Dawidek } 772c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 7737ac2e588SXin LI bzero(sector, pp->sectorsize); 774c58794deSPawel Jakub Dawidek free(sector, M_ELI); 775c58794deSPawel Jakub Dawidek if (*all) 776c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "All keys removed from %s.", pp->name); 777c58794deSPawel Jakub Dawidek else 778c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name); 779c58794deSPawel Jakub Dawidek } 780c58794deSPawel Jakub Dawidek 7810d2f5a4eSPawel Jakub Dawidek static void 7820d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req) 7835ad4a7c7SPawel Jakub Dawidek { 7845ad4a7c7SPawel Jakub Dawidek struct g_eli_worker *wr; 7855ad4a7c7SPawel Jakub Dawidek 7865ad4a7c7SPawel Jakub Dawidek g_topology_assert(); 7875ad4a7c7SPawel Jakub Dawidek 7880d2f5a4eSPawel Jakub Dawidek KASSERT(sc != NULL, ("NULL sc")); 7890d2f5a4eSPawel Jakub Dawidek 7900d2f5a4eSPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_ONETIME) { 7910d2f5a4eSPawel Jakub Dawidek gctl_error(req, 7920d2f5a4eSPawel Jakub Dawidek "Device %s is using one-time key, suspend not supported.", 7930d2f5a4eSPawel Jakub Dawidek sc->sc_name); 7940d2f5a4eSPawel Jakub Dawidek return; 7950d2f5a4eSPawel Jakub Dawidek } 7965ad4a7c7SPawel Jakub Dawidek 7975ad4a7c7SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 7985ad4a7c7SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_SUSPEND) { 7995ad4a7c7SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8000d2f5a4eSPawel Jakub Dawidek gctl_error(req, "Device %s already suspended.", 8010d2f5a4eSPawel Jakub Dawidek sc->sc_name); 8020d2f5a4eSPawel Jakub Dawidek return; 8035ad4a7c7SPawel Jakub Dawidek } 8045ad4a7c7SPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_SUSPEND; 8055ad4a7c7SPawel Jakub Dawidek wakeup(sc); 8065ad4a7c7SPawel Jakub Dawidek for (;;) { 8075ad4a7c7SPawel Jakub Dawidek LIST_FOREACH(wr, &sc->sc_workers, w_next) { 8085ad4a7c7SPawel Jakub Dawidek if (wr->w_active) 8095ad4a7c7SPawel Jakub Dawidek break; 8105ad4a7c7SPawel Jakub Dawidek } 8115ad4a7c7SPawel Jakub Dawidek if (wr == NULL) 8125ad4a7c7SPawel Jakub Dawidek break; 8135ad4a7c7SPawel Jakub Dawidek /* Not all threads suspended. */ 8145ad4a7c7SPawel Jakub Dawidek msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO, 8155ad4a7c7SPawel Jakub Dawidek "geli:suspend", 0); 8165ad4a7c7SPawel Jakub Dawidek } 8175ad4a7c7SPawel Jakub Dawidek /* 8185ad4a7c7SPawel Jakub Dawidek * Clear sensitive data on suspend, they will be recovered on resume. 8195ad4a7c7SPawel Jakub Dawidek */ 8205ad4a7c7SPawel Jakub Dawidek bzero(sc->sc_mkey, sizeof(sc->sc_mkey)); 8211e09ff3dSPawel Jakub Dawidek g_eli_key_destroy(sc); 8225ad4a7c7SPawel Jakub Dawidek bzero(sc->sc_akey, sizeof(sc->sc_akey)); 8235ad4a7c7SPawel Jakub Dawidek bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx)); 8245ad4a7c7SPawel Jakub Dawidek bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey)); 8255ad4a7c7SPawel Jakub Dawidek bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx)); 8265ad4a7c7SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 8270d2f5a4eSPawel Jakub Dawidek G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name); 8285ad4a7c7SPawel Jakub Dawidek } 8295ad4a7c7SPawel Jakub Dawidek 8305ad4a7c7SPawel Jakub Dawidek static void 8315ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp) 8325ad4a7c7SPawel Jakub Dawidek { 8335ad4a7c7SPawel Jakub Dawidek struct g_eli_softc *sc; 8345ad4a7c7SPawel Jakub Dawidek int *all, *nargs; 8355ad4a7c7SPawel Jakub Dawidek 8365ad4a7c7SPawel Jakub Dawidek g_topology_assert(); 8375ad4a7c7SPawel Jakub Dawidek 8385ad4a7c7SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 8395ad4a7c7SPawel Jakub Dawidek if (nargs == NULL) { 8405ad4a7c7SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 8415ad4a7c7SPawel Jakub Dawidek return; 8425ad4a7c7SPawel Jakub Dawidek } 8435ad4a7c7SPawel Jakub Dawidek all = gctl_get_paraml(req, "all", sizeof(*all)); 8445ad4a7c7SPawel Jakub Dawidek if (all == NULL) { 8455ad4a7c7SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "all"); 8465ad4a7c7SPawel Jakub Dawidek return; 8475ad4a7c7SPawel Jakub Dawidek } 8485ad4a7c7SPawel Jakub Dawidek if (!*all && *nargs == 0) { 8495ad4a7c7SPawel Jakub Dawidek gctl_error(req, "Too few arguments."); 8505ad4a7c7SPawel Jakub Dawidek return; 8515ad4a7c7SPawel Jakub Dawidek } 8525ad4a7c7SPawel Jakub Dawidek 8535ad4a7c7SPawel Jakub Dawidek if (*all) { 8545ad4a7c7SPawel Jakub Dawidek struct g_geom *gp, *gp2; 8555ad4a7c7SPawel Jakub Dawidek 8565ad4a7c7SPawel Jakub Dawidek LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 8575ad4a7c7SPawel Jakub Dawidek sc = gp->softc; 8580d2f5a4eSPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_ONETIME) { 8590d2f5a4eSPawel Jakub Dawidek G_ELI_DEBUG(0, 8600d2f5a4eSPawel Jakub Dawidek "Device %s is using one-time key, suspend not supported, skipping.", 8610d2f5a4eSPawel Jakub Dawidek sc->sc_name); 8625ad4a7c7SPawel Jakub Dawidek continue; 8630d2f5a4eSPawel Jakub Dawidek } 8640d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(sc, req); 8655ad4a7c7SPawel Jakub Dawidek } 8665ad4a7c7SPawel Jakub Dawidek } else { 8675ad4a7c7SPawel Jakub Dawidek const char *prov; 8685ad4a7c7SPawel Jakub Dawidek char param[16]; 8695ad4a7c7SPawel Jakub Dawidek int i; 8705ad4a7c7SPawel Jakub Dawidek 8715ad4a7c7SPawel Jakub Dawidek for (i = 0; i < *nargs; i++) { 8725ad4a7c7SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%d", i); 8735ad4a7c7SPawel Jakub Dawidek prov = gctl_get_asciiparam(req, param); 8745ad4a7c7SPawel Jakub Dawidek if (prov == NULL) { 8755ad4a7c7SPawel Jakub Dawidek G_ELI_DEBUG(0, "No 'arg%d' argument.", i); 8765ad4a7c7SPawel Jakub Dawidek continue; 8775ad4a7c7SPawel Jakub Dawidek } 8785ad4a7c7SPawel Jakub Dawidek 8795ad4a7c7SPawel Jakub Dawidek sc = g_eli_find_device(mp, prov); 8805ad4a7c7SPawel Jakub Dawidek if (sc == NULL) { 8815ad4a7c7SPawel Jakub Dawidek G_ELI_DEBUG(0, "No such provider: %s.", prov); 8825ad4a7c7SPawel Jakub Dawidek continue; 8835ad4a7c7SPawel Jakub Dawidek } 8840d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(sc, req); 8855ad4a7c7SPawel Jakub Dawidek } 8865ad4a7c7SPawel Jakub Dawidek } 8875ad4a7c7SPawel Jakub Dawidek } 8885ad4a7c7SPawel Jakub Dawidek 8895ad4a7c7SPawel Jakub Dawidek static void 8905ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp) 8915ad4a7c7SPawel Jakub Dawidek { 8925ad4a7c7SPawel Jakub Dawidek struct g_eli_metadata md; 8935ad4a7c7SPawel Jakub Dawidek struct g_eli_softc *sc; 8945ad4a7c7SPawel Jakub Dawidek struct g_provider *pp; 8955ad4a7c7SPawel Jakub Dawidek struct g_consumer *cp; 8965ad4a7c7SPawel Jakub Dawidek const char *name; 8975ad4a7c7SPawel Jakub Dawidek u_char *key, mkey[G_ELI_DATAIVKEYLEN]; 8985ad4a7c7SPawel Jakub Dawidek int *nargs, keysize, error; 8995ad4a7c7SPawel Jakub Dawidek u_int nkey; 9005ad4a7c7SPawel Jakub Dawidek 9015ad4a7c7SPawel Jakub Dawidek g_topology_assert(); 9025ad4a7c7SPawel Jakub Dawidek 9035ad4a7c7SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 9045ad4a7c7SPawel Jakub Dawidek if (nargs == NULL) { 9055ad4a7c7SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 9065ad4a7c7SPawel Jakub Dawidek return; 9075ad4a7c7SPawel Jakub Dawidek } 9085ad4a7c7SPawel Jakub Dawidek if (*nargs != 1) { 9095ad4a7c7SPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 9105ad4a7c7SPawel Jakub Dawidek return; 9115ad4a7c7SPawel Jakub Dawidek } 9125ad4a7c7SPawel Jakub Dawidek 9135ad4a7c7SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 9145ad4a7c7SPawel Jakub Dawidek if (name == NULL) { 9155ad4a7c7SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 9165ad4a7c7SPawel Jakub Dawidek return; 9175ad4a7c7SPawel Jakub Dawidek } 9185ad4a7c7SPawel Jakub Dawidek sc = g_eli_find_device(mp, name); 9195ad4a7c7SPawel Jakub Dawidek if (sc == NULL) { 9205ad4a7c7SPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 9215ad4a7c7SPawel Jakub Dawidek return; 9225ad4a7c7SPawel Jakub Dawidek } 9235ad4a7c7SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 9245ad4a7c7SPawel Jakub Dawidek pp = cp->provider; 9255ad4a7c7SPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 9265ad4a7c7SPawel Jakub Dawidek if (error != 0) { 9275ad4a7c7SPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 9285ad4a7c7SPawel Jakub Dawidek name, error); 9295ad4a7c7SPawel Jakub Dawidek return; 9305ad4a7c7SPawel Jakub Dawidek } 9315ad4a7c7SPawel Jakub Dawidek if (md.md_keys == 0x00) { 9325ad4a7c7SPawel Jakub Dawidek bzero(&md, sizeof(md)); 9335ad4a7c7SPawel Jakub Dawidek gctl_error(req, "No valid keys on %s.", pp->name); 9345ad4a7c7SPawel Jakub Dawidek return; 9355ad4a7c7SPawel Jakub Dawidek } 9365ad4a7c7SPawel Jakub Dawidek 9375ad4a7c7SPawel Jakub Dawidek key = gctl_get_param(req, "key", &keysize); 9385ad4a7c7SPawel Jakub Dawidek if (key == NULL || keysize != G_ELI_USERKEYLEN) { 9395ad4a7c7SPawel Jakub Dawidek bzero(&md, sizeof(md)); 9405ad4a7c7SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "key"); 9415ad4a7c7SPawel Jakub Dawidek return; 9425ad4a7c7SPawel Jakub Dawidek } 9435ad4a7c7SPawel Jakub Dawidek 9445ad4a7c7SPawel Jakub Dawidek error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); 9455ad4a7c7SPawel Jakub Dawidek bzero(key, keysize); 9465ad4a7c7SPawel Jakub Dawidek if (error == -1) { 9475ad4a7c7SPawel Jakub Dawidek bzero(&md, sizeof(md)); 9485ad4a7c7SPawel Jakub Dawidek gctl_error(req, "Wrong key for %s.", pp->name); 9495ad4a7c7SPawel Jakub Dawidek return; 9505ad4a7c7SPawel Jakub Dawidek } else if (error > 0) { 9515ad4a7c7SPawel Jakub Dawidek bzero(&md, sizeof(md)); 9525ad4a7c7SPawel Jakub Dawidek gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).", 9535ad4a7c7SPawel Jakub Dawidek pp->name, error); 9545ad4a7c7SPawel Jakub Dawidek return; 9555ad4a7c7SPawel Jakub Dawidek } 9565ad4a7c7SPawel Jakub Dawidek G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); 9575ad4a7c7SPawel Jakub Dawidek 9585ad4a7c7SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 9592f2d7830SPawel Jakub Dawidek if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND)) 9602f2d7830SPawel Jakub Dawidek gctl_error(req, "Device %s is not suspended.", name); 9612f2d7830SPawel Jakub Dawidek else { 9625ad4a7c7SPawel Jakub Dawidek /* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */ 9635ad4a7c7SPawel Jakub Dawidek g_eli_mkey_propagate(sc, mkey); 9645ad4a7c7SPawel Jakub Dawidek sc->sc_flags &= ~G_ELI_FLAG_SUSPEND; 9652f2d7830SPawel Jakub Dawidek G_ELI_DEBUG(1, "Resumed %s.", pp->name); 9662f2d7830SPawel Jakub Dawidek wakeup(sc); 9672f2d7830SPawel Jakub Dawidek } 9685ad4a7c7SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 9691d021441SPawel Jakub Dawidek bzero(mkey, sizeof(mkey)); 9701d021441SPawel Jakub Dawidek bzero(&md, sizeof(md)); 9715ad4a7c7SPawel Jakub Dawidek } 9725ad4a7c7SPawel Jakub Dawidek 9735ad4a7c7SPawel Jakub Dawidek static int 974c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc) 975c58794deSPawel Jakub Dawidek { 976c58794deSPawel Jakub Dawidek struct g_provider *pp; 977c58794deSPawel Jakub Dawidek struct g_consumer *cp; 97885059016SPawel Jakub Dawidek int error = 0; 979c58794deSPawel Jakub Dawidek 980c58794deSPawel Jakub Dawidek g_topology_assert(); 981c58794deSPawel Jakub Dawidek 982c58794deSPawel Jakub Dawidek if (sc == NULL) 983c58794deSPawel Jakub Dawidek return (ENOENT); 984c58794deSPawel Jakub Dawidek 985c58794deSPawel Jakub Dawidek pp = LIST_FIRST(&sc->sc_geom->provider); 986c58794deSPawel Jakub Dawidek g_error_provider(pp, ENXIO); 987c58794deSPawel Jakub Dawidek 988c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 989c58794deSPawel Jakub Dawidek pp = cp->provider; 990c58794deSPawel Jakub Dawidek 99185059016SPawel Jakub Dawidek if (sc->sc_flags & G_ELI_FLAG_RO) { 99285059016SPawel Jakub Dawidek G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only " 99385059016SPawel Jakub Dawidek "provider: %s.", pp->name); 99485059016SPawel Jakub Dawidek } else { 99585059016SPawel Jakub Dawidek u_char *sector; 99685059016SPawel Jakub Dawidek u_int i; 99785059016SPawel Jakub Dawidek int err; 99885059016SPawel Jakub Dawidek 999c58794deSPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK); 1000c58794deSPawel Jakub Dawidek for (i = 0; i <= g_eli_overwrites; i++) { 1001c58794deSPawel Jakub Dawidek if (i == g_eli_overwrites) 1002c58794deSPawel Jakub Dawidek bzero(sector, pp->sectorsize); 1003c58794deSPawel Jakub Dawidek else 1004c58794deSPawel Jakub Dawidek arc4rand(sector, pp->sectorsize, 0); 100585059016SPawel Jakub Dawidek err = g_write_data(cp, pp->mediasize - pp->sectorsize, 100685059016SPawel Jakub Dawidek sector, pp->sectorsize); 1007c58794deSPawel Jakub Dawidek if (err != 0) { 1008c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot erase metadata on %s " 1009c58794deSPawel Jakub Dawidek "(error=%d).", pp->name, err); 1010c58794deSPawel Jakub Dawidek if (error == 0) 1011c58794deSPawel Jakub Dawidek error = err; 1012c58794deSPawel Jakub Dawidek } 1013350e8df8SPawel Jakub Dawidek /* 1014350e8df8SPawel Jakub Dawidek * Flush write cache so we don't overwrite data N times 1015350e8df8SPawel Jakub Dawidek * in cache and only once on disk. 1016350e8df8SPawel Jakub Dawidek */ 1017350e8df8SPawel Jakub Dawidek (void)g_io_flush(cp); 1018c58794deSPawel Jakub Dawidek } 1019c58794deSPawel Jakub Dawidek free(sector, M_ELI); 102085059016SPawel Jakub Dawidek } 1021c58794deSPawel Jakub Dawidek if (error == 0) 1022c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "%s has been killed.", pp->name); 10235ad4a7c7SPawel Jakub Dawidek g_eli_destroy(sc, TRUE); 1024c58794deSPawel Jakub Dawidek return (error); 1025c58794deSPawel Jakub Dawidek } 1026c58794deSPawel Jakub Dawidek 1027c58794deSPawel Jakub Dawidek static void 1028c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp) 1029c58794deSPawel Jakub Dawidek { 1030c58794deSPawel Jakub Dawidek int *all, *nargs; 1031c58794deSPawel Jakub Dawidek int error; 1032c58794deSPawel Jakub Dawidek 1033c58794deSPawel Jakub Dawidek g_topology_assert(); 1034c58794deSPawel Jakub Dawidek 1035c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1036c58794deSPawel Jakub Dawidek if (nargs == NULL) { 1037c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 1038c58794deSPawel Jakub Dawidek return; 1039c58794deSPawel Jakub Dawidek } 1040c58794deSPawel Jakub Dawidek all = gctl_get_paraml(req, "all", sizeof(*all)); 1041c58794deSPawel Jakub Dawidek if (all == NULL) { 1042c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "all"); 1043c58794deSPawel Jakub Dawidek return; 1044c58794deSPawel Jakub Dawidek } 1045c58794deSPawel Jakub Dawidek if (!*all && *nargs == 0) { 1046c58794deSPawel Jakub Dawidek gctl_error(req, "Too few arguments."); 1047c58794deSPawel Jakub Dawidek return; 1048c58794deSPawel Jakub Dawidek } 1049c58794deSPawel Jakub Dawidek 1050c58794deSPawel Jakub Dawidek if (*all) { 1051c58794deSPawel Jakub Dawidek struct g_geom *gp, *gp2; 1052c58794deSPawel Jakub Dawidek 1053c58794deSPawel Jakub Dawidek LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 1054c58794deSPawel Jakub Dawidek error = g_eli_kill_one(gp->softc); 1055c58794deSPawel Jakub Dawidek if (error != 0) 1056c58794deSPawel Jakub Dawidek gctl_error(req, "Not fully done."); 1057c58794deSPawel Jakub Dawidek } 1058c58794deSPawel Jakub Dawidek } else { 1059c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 1060c58794deSPawel Jakub Dawidek const char *prov; 1061c58794deSPawel Jakub Dawidek char param[16]; 1062c58794deSPawel Jakub Dawidek int i; 1063c58794deSPawel Jakub Dawidek 1064c58794deSPawel Jakub Dawidek for (i = 0; i < *nargs; i++) { 10657d54b385SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%d", i); 1066c58794deSPawel Jakub Dawidek prov = gctl_get_asciiparam(req, param); 1067b5f30223SPawel Jakub Dawidek if (prov == NULL) { 1068b5f30223SPawel Jakub Dawidek G_ELI_DEBUG(0, "No 'arg%d' argument.", i); 1069b5f30223SPawel Jakub Dawidek continue; 1070b5f30223SPawel Jakub Dawidek } 1071c58794deSPawel Jakub Dawidek 1072c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, prov); 1073c58794deSPawel Jakub Dawidek if (sc == NULL) { 10747d54b385SPawel Jakub Dawidek G_ELI_DEBUG(0, "No such provider: %s.", prov); 1075c58794deSPawel Jakub Dawidek continue; 1076c58794deSPawel Jakub Dawidek } 1077c58794deSPawel Jakub Dawidek error = g_eli_kill_one(sc); 1078c58794deSPawel Jakub Dawidek if (error != 0) 1079c58794deSPawel Jakub Dawidek gctl_error(req, "Not fully done."); 1080c58794deSPawel Jakub Dawidek } 1081c58794deSPawel Jakub Dawidek } 1082c58794deSPawel Jakub Dawidek } 1083c58794deSPawel Jakub Dawidek 1084c58794deSPawel Jakub Dawidek void 1085c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1086c58794deSPawel Jakub Dawidek { 1087c58794deSPawel Jakub Dawidek uint32_t *version; 1088c58794deSPawel Jakub Dawidek 1089c58794deSPawel Jakub Dawidek g_topology_assert(); 1090c58794deSPawel Jakub Dawidek 1091c58794deSPawel Jakub Dawidek version = gctl_get_paraml(req, "version", sizeof(*version)); 1092c58794deSPawel Jakub Dawidek if (version == NULL) { 1093c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "version"); 1094c58794deSPawel Jakub Dawidek return; 1095c58794deSPawel Jakub Dawidek } 1096731adc86SPawel Jakub Dawidek while (*version != G_ELI_VERSION) { 1097731adc86SPawel Jakub Dawidek if (G_ELI_VERSION == G_ELI_VERSION_06 && 1098731adc86SPawel Jakub Dawidek *version == G_ELI_VERSION_05) { 1099731adc86SPawel Jakub Dawidek /* Compatible. */ 1100731adc86SPawel Jakub Dawidek break; 1101731adc86SPawel Jakub Dawidek } 1102457bbc4fSPawel Jakub Dawidek if (G_ELI_VERSION == G_ELI_VERSION_07 && 1103457bbc4fSPawel Jakub Dawidek (*version == G_ELI_VERSION_05 || 1104457bbc4fSPawel Jakub Dawidek *version == G_ELI_VERSION_06)) { 1105457bbc4fSPawel Jakub Dawidek /* Compatible. */ 1106457bbc4fSPawel Jakub Dawidek break; 1107457bbc4fSPawel Jakub Dawidek } 1108c58794deSPawel Jakub Dawidek gctl_error(req, "Userland and kernel parts are out of sync."); 1109c58794deSPawel Jakub Dawidek return; 1110c58794deSPawel Jakub Dawidek } 1111c58794deSPawel Jakub Dawidek 1112c58794deSPawel Jakub Dawidek if (strcmp(verb, "attach") == 0) 1113c58794deSPawel Jakub Dawidek g_eli_ctl_attach(req, mp); 1114c58794deSPawel Jakub Dawidek else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0) 1115c58794deSPawel Jakub Dawidek g_eli_ctl_detach(req, mp); 1116c58794deSPawel Jakub Dawidek else if (strcmp(verb, "onetime") == 0) 1117c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(req, mp); 11188abd1ad1SPawel Jakub Dawidek else if (strcmp(verb, "configure") == 0) 11198abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(req, mp); 1120c58794deSPawel Jakub Dawidek else if (strcmp(verb, "setkey") == 0) 1121c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(req, mp); 1122c58794deSPawel Jakub Dawidek else if (strcmp(verb, "delkey") == 0) 1123c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(req, mp); 11245ad4a7c7SPawel Jakub Dawidek else if (strcmp(verb, "suspend") == 0) 11255ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(req, mp); 11265ad4a7c7SPawel Jakub Dawidek else if (strcmp(verb, "resume") == 0) 11275ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(req, mp); 1128c58794deSPawel Jakub Dawidek else if (strcmp(verb, "kill") == 0) 1129c58794deSPawel Jakub Dawidek g_eli_ctl_kill(req, mp); 1130c58794deSPawel Jakub Dawidek else 1131c58794deSPawel Jakub Dawidek gctl_error(req, "Unknown verb."); 1132c58794deSPawel Jakub Dawidek } 1133