1c58794deSPawel Jakub Dawidek /*- 2c58794deSPawel Jakub Dawidek * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 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]; 60c58794deSPawel Jakub Dawidek int *nargs, *detach; 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 82c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 83c58794deSPawel Jakub Dawidek if (name == NULL) { 84c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 85c58794deSPawel Jakub Dawidek return; 86c58794deSPawel Jakub Dawidek } 87c58794deSPawel Jakub Dawidek if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 88c58794deSPawel Jakub Dawidek name += strlen("/dev/"); 89c58794deSPawel Jakub Dawidek pp = g_provider_by_name(name); 90c58794deSPawel Jakub Dawidek if (pp == NULL) { 91c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 92c58794deSPawel Jakub Dawidek return; 93c58794deSPawel Jakub Dawidek } 94c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 95c58794deSPawel Jakub Dawidek if (error != 0) { 96c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 97c58794deSPawel Jakub Dawidek name, error); 98c58794deSPawel Jakub Dawidek return; 99c58794deSPawel Jakub Dawidek } 100c58794deSPawel Jakub Dawidek if (md.md_keys == 0x00) { 101c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 102c58794deSPawel Jakub Dawidek gctl_error(req, "No valid keys on %s.", pp->name); 103c58794deSPawel Jakub Dawidek return; 104c58794deSPawel Jakub Dawidek } 105c58794deSPawel Jakub Dawidek 106c58794deSPawel Jakub Dawidek key = gctl_get_param(req, "key", &keysize); 107c58794deSPawel Jakub Dawidek if (key == NULL || keysize != G_ELI_USERKEYLEN) { 108c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 109c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "key"); 110c58794deSPawel Jakub Dawidek return; 111c58794deSPawel Jakub Dawidek } 112c58794deSPawel Jakub Dawidek 113c58794deSPawel Jakub Dawidek error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); 114c58794deSPawel Jakub Dawidek bzero(key, keysize); 115c58794deSPawel Jakub Dawidek if (error == -1) { 116c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 117c58794deSPawel Jakub Dawidek gctl_error(req, "Wrong key for %s.", pp->name); 118c58794deSPawel Jakub Dawidek return; 119c58794deSPawel Jakub Dawidek } else if (error > 0) { 120c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 121c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).", 122c58794deSPawel Jakub Dawidek pp->name, error); 123c58794deSPawel Jakub Dawidek return; 124c58794deSPawel Jakub Dawidek } 125c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); 126c58794deSPawel Jakub Dawidek 127c58794deSPawel Jakub Dawidek if (*detach) 128c58794deSPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_WO_DETACH; 129c58794deSPawel Jakub Dawidek g_eli_create(req, mp, pp, &md, mkey, nkey); 130c58794deSPawel Jakub Dawidek bzero(mkey, sizeof(mkey)); 131c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 132c58794deSPawel Jakub Dawidek } 133c58794deSPawel Jakub Dawidek 134c58794deSPawel Jakub Dawidek static struct g_eli_softc * 135c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov) 136c58794deSPawel Jakub Dawidek { 137c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 138c58794deSPawel Jakub Dawidek struct g_geom *gp; 139c58794deSPawel Jakub Dawidek struct g_provider *pp; 140c58794deSPawel Jakub Dawidek struct g_consumer *cp; 141c58794deSPawel Jakub Dawidek 142c58794deSPawel Jakub Dawidek if (strncmp(prov, "/dev/", strlen("/dev/")) == 0) 143c58794deSPawel Jakub Dawidek prov += strlen("/dev/"); 144c58794deSPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 145c58794deSPawel Jakub Dawidek sc = gp->softc; 146c58794deSPawel Jakub Dawidek if (sc == NULL) 147c58794deSPawel Jakub Dawidek continue; 148c58794deSPawel Jakub Dawidek pp = LIST_FIRST(&gp->provider); 149c58794deSPawel Jakub Dawidek if (pp != NULL && strcmp(pp->name, prov) == 0) 150c58794deSPawel Jakub Dawidek return (sc); 151c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&gp->consumer); 152c58794deSPawel Jakub Dawidek if (cp != NULL && cp->provider != NULL && 153c58794deSPawel Jakub Dawidek strcmp(cp->provider->name, prov) == 0) { 154c58794deSPawel Jakub Dawidek return (sc); 155c58794deSPawel Jakub Dawidek } 156c58794deSPawel Jakub Dawidek } 157c58794deSPawel Jakub Dawidek return (NULL); 158c58794deSPawel Jakub Dawidek } 159c58794deSPawel Jakub Dawidek 160c58794deSPawel Jakub Dawidek static void 161c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp) 162c58794deSPawel Jakub Dawidek { 163c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 164c58794deSPawel Jakub Dawidek int *force, *last, *nargs, error; 165c58794deSPawel Jakub Dawidek const char *prov; 166c58794deSPawel Jakub Dawidek char param[16]; 167c58794deSPawel Jakub Dawidek u_int i; 168c58794deSPawel Jakub Dawidek 169c58794deSPawel Jakub Dawidek g_topology_assert(); 170c58794deSPawel Jakub Dawidek 171c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 172c58794deSPawel Jakub Dawidek if (nargs == NULL) { 173c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 174c58794deSPawel Jakub Dawidek return; 175c58794deSPawel Jakub Dawidek } 176c58794deSPawel Jakub Dawidek if (*nargs <= 0) { 177c58794deSPawel Jakub Dawidek gctl_error(req, "Missing device(s)."); 178c58794deSPawel Jakub Dawidek return; 179c58794deSPawel Jakub Dawidek } 180c58794deSPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force)); 181c58794deSPawel Jakub Dawidek if (force == NULL) { 182c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force"); 183c58794deSPawel Jakub Dawidek return; 184c58794deSPawel Jakub Dawidek } 185c58794deSPawel Jakub Dawidek last = gctl_get_paraml(req, "last", sizeof(*last)); 186c58794deSPawel Jakub Dawidek if (last == NULL) { 187c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "last"); 188c58794deSPawel Jakub Dawidek return; 189c58794deSPawel Jakub Dawidek } 190c58794deSPawel Jakub Dawidek 191c58794deSPawel Jakub Dawidek for (i = 0; i < (u_int)*nargs; i++) { 192c58794deSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i); 193c58794deSPawel Jakub Dawidek prov = gctl_get_asciiparam(req, param); 194c58794deSPawel Jakub Dawidek if (prov == NULL) { 195c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i); 196c58794deSPawel Jakub Dawidek return; 197c58794deSPawel Jakub Dawidek } 198c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, prov); 199c58794deSPawel Jakub Dawidek if (sc == NULL) { 200c58794deSPawel Jakub Dawidek gctl_error(req, "No such device: %s.", prov); 201c58794deSPawel Jakub Dawidek return; 202c58794deSPawel Jakub Dawidek } 203c58794deSPawel Jakub Dawidek if (*last) { 204c58794deSPawel Jakub Dawidek sc->sc_flags |= G_ELI_FLAG_RW_DETACH; 205c58794deSPawel Jakub Dawidek sc->sc_geom->access = g_eli_access; 206c58794deSPawel Jakub Dawidek } else { 207c58794deSPawel Jakub Dawidek error = g_eli_destroy(sc, *force); 208c58794deSPawel Jakub Dawidek if (error != 0) { 209c58794deSPawel Jakub Dawidek gctl_error(req, 210c58794deSPawel Jakub Dawidek "Cannot destroy device %s (error=%d).", 211c58794deSPawel Jakub Dawidek sc->sc_name, error); 212c58794deSPawel Jakub Dawidek return; 213c58794deSPawel Jakub Dawidek } 214c58794deSPawel Jakub Dawidek } 215c58794deSPawel Jakub Dawidek } 216c58794deSPawel Jakub Dawidek } 217c58794deSPawel Jakub Dawidek 218c58794deSPawel Jakub Dawidek static void 219c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) 220c58794deSPawel Jakub Dawidek { 221c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 222c58794deSPawel Jakub Dawidek struct g_provider *pp; 223c58794deSPawel Jakub Dawidek const char *name; 224c58794deSPawel Jakub Dawidek intmax_t *keylen, *sectorsize; 225c58794deSPawel Jakub Dawidek u_char mkey[G_ELI_DATAIVKEYLEN]; 226c58794deSPawel Jakub Dawidek int *nargs, *detach; 227c58794deSPawel Jakub Dawidek 228c58794deSPawel Jakub Dawidek g_topology_assert(); 229c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 230c58794deSPawel Jakub Dawidek 231c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 232c58794deSPawel Jakub Dawidek if (nargs == NULL) { 233c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 234c58794deSPawel Jakub Dawidek return; 235c58794deSPawel Jakub Dawidek } 236c58794deSPawel Jakub Dawidek if (*nargs != 1) { 237c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 238c58794deSPawel Jakub Dawidek return; 239c58794deSPawel Jakub Dawidek } 240c58794deSPawel Jakub Dawidek 241c58794deSPawel Jakub Dawidek detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 242c58794deSPawel Jakub Dawidek if (detach == NULL) { 243c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "detach"); 244c58794deSPawel Jakub Dawidek return; 245c58794deSPawel Jakub Dawidek } 246c58794deSPawel Jakub Dawidek 247c58794deSPawel Jakub Dawidek strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 248c58794deSPawel Jakub Dawidek md.md_version = G_ELI_VERSION; 249c58794deSPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_ONETIME; 250c58794deSPawel Jakub Dawidek if (*detach) 251c58794deSPawel Jakub Dawidek md.md_flags |= G_ELI_FLAG_WO_DETACH; 252c58794deSPawel Jakub Dawidek 253c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "algo"); 254c58794deSPawel Jakub Dawidek if (name == NULL) { 255c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "algo"); 256c58794deSPawel Jakub Dawidek return; 257c58794deSPawel Jakub Dawidek } 258c58794deSPawel Jakub Dawidek md.md_algo = g_eli_str2algo(name); 259c58794deSPawel Jakub Dawidek if (md.md_algo < CRYPTO_ALGORITHM_MIN || 260c58794deSPawel Jakub Dawidek md.md_algo > CRYPTO_ALGORITHM_MAX) { 261c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "algo"); 262c58794deSPawel Jakub Dawidek return; 263c58794deSPawel Jakub Dawidek } 264c58794deSPawel Jakub Dawidek 265c58794deSPawel Jakub Dawidek keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen)); 266c58794deSPawel Jakub Dawidek if (keylen == NULL) { 267c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "keylen"); 268c58794deSPawel Jakub Dawidek return; 269c58794deSPawel Jakub Dawidek } 270c58794deSPawel Jakub Dawidek md.md_keylen = g_eli_keylen(md.md_algo, *keylen); 271c58794deSPawel Jakub Dawidek if (md.md_keylen == 0) { 272c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "keylen"); 273c58794deSPawel Jakub Dawidek return; 274c58794deSPawel Jakub Dawidek } 275c58794deSPawel Jakub Dawidek 276c58794deSPawel Jakub Dawidek /* Not important here. */ 277c58794deSPawel Jakub Dawidek md.md_provsize = 0; 278c58794deSPawel Jakub Dawidek /* Not important here. */ 279c58794deSPawel Jakub Dawidek bzero(md.md_salt, sizeof(md.md_salt)); 280c58794deSPawel Jakub Dawidek 281c58794deSPawel Jakub Dawidek md.md_keys = 0x01; 282c58794deSPawel Jakub Dawidek arc4rand(mkey, sizeof(mkey), 0); 283c58794deSPawel Jakub Dawidek 284c58794deSPawel Jakub Dawidek /* Not important here. */ 285c58794deSPawel Jakub Dawidek bzero(md.md_hash, sizeof(md.md_hash)); 286c58794deSPawel Jakub Dawidek 287c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 288c58794deSPawel Jakub Dawidek if (name == NULL) { 289c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 290c58794deSPawel Jakub Dawidek return; 291c58794deSPawel Jakub Dawidek } 292c58794deSPawel Jakub Dawidek if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 293c58794deSPawel Jakub Dawidek name += strlen("/dev/"); 294c58794deSPawel Jakub Dawidek pp = g_provider_by_name(name); 295c58794deSPawel Jakub Dawidek if (pp == NULL) { 296c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 297c58794deSPawel Jakub Dawidek return; 298c58794deSPawel Jakub Dawidek } 299c58794deSPawel Jakub Dawidek 300c58794deSPawel Jakub Dawidek sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize)); 301c58794deSPawel Jakub Dawidek if (sectorsize == NULL) { 302c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "sectorsize"); 303c58794deSPawel Jakub Dawidek return; 304c58794deSPawel Jakub Dawidek } 305c58794deSPawel Jakub Dawidek if (*sectorsize == 0) 306c58794deSPawel Jakub Dawidek md.md_sectorsize = pp->sectorsize; 307c58794deSPawel Jakub Dawidek else { 308c58794deSPawel Jakub Dawidek if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) { 309c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid sector size."); 310c58794deSPawel Jakub Dawidek return; 311c58794deSPawel Jakub Dawidek } 312c58794deSPawel Jakub Dawidek md.md_sectorsize = *sectorsize; 313c58794deSPawel Jakub Dawidek } 314c58794deSPawel Jakub Dawidek 315c58794deSPawel Jakub Dawidek g_eli_create(req, mp, pp, &md, mkey, -1); 316c58794deSPawel Jakub Dawidek bzero(mkey, sizeof(mkey)); 317c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 318c58794deSPawel Jakub Dawidek } 319c58794deSPawel Jakub Dawidek 320c58794deSPawel Jakub Dawidek static void 321c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp) 322c58794deSPawel Jakub Dawidek { 323c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 324c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 325c58794deSPawel Jakub Dawidek struct g_provider *pp; 326c58794deSPawel Jakub Dawidek struct g_consumer *cp; 327c58794deSPawel Jakub Dawidek const char *name; 328c58794deSPawel Jakub Dawidek u_char *key, *mkeydst, *sector; 329c58794deSPawel Jakub Dawidek intmax_t *valp; 330c58794deSPawel Jakub Dawidek int nkey; 331c58794deSPawel Jakub Dawidek int keysize, error; 332c58794deSPawel Jakub Dawidek 333c58794deSPawel Jakub Dawidek g_topology_assert(); 334c58794deSPawel Jakub Dawidek 335c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 336c58794deSPawel Jakub Dawidek if (name == NULL) { 337c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 338c58794deSPawel Jakub Dawidek return; 339c58794deSPawel Jakub Dawidek } 340c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, name); 341c58794deSPawel Jakub Dawidek if (sc == NULL) { 342c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 343c58794deSPawel Jakub Dawidek return; 344c58794deSPawel Jakub Dawidek } 345c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 346c58794deSPawel Jakub Dawidek pp = cp->provider; 347c58794deSPawel Jakub Dawidek 348c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 349c58794deSPawel Jakub Dawidek if (error != 0) { 350c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 351c58794deSPawel Jakub Dawidek name, error); 352c58794deSPawel Jakub Dawidek return; 353c58794deSPawel Jakub Dawidek } 354c58794deSPawel Jakub Dawidek 355c58794deSPawel Jakub Dawidek valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 356c58794deSPawel Jakub Dawidek if (valp == NULL) { 357c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "keyno"); 358c58794deSPawel Jakub Dawidek return; 359c58794deSPawel Jakub Dawidek } 360c58794deSPawel Jakub Dawidek if (*valp != -1) 361c58794deSPawel Jakub Dawidek nkey = *valp; 362c58794deSPawel Jakub Dawidek else 363c58794deSPawel Jakub Dawidek nkey = sc->sc_nkey; 364c58794deSPawel Jakub Dawidek if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 365c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "keyno"); 366c58794deSPawel Jakub Dawidek return; 367c58794deSPawel Jakub Dawidek } 368c58794deSPawel Jakub Dawidek 369c58794deSPawel Jakub Dawidek key = gctl_get_param(req, "key", &keysize); 370c58794deSPawel Jakub Dawidek if (key == NULL || keysize != G_ELI_USERKEYLEN) { 371c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 372c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "key"); 373c58794deSPawel Jakub Dawidek return; 374c58794deSPawel Jakub Dawidek } 375c58794deSPawel Jakub Dawidek 376c58794deSPawel Jakub Dawidek mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 377c58794deSPawel Jakub Dawidek md.md_keys |= (1 << nkey); 378c58794deSPawel Jakub Dawidek 379c58794deSPawel Jakub Dawidek bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey)); 380c58794deSPawel Jakub Dawidek bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey), 381c58794deSPawel Jakub Dawidek sizeof(sc->sc_datakey)); 382c58794deSPawel Jakub Dawidek 383c58794deSPawel Jakub Dawidek /* Encrypt Master Key with the new key. */ 384c58794deSPawel Jakub Dawidek error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst); 385c58794deSPawel Jakub Dawidek bzero(key, sizeof(key)); 386c58794deSPawel Jakub Dawidek if (error != 0) { 387c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 388c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot encrypt Master Key (error=%d).", error); 389c58794deSPawel Jakub Dawidek return; 390c58794deSPawel Jakub Dawidek } 391c58794deSPawel Jakub Dawidek 392c58794deSPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 393c58794deSPawel Jakub Dawidek /* Store metadata with fresh key. */ 394c58794deSPawel Jakub Dawidek eli_metadata_encode(&md, sector); 395c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 396c58794deSPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 397c58794deSPawel Jakub Dawidek pp->sectorsize); 398c58794deSPawel Jakub Dawidek bzero(sector, sizeof(sector)); 399c58794deSPawel Jakub Dawidek free(sector, M_ELI); 400c58794deSPawel Jakub Dawidek if (error != 0) { 401c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot store metadata on %s (error=%d).", 402c58794deSPawel Jakub Dawidek pp->name, error); 403c58794deSPawel Jakub Dawidek return; 404c58794deSPawel Jakub Dawidek } 405c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name); 406c58794deSPawel Jakub Dawidek } 407c58794deSPawel Jakub Dawidek 408c58794deSPawel Jakub Dawidek static void 409c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) 410c58794deSPawel Jakub Dawidek { 411c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 412c58794deSPawel Jakub Dawidek struct g_eli_metadata md; 413c58794deSPawel Jakub Dawidek struct g_provider *pp; 414c58794deSPawel Jakub Dawidek struct g_consumer *cp; 415c58794deSPawel Jakub Dawidek const char *name; 416c58794deSPawel Jakub Dawidek u_char *mkeydst, *sector; 417c58794deSPawel Jakub Dawidek intmax_t *valp; 418c58794deSPawel Jakub Dawidek size_t keysize; 419c58794deSPawel Jakub Dawidek int error, nkey, *all, *force; 420c58794deSPawel Jakub Dawidek u_int i; 421c58794deSPawel Jakub Dawidek 422c58794deSPawel Jakub Dawidek g_topology_assert(); 423c58794deSPawel Jakub Dawidek 424c58794deSPawel Jakub Dawidek nkey = 0; /* fixes causeless gcc warning */ 425c58794deSPawel Jakub Dawidek 426c58794deSPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 427c58794deSPawel Jakub Dawidek if (name == NULL) { 428c58794deSPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 429c58794deSPawel Jakub Dawidek return; 430c58794deSPawel Jakub Dawidek } 431c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, name); 432c58794deSPawel Jakub Dawidek if (sc == NULL) { 433c58794deSPawel Jakub Dawidek gctl_error(req, "Provider %s is invalid.", name); 434c58794deSPawel Jakub Dawidek return; 435c58794deSPawel Jakub Dawidek } 436c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 437c58794deSPawel Jakub Dawidek pp = cp->provider; 438c58794deSPawel Jakub Dawidek 439c58794deSPawel Jakub Dawidek error = g_eli_read_metadata(mp, pp, &md); 440c58794deSPawel Jakub Dawidek if (error != 0) { 441c58794deSPawel Jakub Dawidek gctl_error(req, "Cannot read metadata from %s (error=%d).", 442c58794deSPawel Jakub Dawidek name, error); 443c58794deSPawel Jakub Dawidek return; 444c58794deSPawel Jakub Dawidek } 445c58794deSPawel Jakub Dawidek 446c58794deSPawel Jakub Dawidek all = gctl_get_paraml(req, "all", sizeof(*all)); 447c58794deSPawel Jakub Dawidek if (all == NULL) { 448c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "all"); 449c58794deSPawel Jakub Dawidek return; 450c58794deSPawel Jakub Dawidek } 451c58794deSPawel Jakub Dawidek 452c58794deSPawel Jakub Dawidek if (*all) { 453c58794deSPawel Jakub Dawidek mkeydst = md.md_mkeys; 454c58794deSPawel Jakub Dawidek keysize = sizeof(md.md_mkeys); 455c58794deSPawel Jakub Dawidek } else { 456c58794deSPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force)); 457c58794deSPawel Jakub Dawidek if (force == NULL) { 458c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force"); 459c58794deSPawel Jakub Dawidek return; 460c58794deSPawel Jakub Dawidek } 461c58794deSPawel Jakub Dawidek 462c58794deSPawel Jakub Dawidek valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 463c58794deSPawel Jakub Dawidek if (valp == NULL) { 464c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "keyno"); 465c58794deSPawel Jakub Dawidek return; 466c58794deSPawel Jakub Dawidek } 467c58794deSPawel Jakub Dawidek if (*valp != -1) 468c58794deSPawel Jakub Dawidek nkey = *valp; 469c58794deSPawel Jakub Dawidek else 470c58794deSPawel Jakub Dawidek nkey = sc->sc_nkey; 471c58794deSPawel Jakub Dawidek if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 472c58794deSPawel Jakub Dawidek gctl_error(req, "Invalid '%s' argument.", "keyno"); 473c58794deSPawel Jakub Dawidek return; 474c58794deSPawel Jakub Dawidek } 475c58794deSPawel Jakub Dawidek if (!(md.md_keys & (1 << nkey)) && !*force) { 476c58794deSPawel Jakub Dawidek gctl_error(req, "Master Key %u is not set.", nkey); 477c58794deSPawel Jakub Dawidek return; 478c58794deSPawel Jakub Dawidek } 479c58794deSPawel Jakub Dawidek md.md_keys &= ~(1 << nkey); 480c58794deSPawel Jakub Dawidek if (md.md_keys == 0 && !*force) { 481c58794deSPawel Jakub Dawidek gctl_error(req, "This is the last Master Key. Use '-f' " 482c58794deSPawel Jakub Dawidek "flag if you really want to remove it."); 483c58794deSPawel Jakub Dawidek return; 484c58794deSPawel Jakub Dawidek } 485c58794deSPawel Jakub Dawidek mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 486c58794deSPawel Jakub Dawidek keysize = G_ELI_MKEYLEN; 487c58794deSPawel Jakub Dawidek } 488c58794deSPawel Jakub Dawidek 489c58794deSPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 490c58794deSPawel Jakub Dawidek for (i = 0; i <= g_eli_overwrites; i++) { 491c58794deSPawel Jakub Dawidek if (i == g_eli_overwrites) 492c58794deSPawel Jakub Dawidek bzero(mkeydst, keysize); 493c58794deSPawel Jakub Dawidek else 494c58794deSPawel Jakub Dawidek arc4rand(mkeydst, keysize, 0); 495c58794deSPawel Jakub Dawidek /* Store metadata with destroyed key. */ 496c58794deSPawel Jakub Dawidek eli_metadata_encode(&md, sector); 497c58794deSPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 498c58794deSPawel Jakub Dawidek pp->sectorsize); 499c58794deSPawel Jakub Dawidek if (error != 0) { 500c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot store metadata on %s " 501c58794deSPawel Jakub Dawidek "(error=%d).", pp->name, error); 502c58794deSPawel Jakub Dawidek } 503c58794deSPawel Jakub Dawidek } 504c58794deSPawel Jakub Dawidek bzero(&md, sizeof(md)); 505c58794deSPawel Jakub Dawidek bzero(sector, sizeof(sector)); 506c58794deSPawel Jakub Dawidek free(sector, M_ELI); 507c58794deSPawel Jakub Dawidek if (*all) 508c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "All keys removed from %s.", pp->name); 509c58794deSPawel Jakub Dawidek else 510c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name); 511c58794deSPawel Jakub Dawidek } 512c58794deSPawel Jakub Dawidek 513c58794deSPawel Jakub Dawidek static int 514c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc) 515c58794deSPawel Jakub Dawidek { 516c58794deSPawel Jakub Dawidek struct g_provider *pp; 517c58794deSPawel Jakub Dawidek struct g_consumer *cp; 518c58794deSPawel Jakub Dawidek u_char *sector; 519c58794deSPawel Jakub Dawidek int err, error = 0; 520c58794deSPawel Jakub Dawidek u_int i; 521c58794deSPawel Jakub Dawidek 522c58794deSPawel Jakub Dawidek g_topology_assert(); 523c58794deSPawel Jakub Dawidek 524c58794deSPawel Jakub Dawidek if (sc == NULL) 525c58794deSPawel Jakub Dawidek return (ENOENT); 526c58794deSPawel Jakub Dawidek 527c58794deSPawel Jakub Dawidek pp = LIST_FIRST(&sc->sc_geom->provider); 528c58794deSPawel Jakub Dawidek g_error_provider(pp, ENXIO); 529c58794deSPawel Jakub Dawidek 530c58794deSPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_geom->consumer); 531c58794deSPawel Jakub Dawidek pp = cp->provider; 532c58794deSPawel Jakub Dawidek 533c58794deSPawel Jakub Dawidek sector = malloc(pp->sectorsize, M_ELI, M_WAITOK); 534c58794deSPawel Jakub Dawidek for (i = 0; i <= g_eli_overwrites; i++) { 535c58794deSPawel Jakub Dawidek if (i == g_eli_overwrites) 536c58794deSPawel Jakub Dawidek bzero(sector, pp->sectorsize); 537c58794deSPawel Jakub Dawidek else 538c58794deSPawel Jakub Dawidek arc4rand(sector, pp->sectorsize, 0); 539c58794deSPawel Jakub Dawidek err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 540c58794deSPawel Jakub Dawidek pp->sectorsize); 541c58794deSPawel Jakub Dawidek if (err != 0) { 542c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "Cannot erase metadata on %s " 543c58794deSPawel Jakub Dawidek "(error=%d).", pp->name, err); 544c58794deSPawel Jakub Dawidek if (error == 0) 545c58794deSPawel Jakub Dawidek error = err; 546c58794deSPawel Jakub Dawidek } 547c58794deSPawel Jakub Dawidek } 548c58794deSPawel Jakub Dawidek free(sector, M_ELI); 549c58794deSPawel Jakub Dawidek if (error == 0) 550c58794deSPawel Jakub Dawidek G_ELI_DEBUG(0, "%s has been killed.", pp->name); 551c58794deSPawel Jakub Dawidek g_eli_destroy(sc, 1); 552c58794deSPawel Jakub Dawidek return (error); 553c58794deSPawel Jakub Dawidek } 554c58794deSPawel Jakub Dawidek 555c58794deSPawel Jakub Dawidek static void 556c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp) 557c58794deSPawel Jakub Dawidek { 558c58794deSPawel Jakub Dawidek int *all, *nargs; 559c58794deSPawel Jakub Dawidek int error; 560c58794deSPawel Jakub Dawidek 561c58794deSPawel Jakub Dawidek g_topology_assert(); 562c58794deSPawel Jakub Dawidek 563c58794deSPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 564c58794deSPawel Jakub Dawidek if (nargs == NULL) { 565c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 566c58794deSPawel Jakub Dawidek return; 567c58794deSPawel Jakub Dawidek } 568c58794deSPawel Jakub Dawidek all = gctl_get_paraml(req, "all", sizeof(*all)); 569c58794deSPawel Jakub Dawidek if (all == NULL) { 570c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "all"); 571c58794deSPawel Jakub Dawidek return; 572c58794deSPawel Jakub Dawidek } 573c58794deSPawel Jakub Dawidek if (!*all && *nargs == 0) { 574c58794deSPawel Jakub Dawidek gctl_error(req, "Too few arguments."); 575c58794deSPawel Jakub Dawidek return; 576c58794deSPawel Jakub Dawidek } 577c58794deSPawel Jakub Dawidek 578c58794deSPawel Jakub Dawidek if (*all) { 579c58794deSPawel Jakub Dawidek struct g_geom *gp, *gp2; 580c58794deSPawel Jakub Dawidek 581c58794deSPawel Jakub Dawidek LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 582c58794deSPawel Jakub Dawidek error = g_eli_kill_one(gp->softc); 583c58794deSPawel Jakub Dawidek if (error != 0) 584c58794deSPawel Jakub Dawidek gctl_error(req, "Not fully done."); 585c58794deSPawel Jakub Dawidek } 586c58794deSPawel Jakub Dawidek } else { 587c58794deSPawel Jakub Dawidek struct g_eli_softc *sc; 588c58794deSPawel Jakub Dawidek const char *prov; 589c58794deSPawel Jakub Dawidek char param[16]; 590c58794deSPawel Jakub Dawidek int i; 591c58794deSPawel Jakub Dawidek 592c58794deSPawel Jakub Dawidek for (i = 0; i < *nargs; i++) { 593c58794deSPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i); 594c58794deSPawel Jakub Dawidek prov = gctl_get_asciiparam(req, param); 595c58794deSPawel Jakub Dawidek 596c58794deSPawel Jakub Dawidek sc = g_eli_find_device(mp, prov); 597c58794deSPawel Jakub Dawidek if (sc == NULL) { 598c58794deSPawel Jakub Dawidek G_ELI_DEBUG(1, "No such provider: %s.", prov); 599c58794deSPawel Jakub Dawidek continue; 600c58794deSPawel Jakub Dawidek } 601c58794deSPawel Jakub Dawidek error = g_eli_kill_one(sc); 602c58794deSPawel Jakub Dawidek if (error != 0) 603c58794deSPawel Jakub Dawidek gctl_error(req, "Not fully done."); 604c58794deSPawel Jakub Dawidek } 605c58794deSPawel Jakub Dawidek } 606c58794deSPawel Jakub Dawidek } 607c58794deSPawel Jakub Dawidek 608c58794deSPawel Jakub Dawidek void 609c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb) 610c58794deSPawel Jakub Dawidek { 611c58794deSPawel Jakub Dawidek uint32_t *version; 612c58794deSPawel Jakub Dawidek 613c58794deSPawel Jakub Dawidek g_topology_assert(); 614c58794deSPawel Jakub Dawidek 615c58794deSPawel Jakub Dawidek version = gctl_get_paraml(req, "version", sizeof(*version)); 616c58794deSPawel Jakub Dawidek if (version == NULL) { 617c58794deSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "version"); 618c58794deSPawel Jakub Dawidek return; 619c58794deSPawel Jakub Dawidek } 620c58794deSPawel Jakub Dawidek if (*version != G_ELI_VERSION) { 621c58794deSPawel Jakub Dawidek gctl_error(req, "Userland and kernel parts are out of sync."); 622c58794deSPawel Jakub Dawidek return; 623c58794deSPawel Jakub Dawidek } 624c58794deSPawel Jakub Dawidek 625c58794deSPawel Jakub Dawidek if (strcmp(verb, "attach") == 0) 626c58794deSPawel Jakub Dawidek g_eli_ctl_attach(req, mp); 627c58794deSPawel Jakub Dawidek else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0) 628c58794deSPawel Jakub Dawidek g_eli_ctl_detach(req, mp); 629c58794deSPawel Jakub Dawidek else if (strcmp(verb, "onetime") == 0) 630c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(req, mp); 631c58794deSPawel Jakub Dawidek else if (strcmp(verb, "setkey") == 0) 632c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(req, mp); 633c58794deSPawel Jakub Dawidek else if (strcmp(verb, "delkey") == 0) 634c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(req, mp); 635c58794deSPawel Jakub Dawidek else if (strcmp(verb, "kill") == 0) 636c58794deSPawel Jakub Dawidek g_eli_ctl_kill(req, mp); 637c58794deSPawel Jakub Dawidek else 638c58794deSPawel Jakub Dawidek gctl_error(req, "Unknown verb."); 639c58794deSPawel Jakub Dawidek } 640