g_eli_ctl.c revision 212547
1211201Stakawata/*- 2211201Stakawata * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3211201Stakawata * All rights reserved. 4211201Stakawata * 5211201Stakawata * Redistribution and use in source and binary forms, with or without 6211201Stakawata * modification, are permitted provided that the following conditions 7211201Stakawata * are met: 8211201Stakawata * 1. Redistributions of source code must retain the above copyright 9211201Stakawata * notice, this list of conditions and the following disclaimer. 10211201Stakawata * 2. Redistributions in binary form must reproduce the above copyright 11211201Stakawata * notice, this list of conditions and the following disclaimer in the 12211201Stakawata * documentation and/or other materials provided with the distribution. 13211201Stakawata * 14211201Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15211201Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16211201Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17211201Stakawata * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18211201Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19211201Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20211201Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21211201Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22211201Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23211201Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24211201Stakawata * SUCH DAMAGE. 25211201Stakawata */ 26211201Stakawata 27211201Stakawata#include <sys/cdefs.h> 28211201Stakawata__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 212547 2010-09-13 08:56:07Z pjd $"); 29211201Stakawata 30211201Stakawata#include <sys/param.h> 31211201Stakawata#include <sys/systm.h> 32211201Stakawata#include <sys/kernel.h> 33211201Stakawata#include <sys/module.h> 34211201Stakawata#include <sys/lock.h> 35211201Stakawata#include <sys/mutex.h> 36211201Stakawata#include <sys/bio.h> 37211201Stakawata#include <sys/sysctl.h> 38211201Stakawata#include <sys/malloc.h> 39211201Stakawata#include <sys/kthread.h> 40211201Stakawata#include <sys/proc.h> 41211201Stakawata#include <sys/sched.h> 42211201Stakawata#include <sys/uio.h> 43211201Stakawata 44211201Stakawata#include <vm/uma.h> 45211201Stakawata 46211201Stakawata#include <geom/geom.h> 47211201Stakawata#include <geom/eli/g_eli.h> 48211201Stakawata 49211201Stakawata 50211201StakawataMALLOC_DECLARE(M_ELI); 51211201Stakawata 52211201Stakawata 53211201Stakawatastatic void 54211201Stakawatag_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) 55211201Stakawata{ 56211201Stakawata struct g_eli_metadata md; 57211201Stakawata struct g_provider *pp; 58211201Stakawata const char *name; 59211201Stakawata u_char *key, mkey[G_ELI_DATAIVKEYLEN]; 60211201Stakawata int *nargs, *detach, *readonly; 61211201Stakawata int keysize, error; 62211201Stakawata u_int nkey; 63211201Stakawata 64211201Stakawata g_topology_assert(); 65211201Stakawata 66211201Stakawata nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 67211201Stakawata if (nargs == NULL) { 68211201Stakawata gctl_error(req, "No '%s' argument.", "nargs"); 69211201Stakawata return; 70211201Stakawata } 71211201Stakawata if (*nargs != 1) { 72211201Stakawata gctl_error(req, "Invalid number of arguments."); 73211201Stakawata return; 74211201Stakawata } 75211201Stakawata 76211201Stakawata detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 77211201Stakawata if (detach == NULL) { 78211201Stakawata gctl_error(req, "No '%s' argument.", "detach"); 79211201Stakawata return; 80211201Stakawata } 81211201Stakawata 82211201Stakawata readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly)); 83211201Stakawata if (readonly == NULL) { 84211201Stakawata gctl_error(req, "No '%s' argument.", "readonly"); 85211201Stakawata return; 86211201Stakawata } 87211201Stakawata 88211201Stakawata name = gctl_get_asciiparam(req, "arg0"); 89211201Stakawata if (name == NULL) { 90211201Stakawata gctl_error(req, "No 'arg%u' argument.", 0); 91211201Stakawata return; 92211201Stakawata } 93211201Stakawata if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 94211201Stakawata name += strlen("/dev/"); 95211201Stakawata pp = g_provider_by_name(name); 96211201Stakawata if (pp == NULL) { 97211201Stakawata gctl_error(req, "Provider %s is invalid.", name); 98211201Stakawata return; 99211201Stakawata } 100211201Stakawata error = g_eli_read_metadata(mp, pp, &md); 101211201Stakawata if (error != 0) { 102211201Stakawata gctl_error(req, "Cannot read metadata from %s (error=%d).", 103211201Stakawata name, error); 104211201Stakawata return; 105211201Stakawata } 106211201Stakawata if (md.md_keys == 0x00) { 107211201Stakawata bzero(&md, sizeof(md)); 108211201Stakawata gctl_error(req, "No valid keys on %s.", pp->name); 109211201Stakawata return; 110211201Stakawata } 111211201Stakawata 112211201Stakawata key = gctl_get_param(req, "key", &keysize); 113211201Stakawata if (key == NULL || keysize != G_ELI_USERKEYLEN) { 114211201Stakawata bzero(&md, sizeof(md)); 115211201Stakawata gctl_error(req, "No '%s' argument.", "key"); 116211201Stakawata return; 117211201Stakawata } 118211201Stakawata 119211201Stakawata error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); 120211201Stakawata bzero(key, keysize); 121211201Stakawata if (error == -1) { 122211201Stakawata bzero(&md, sizeof(md)); 123211201Stakawata gctl_error(req, "Wrong key for %s.", pp->name); 124211201Stakawata return; 125211201Stakawata } else if (error > 0) { 126211201Stakawata bzero(&md, sizeof(md)); 127211201Stakawata gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).", 128211201Stakawata pp->name, error); 129211201Stakawata return; 130211201Stakawata } 131211201Stakawata G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); 132211201Stakawata 133211201Stakawata if (*detach && *readonly) { 134211201Stakawata bzero(&md, sizeof(md)); 135211201Stakawata gctl_error(req, "Options -d and -r are mutually exclusive."); 136211201Stakawata return; 137211201Stakawata } 138211201Stakawata if (*detach) 139211201Stakawata md.md_flags |= G_ELI_FLAG_WO_DETACH; 140211201Stakawata if (*readonly) 141211201Stakawata md.md_flags |= G_ELI_FLAG_RO; 142211201Stakawata g_eli_create(req, mp, pp, &md, mkey, nkey); 143211201Stakawata bzero(mkey, sizeof(mkey)); 144211201Stakawata bzero(&md, sizeof(md)); 145211201Stakawata} 146211201Stakawata 147211201Stakawatastatic struct g_eli_softc * 148211201Stakawatag_eli_find_device(struct g_class *mp, const char *prov) 149211201Stakawata{ 150211201Stakawata struct g_eli_softc *sc; 151211201Stakawata struct g_geom *gp; 152211201Stakawata struct g_provider *pp; 153211201Stakawata struct g_consumer *cp; 154211201Stakawata 155211201Stakawata if (strncmp(prov, "/dev/", strlen("/dev/")) == 0) 156211201Stakawata prov += strlen("/dev/"); 157211201Stakawata LIST_FOREACH(gp, &mp->geom, geom) { 158211201Stakawata sc = gp->softc; 159211201Stakawata if (sc == NULL) 160211201Stakawata continue; 161211201Stakawata pp = LIST_FIRST(&gp->provider); 162211201Stakawata if (pp != NULL && strcmp(pp->name, prov) == 0) 163211201Stakawata return (sc); 164211201Stakawata cp = LIST_FIRST(&gp->consumer); 165211201Stakawata if (cp != NULL && cp->provider != NULL && 166211201Stakawata strcmp(cp->provider->name, prov) == 0) { 167211201Stakawata return (sc); 168211201Stakawata } 169211201Stakawata } 170211201Stakawata return (NULL); 171211201Stakawata} 172211201Stakawata 173211201Stakawatastatic void 174211201Stakawatag_eli_ctl_detach(struct gctl_req *req, struct g_class *mp) 175211201Stakawata{ 176211201Stakawata struct g_eli_softc *sc; 177211201Stakawata int *force, *last, *nargs, error; 178211201Stakawata const char *prov; 179211201Stakawata char param[16]; 180211201Stakawata int i; 181211201Stakawata 182211201Stakawata g_topology_assert(); 183211201Stakawata 184211201Stakawata nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 185211201Stakawata if (nargs == NULL) { 186211201Stakawata gctl_error(req, "No '%s' argument.", "nargs"); 187211201Stakawata return; 188211201Stakawata } 189211201Stakawata if (*nargs <= 0) { 190211201Stakawata gctl_error(req, "Missing device(s)."); 191211201Stakawata return; 192211201Stakawata } 193211201Stakawata force = gctl_get_paraml(req, "force", sizeof(*force)); 194211201Stakawata if (force == NULL) { 195211201Stakawata gctl_error(req, "No '%s' argument.", "force"); 196211201Stakawata return; 197211201Stakawata } 198211201Stakawata last = gctl_get_paraml(req, "last", sizeof(*last)); 199211201Stakawata if (last == NULL) { 200211201Stakawata gctl_error(req, "No '%s' argument.", "last"); 201211201Stakawata return; 202211201Stakawata } 203211201Stakawata 204211201Stakawata for (i = 0; i < *nargs; i++) { 205211201Stakawata snprintf(param, sizeof(param), "arg%d", i); 206211201Stakawata prov = gctl_get_asciiparam(req, param); 207211201Stakawata if (prov == NULL) { 208211201Stakawata gctl_error(req, "No 'arg%d' argument.", i); 209211201Stakawata return; 210211201Stakawata } 211211201Stakawata sc = g_eli_find_device(mp, prov); 212211201Stakawata if (sc == NULL) { 213211201Stakawata gctl_error(req, "No such device: %s.", prov); 214211201Stakawata return; 215211201Stakawata } 216211201Stakawata if (*last) { 217211201Stakawata sc->sc_flags |= G_ELI_FLAG_RW_DETACH; 218211201Stakawata sc->sc_geom->access = g_eli_access; 219211201Stakawata } else { 220211201Stakawata error = g_eli_destroy(sc, *force); 221211201Stakawata if (error != 0) { 222211201Stakawata gctl_error(req, 223211201Stakawata "Cannot destroy device %s (error=%d).", 224211201Stakawata sc->sc_name, error); 225211201Stakawata return; 226211201Stakawata } 227211201Stakawata } 228211201Stakawata } 229211201Stakawata} 230211201Stakawata 231211201Stakawatastatic void 232211201Stakawatag_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) 233211201Stakawata{ 234211201Stakawata struct g_eli_metadata md; 235211201Stakawata struct g_provider *pp; 236211201Stakawata const char *name; 237211201Stakawata intmax_t *keylen, *sectorsize; 238211201Stakawata u_char mkey[G_ELI_DATAIVKEYLEN]; 239211201Stakawata int *nargs, *detach; 240211201Stakawata 241211201Stakawata g_topology_assert(); 242211201Stakawata bzero(&md, sizeof(md)); 243211201Stakawata 244211201Stakawata nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 245211201Stakawata if (nargs == NULL) { 246211201Stakawata gctl_error(req, "No '%s' argument.", "nargs"); 247211201Stakawata return; 248211201Stakawata } 249211201Stakawata if (*nargs != 1) { 250211201Stakawata gctl_error(req, "Invalid number of arguments."); 251211201Stakawata return; 252211201Stakawata } 253211201Stakawata 254211201Stakawata detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 255211201Stakawata if (detach == NULL) { 256211201Stakawata gctl_error(req, "No '%s' argument.", "detach"); 257211201Stakawata return; 258211201Stakawata } 259211201Stakawata 260211201Stakawata strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 261211201Stakawata md.md_version = G_ELI_VERSION; 262211201Stakawata md.md_flags |= G_ELI_FLAG_ONETIME; 263211201Stakawata if (*detach) 264211201Stakawata md.md_flags |= G_ELI_FLAG_WO_DETACH; 265211201Stakawata 266211201Stakawata md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 267211201Stakawata name = gctl_get_asciiparam(req, "aalgo"); 268211201Stakawata if (name == NULL) { 269211201Stakawata gctl_error(req, "No '%s' argument.", "aalgo"); 270211201Stakawata return; 271211201Stakawata } 272211201Stakawata if (*name != '\0') { 273211201Stakawata md.md_aalgo = g_eli_str2aalgo(name); 274211201Stakawata if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 275211201Stakawata md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 276211201Stakawata md.md_flags |= G_ELI_FLAG_AUTH; 277211201Stakawata } else { 278211201Stakawata /* 279211201Stakawata * For backward compatibility, check if the -a option 280211201Stakawata * was used to provide encryption algorithm. 281211201Stakawata */ 282211201Stakawata md.md_ealgo = g_eli_str2ealgo(name); 283211201Stakawata if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 284211201Stakawata md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 285211201Stakawata gctl_error(req, 286211201Stakawata "Invalid authentication algorithm."); 287211201Stakawata return; 288211201Stakawata } else { 289211201Stakawata gctl_error(req, "warning: The -e option, not " 290211201Stakawata "the -a option is now used to specify " 291211201Stakawata "encryption algorithm to use."); 292211201Stakawata } 293211201Stakawata } 294211201Stakawata } 295211201Stakawata 296211201Stakawata if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 297211201Stakawata md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 298211201Stakawata name = gctl_get_asciiparam(req, "ealgo"); 299211201Stakawata if (name == NULL) { 300211201Stakawata gctl_error(req, "No '%s' argument.", "ealgo"); 301211201Stakawata return; 302211201Stakawata } 303211201Stakawata md.md_ealgo = g_eli_str2ealgo(name); 304211201Stakawata if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 305211201Stakawata md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 306211201Stakawata gctl_error(req, "Invalid encryption algorithm."); 307211201Stakawata return; 308211201Stakawata } 309211201Stakawata } 310211201Stakawata 311211201Stakawata keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen)); 312211201Stakawata if (keylen == NULL) { 313211201Stakawata gctl_error(req, "No '%s' argument.", "keylen"); 314211201Stakawata return; 315211201Stakawata } 316211201Stakawata md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen); 317211201Stakawata if (md.md_keylen == 0) { 318211201Stakawata gctl_error(req, "Invalid '%s' argument.", "keylen"); 319211201Stakawata return; 320211201Stakawata } 321211201Stakawata 322211201Stakawata /* Not important here. */ 323211201Stakawata md.md_provsize = 0; 324211201Stakawata /* Not important here. */ 325211201Stakawata bzero(md.md_salt, sizeof(md.md_salt)); 326211201Stakawata 327211201Stakawata md.md_keys = 0x01; 328211201Stakawata arc4rand(mkey, sizeof(mkey), 0); 329211201Stakawata 330211201Stakawata /* Not important here. */ 331211201Stakawata bzero(md.md_hash, sizeof(md.md_hash)); 332211201Stakawata 333211201Stakawata name = gctl_get_asciiparam(req, "arg0"); 334211201Stakawata if (name == NULL) { 335211201Stakawata gctl_error(req, "No 'arg%u' argument.", 0); 336211201Stakawata return; 337211201Stakawata } 338211201Stakawata if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 339211201Stakawata name += strlen("/dev/"); 340211201Stakawata pp = g_provider_by_name(name); 341211201Stakawata if (pp == NULL) { 342211201Stakawata gctl_error(req, "Provider %s is invalid.", name); 343211201Stakawata return; 344211201Stakawata } 345211201Stakawata 346211201Stakawata sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize)); 347211201Stakawata if (sectorsize == NULL) { 348211201Stakawata gctl_error(req, "No '%s' argument.", "sectorsize"); 349211201Stakawata return; 350211201Stakawata } 351211201Stakawata if (*sectorsize == 0) 352211201Stakawata md.md_sectorsize = pp->sectorsize; 353211201Stakawata else { 354211201Stakawata if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) { 355211201Stakawata gctl_error(req, "Invalid sector size."); 356211201Stakawata return; 357211201Stakawata } 358211201Stakawata if (*sectorsize > PAGE_SIZE) { 359211201Stakawata gctl_error(req, "warning: Using sectorsize bigger than " 360211201Stakawata "the page size!"); 361211201Stakawata } 362211201Stakawata md.md_sectorsize = *sectorsize; 363211201Stakawata } 364211201Stakawata 365211201Stakawata g_eli_create(req, mp, pp, &md, mkey, -1); 366211201Stakawata bzero(mkey, sizeof(mkey)); 367211201Stakawata bzero(&md, sizeof(md)); 368211201Stakawata} 369211201Stakawata 370211201Stakawatastatic void 371211201Stakawatag_eli_ctl_configure(struct gctl_req *req, struct g_class *mp) 372211201Stakawata{ 373211201Stakawata struct g_eli_softc *sc; 374211201Stakawata struct g_eli_metadata md; 375211201Stakawata struct g_provider *pp; 376211201Stakawata struct g_consumer *cp; 377211201Stakawata char param[16]; 378211201Stakawata const char *prov; 379211201Stakawata u_char *sector; 380211201Stakawata int *nargs, *boot, *noboot; 381211201Stakawata int error; 382211201Stakawata u_int i; 383211201Stakawata 384211201Stakawata g_topology_assert(); 385211201Stakawata 386211201Stakawata nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 387211201Stakawata if (nargs == NULL) { 388211201Stakawata gctl_error(req, "No '%s' argument.", "nargs"); 389211201Stakawata return; 390211201Stakawata } 391211201Stakawata if (*nargs <= 0) { 392211201Stakawata gctl_error(req, "Missing device(s)."); 393211201Stakawata return; 394211201Stakawata } 395211201Stakawata 396211201Stakawata boot = gctl_get_paraml(req, "boot", sizeof(*boot)); 397211201Stakawata if (boot == NULL) { 398211201Stakawata gctl_error(req, "No '%s' argument.", "boot"); 399211201Stakawata return; 400211201Stakawata } 401211201Stakawata noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot)); 402211201Stakawata if (noboot == NULL) { 403211201Stakawata gctl_error(req, "No '%s' argument.", "noboot"); 404211201Stakawata return; 405211201Stakawata } 406211201Stakawata if (*boot && *noboot) { 407211201Stakawata gctl_error(req, "Options -b and -B are mutually exclusive."); 408211201Stakawata return; 409211201Stakawata } 410211201Stakawata if (!*boot && !*noboot) { 411211201Stakawata gctl_error(req, "No option given."); 412211201Stakawata return; 413211201Stakawata } 414211201Stakawata 415211201Stakawata for (i = 0; i < *nargs; i++) { 416211201Stakawata snprintf(param, sizeof(param), "arg%d", i); 417211201Stakawata prov = gctl_get_asciiparam(req, param); 418211201Stakawata if (prov == NULL) { 419211201Stakawata gctl_error(req, "No 'arg%d' argument.", i); 420211201Stakawata return; 421211201Stakawata } 422211201Stakawata sc = g_eli_find_device(mp, prov); 423211201Stakawata if (sc == NULL) { 424211201Stakawata /* 425211201Stakawata * We ignore not attached providers, userland part will 426211201Stakawata * take care of them. 427211201Stakawata */ 428211201Stakawata G_ELI_DEBUG(1, "Skipping configuration of not attached " 429211201Stakawata "provider %s.", prov); 430211201Stakawata continue; 431211201Stakawata } 432211201Stakawata if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) { 433211201Stakawata G_ELI_DEBUG(1, "BOOT flag already configured for %s.", 434211201Stakawata prov); 435211201Stakawata continue; 436211201Stakawata } else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) { 437211201Stakawata G_ELI_DEBUG(1, "BOOT flag not configured for %s.", 438211201Stakawata prov); 439211201Stakawata continue; 440211201Stakawata } 441211201Stakawata if (sc->sc_flags & G_ELI_FLAG_RO) { 442211201Stakawata gctl_error(req, "Cannot change configuration of " 443211201Stakawata "read-only provider %s.", prov); 444211201Stakawata continue; 445211201Stakawata } 446211201Stakawata cp = LIST_FIRST(&sc->sc_geom->consumer); 447211201Stakawata pp = cp->provider; 448211201Stakawata error = g_eli_read_metadata(mp, pp, &md); 449211201Stakawata if (error != 0) { 450211201Stakawata gctl_error(req, 451211201Stakawata "Cannot read metadata from %s (error=%d).", 452211201Stakawata prov, error); 453211201Stakawata continue; 454211201Stakawata } 455211201Stakawata 456211201Stakawata if (*boot) { 457211201Stakawata md.md_flags |= G_ELI_FLAG_BOOT; 458211201Stakawata sc->sc_flags |= G_ELI_FLAG_BOOT; 459211201Stakawata } else { 460211201Stakawata md.md_flags &= ~G_ELI_FLAG_BOOT; 461211201Stakawata sc->sc_flags &= ~G_ELI_FLAG_BOOT; 462211201Stakawata } 463211201Stakawata 464211201Stakawata sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 465211201Stakawata eli_metadata_encode(&md, sector); 466211201Stakawata error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 467211201Stakawata pp->sectorsize); 468211201Stakawata if (error != 0) { 469211201Stakawata gctl_error(req, 470211201Stakawata "Cannot store metadata on %s (error=%d).", 471211201Stakawata prov, error); 472211201Stakawata } 473211201Stakawata bzero(&md, sizeof(md)); 474211201Stakawata bzero(sector, sizeof(sector)); 475211201Stakawata free(sector, M_ELI); 476211201Stakawata } 477211201Stakawata} 478211201Stakawata 479211201Stakawatastatic void 480211201Stakawatag_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp) 481211201Stakawata{ 482211201Stakawata struct g_eli_softc *sc; 483211201Stakawata struct g_eli_metadata md; 484211201Stakawata struct g_provider *pp; 485211201Stakawata struct g_consumer *cp; 486211201Stakawata const char *name; 487211201Stakawata u_char *key, *mkeydst, *sector; 488211201Stakawata intmax_t *valp; 489211201Stakawata int keysize, nkey, error; 490211201Stakawata 491211201Stakawata g_topology_assert(); 492211201Stakawata 493211201Stakawata name = gctl_get_asciiparam(req, "arg0"); 494211201Stakawata if (name == NULL) { 495211201Stakawata gctl_error(req, "No 'arg%u' argument.", 0); 496211201Stakawata return; 497211201Stakawata } 498211201Stakawata sc = g_eli_find_device(mp, name); 499211201Stakawata if (sc == NULL) { 500211201Stakawata gctl_error(req, "Provider %s is invalid.", name); 501211201Stakawata return; 502211201Stakawata } 503211201Stakawata if (sc->sc_flags & G_ELI_FLAG_RO) { 504211201Stakawata gctl_error(req, "Cannot change keys for read-only provider."); 505211201Stakawata return; 506211201Stakawata } 507211201Stakawata cp = LIST_FIRST(&sc->sc_geom->consumer); 508211201Stakawata pp = cp->provider; 509211201Stakawata 510211201Stakawata error = g_eli_read_metadata(mp, pp, &md); 511211201Stakawata if (error != 0) { 512211201Stakawata gctl_error(req, "Cannot read metadata from %s (error=%d).", 513211201Stakawata name, error); 514211201Stakawata return; 515211201Stakawata } 516211201Stakawata 517211201Stakawata valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 518211201Stakawata if (valp == NULL) { 519211201Stakawata gctl_error(req, "No '%s' argument.", "keyno"); 520211201Stakawata return; 521211201Stakawata } 522211201Stakawata if (*valp != -1) 523211201Stakawata nkey = *valp; 524211201Stakawata else 525211201Stakawata nkey = sc->sc_nkey; 526211201Stakawata if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 527211201Stakawata gctl_error(req, "Invalid '%s' argument.", "keyno"); 528211201Stakawata return; 529211201Stakawata } 530211201Stakawata 531211201Stakawata valp = gctl_get_paraml(req, "iterations", sizeof(*valp)); 532211201Stakawata if (valp == NULL) { 533211201Stakawata gctl_error(req, "No '%s' argument.", "iterations"); 534211201Stakawata return; 535211201Stakawata } 536211201Stakawata /* Check if iterations number should and can be changed. */ 537211201Stakawata if (*valp != -1) { 538211201Stakawata if (bitcount32(md.md_keys) != 1) { 539211201Stakawata gctl_error(req, "To be able to use '-i' option, only " 540211201Stakawata "one key can be defined."); 541211201Stakawata return; 542211201Stakawata } 543211201Stakawata if (md.md_keys != (1 << nkey)) { 544211201Stakawata gctl_error(req, "Only already defined key can be " 545211201Stakawata "changed when '-i' option is used."); 546211201Stakawata return; 547211201Stakawata } 548211201Stakawata md.md_iterations = *valp; 549211201Stakawata } 550211201Stakawata 551211201Stakawata key = gctl_get_param(req, "key", &keysize); 552211201Stakawata if (key == NULL || keysize != G_ELI_USERKEYLEN) { 553211201Stakawata bzero(&md, sizeof(md)); 554211201Stakawata gctl_error(req, "No '%s' argument.", "key"); 555211201Stakawata return; 556211201Stakawata } 557211201Stakawata 558211201Stakawata mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 559211201Stakawata md.md_keys |= (1 << nkey); 560211201Stakawata 561211201Stakawata bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey)); 562211201Stakawata 563211201Stakawata /* Encrypt Master Key with the new key. */ 564211201Stakawata error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst); 565211201Stakawata bzero(key, sizeof(key)); 566211201Stakawata if (error != 0) { 567211201Stakawata bzero(&md, sizeof(md)); 568211201Stakawata gctl_error(req, "Cannot encrypt Master Key (error=%d).", error); 569211201Stakawata return; 570211201Stakawata } 571211201Stakawata 572211201Stakawata sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 573211201Stakawata /* Store metadata with fresh key. */ 574211201Stakawata eli_metadata_encode(&md, sector); 575211201Stakawata bzero(&md, sizeof(md)); 576211201Stakawata error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 577211201Stakawata pp->sectorsize); 578211201Stakawata bzero(sector, sizeof(sector)); 579211201Stakawata free(sector, M_ELI); 580211201Stakawata if (error != 0) { 581211201Stakawata gctl_error(req, "Cannot store metadata on %s (error=%d).", 582211201Stakawata pp->name, error); 583211201Stakawata return; 584211201Stakawata } 585211201Stakawata G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name); 586211201Stakawata} 587211201Stakawata 588211201Stakawatastatic void 589211201Stakawatag_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) 590211201Stakawata{ 591211201Stakawata struct g_eli_softc *sc; 592211201Stakawata struct g_eli_metadata md; 593211201Stakawata struct g_provider *pp; 594211201Stakawata struct g_consumer *cp; 595211201Stakawata const char *name; 596211201Stakawata u_char *mkeydst, *sector; 597211201Stakawata intmax_t *valp; 598211201Stakawata size_t keysize; 599211201Stakawata int error, nkey, *all, *force; 600211201Stakawata u_int i; 601211201Stakawata 602211201Stakawata g_topology_assert(); 603211201Stakawata 604211201Stakawata nkey = 0; /* fixes causeless gcc warning */ 605211201Stakawata 606211201Stakawata name = gctl_get_asciiparam(req, "arg0"); 607211201Stakawata if (name == NULL) { 608211201Stakawata gctl_error(req, "No 'arg%u' argument.", 0); 609211201Stakawata return; 610211201Stakawata } 611211201Stakawata sc = g_eli_find_device(mp, name); 612211201Stakawata if (sc == NULL) { 613211201Stakawata gctl_error(req, "Provider %s is invalid.", name); 614211201Stakawata return; 615211201Stakawata } 616211201Stakawata if (sc->sc_flags & G_ELI_FLAG_RO) { 617211201Stakawata gctl_error(req, "Cannot delete keys for read-only provider."); 618211201Stakawata return; 619211201Stakawata } 620211201Stakawata cp = LIST_FIRST(&sc->sc_geom->consumer); 621211201Stakawata pp = cp->provider; 622211201Stakawata 623211201Stakawata error = g_eli_read_metadata(mp, pp, &md); 624211201Stakawata if (error != 0) { 625211201Stakawata gctl_error(req, "Cannot read metadata from %s (error=%d).", 626211201Stakawata name, error); 627211201Stakawata return; 628211201Stakawata } 629211201Stakawata 630211201Stakawata all = gctl_get_paraml(req, "all", sizeof(*all)); 631211201Stakawata if (all == NULL) { 632211201Stakawata gctl_error(req, "No '%s' argument.", "all"); 633211201Stakawata return; 634211201Stakawata } 635211201Stakawata 636211201Stakawata if (*all) { 637211201Stakawata mkeydst = md.md_mkeys; 638211201Stakawata keysize = sizeof(md.md_mkeys); 639211201Stakawata } else { 640211201Stakawata force = gctl_get_paraml(req, "force", sizeof(*force)); 641211201Stakawata if (force == NULL) { 642211201Stakawata gctl_error(req, "No '%s' argument.", "force"); 643211201Stakawata return; 644211201Stakawata } 645211201Stakawata 646211201Stakawata valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 647211201Stakawata if (valp == NULL) { 648211201Stakawata gctl_error(req, "No '%s' argument.", "keyno"); 649211201Stakawata return; 650211201Stakawata } 651211201Stakawata if (*valp != -1) 652211201Stakawata nkey = *valp; 653211201Stakawata else 654211201Stakawata nkey = sc->sc_nkey; 655211201Stakawata if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 656211201Stakawata gctl_error(req, "Invalid '%s' argument.", "keyno"); 657211201Stakawata return; 658211201Stakawata } 659211201Stakawata if (!(md.md_keys & (1 << nkey)) && !*force) { 660211201Stakawata gctl_error(req, "Master Key %u is not set.", nkey); 661211201Stakawata return; 662211201Stakawata } 663211201Stakawata md.md_keys &= ~(1 << nkey); 664211201Stakawata if (md.md_keys == 0 && !*force) { 665211201Stakawata gctl_error(req, "This is the last Master Key. Use '-f' " 666211201Stakawata "flag if you really want to remove it."); 667211201Stakawata return; 668211201Stakawata } 669211201Stakawata mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 670211201Stakawata keysize = G_ELI_MKEYLEN; 671211201Stakawata } 672211201Stakawata 673211201Stakawata sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 674211201Stakawata for (i = 0; i <= g_eli_overwrites; i++) { 675211201Stakawata if (i == g_eli_overwrites) 676211201Stakawata bzero(mkeydst, keysize); 677211201Stakawata else 678211201Stakawata arc4rand(mkeydst, keysize, 0); 679211201Stakawata /* Store metadata with destroyed key. */ 680211201Stakawata eli_metadata_encode(&md, sector); 681211201Stakawata error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 682211201Stakawata pp->sectorsize); 683211201Stakawata if (error != 0) { 684211201Stakawata G_ELI_DEBUG(0, "Cannot store metadata on %s " 685211201Stakawata "(error=%d).", pp->name, error); 686211201Stakawata } 687211201Stakawata /* 688211201Stakawata * Flush write cache so we don't overwrite data N times in cache 689211201Stakawata * and only once on disk. 690211201Stakawata */ 691211201Stakawata g_io_flush(cp); 692211201Stakawata } 693211201Stakawata bzero(&md, sizeof(md)); 694211201Stakawata bzero(sector, sizeof(sector)); 695211201Stakawata free(sector, M_ELI); 696211201Stakawata if (*all) 697211201Stakawata G_ELI_DEBUG(1, "All keys removed from %s.", pp->name); 698211201Stakawata else 699211201Stakawata G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name); 700211201Stakawata} 701211201Stakawata 702211201Stakawatastatic int 703211201Stakawatag_eli_kill_one(struct g_eli_softc *sc) 704211201Stakawata{ 705211201Stakawata struct g_provider *pp; 706211201Stakawata struct g_consumer *cp; 707211201Stakawata int error = 0; 708211201Stakawata 709211201Stakawata g_topology_assert(); 710211201Stakawata 711211201Stakawata if (sc == NULL) 712211201Stakawata return (ENOENT); 713211201Stakawata 714211201Stakawata pp = LIST_FIRST(&sc->sc_geom->provider); 715211201Stakawata g_error_provider(pp, ENXIO); 716211201Stakawata 717211201Stakawata cp = LIST_FIRST(&sc->sc_geom->consumer); 718211201Stakawata pp = cp->provider; 719211201Stakawata 720211201Stakawata if (sc->sc_flags & G_ELI_FLAG_RO) { 721211201Stakawata G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only " 722211201Stakawata "provider: %s.", pp->name); 723211201Stakawata } else { 724211201Stakawata u_char *sector; 725211201Stakawata u_int i; 726211201Stakawata int err; 727211201Stakawata 728211201Stakawata sector = malloc(pp->sectorsize, M_ELI, M_WAITOK); 729211201Stakawata for (i = 0; i <= g_eli_overwrites; i++) { 730211201Stakawata if (i == g_eli_overwrites) 731211201Stakawata bzero(sector, pp->sectorsize); 732211201Stakawata else 733211201Stakawata arc4rand(sector, pp->sectorsize, 0); 734211201Stakawata err = g_write_data(cp, pp->mediasize - pp->sectorsize, 735211201Stakawata sector, pp->sectorsize); 736211201Stakawata if (err != 0) { 737211201Stakawata G_ELI_DEBUG(0, "Cannot erase metadata on %s " 738211201Stakawata "(error=%d).", pp->name, err); 739211201Stakawata if (error == 0) 740211201Stakawata error = err; 741211201Stakawata } 742211201Stakawata } 743211201Stakawata free(sector, M_ELI); 744211201Stakawata } 745211201Stakawata if (error == 0) 746211201Stakawata G_ELI_DEBUG(0, "%s has been killed.", pp->name); 747211201Stakawata g_eli_destroy(sc, 1); 748211201Stakawata return (error); 749211201Stakawata} 750211201Stakawata 751211201Stakawatastatic void 752211201Stakawatag_eli_ctl_kill(struct gctl_req *req, struct g_class *mp) 753211201Stakawata{ 754211201Stakawata int *all, *nargs; 755211201Stakawata int error; 756211201Stakawata 757211201Stakawata g_topology_assert(); 758211201Stakawata 759211201Stakawata nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 760211201Stakawata if (nargs == NULL) { 761211201Stakawata gctl_error(req, "No '%s' argument.", "nargs"); 762211201Stakawata return; 763211201Stakawata } 764211201Stakawata all = gctl_get_paraml(req, "all", sizeof(*all)); 765211201Stakawata if (all == NULL) { 766211201Stakawata gctl_error(req, "No '%s' argument.", "all"); 767211201Stakawata return; 768211201Stakawata } 769211201Stakawata if (!*all && *nargs == 0) { 770211201Stakawata gctl_error(req, "Too few arguments."); 771211201Stakawata return; 772211201Stakawata } 773211201Stakawata 774211201Stakawata if (*all) { 775211201Stakawata struct g_geom *gp, *gp2; 776211201Stakawata 777211201Stakawata LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 778211201Stakawata error = g_eli_kill_one(gp->softc); 779211201Stakawata if (error != 0) 780211201Stakawata gctl_error(req, "Not fully done."); 781211201Stakawata } 782211201Stakawata } else { 783211201Stakawata struct g_eli_softc *sc; 784211201Stakawata const char *prov; 785211201Stakawata char param[16]; 786211201Stakawata int i; 787211201Stakawata 788211201Stakawata for (i = 0; i < *nargs; i++) { 789211201Stakawata snprintf(param, sizeof(param), "arg%d", i); 790211201Stakawata prov = gctl_get_asciiparam(req, param); 791211201Stakawata if (prov == NULL) { 792211201Stakawata G_ELI_DEBUG(0, "No 'arg%d' argument.", i); 793211201Stakawata continue; 794211201Stakawata } 795211201Stakawata 796211201Stakawata sc = g_eli_find_device(mp, prov); 797211201Stakawata if (sc == NULL) { 798211201Stakawata G_ELI_DEBUG(0, "No such provider: %s.", prov); 799211201Stakawata continue; 800211201Stakawata } 801211201Stakawata error = g_eli_kill_one(sc); 802211201Stakawata if (error != 0) 803211201Stakawata gctl_error(req, "Not fully done."); 804211201Stakawata } 805211201Stakawata } 806211201Stakawata} 807211201Stakawata 808211201Stakawatavoid 809211201Stakawatag_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb) 810211201Stakawata{ 811211201Stakawata uint32_t *version; 812211201Stakawata 813211201Stakawata g_topology_assert(); 814211201Stakawata 815211201Stakawata version = gctl_get_paraml(req, "version", sizeof(*version)); 816211201Stakawata if (version == NULL) { 817211201Stakawata gctl_error(req, "No '%s' argument.", "version"); 818211201Stakawata return; 819211201Stakawata } 820211201Stakawata if (*version != G_ELI_VERSION) { 821211201Stakawata gctl_error(req, "Userland and kernel parts are out of sync."); 822211201Stakawata return; 823211201Stakawata } 824211201Stakawata 825211201Stakawata if (strcmp(verb, "attach") == 0) 826211201Stakawata g_eli_ctl_attach(req, mp); 827211201Stakawata else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0) 828211201Stakawata g_eli_ctl_detach(req, mp); 829211201Stakawata else if (strcmp(verb, "onetime") == 0) 830211201Stakawata g_eli_ctl_onetime(req, mp); 831211201Stakawata else if (strcmp(verb, "configure") == 0) 832211201Stakawata g_eli_ctl_configure(req, mp); 833211201Stakawata else if (strcmp(verb, "setkey") == 0) 834211201Stakawata g_eli_ctl_setkey(req, mp); 835211201Stakawata else if (strcmp(verb, "delkey") == 0) 836211201Stakawata g_eli_ctl_delkey(req, mp); 837211201Stakawata else if (strcmp(verb, "kill") == 0) 838211201Stakawata g_eli_ctl_kill(req, mp); 839211201Stakawata else 840211201Stakawata gctl_error(req, "Unknown verb."); 841211201Stakawata} 842211201Stakawata