g_eli_ctl.c revision 148456
1/*- 2 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_ctl.c 148456 2005-07-27 21:43:37Z pjd $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kernel.h> 33#include <sys/module.h> 34#include <sys/lock.h> 35#include <sys/mutex.h> 36#include <sys/bio.h> 37#include <sys/sysctl.h> 38#include <sys/malloc.h> 39#include <sys/kthread.h> 40#include <sys/proc.h> 41#include <sys/sched.h> 42#include <sys/uio.h> 43 44#include <vm/uma.h> 45 46#include <geom/geom.h> 47#include <geom/eli/g_eli.h> 48 49 50MALLOC_DECLARE(M_ELI); 51 52 53static void 54g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp) 55{ 56 struct g_eli_metadata md; 57 struct g_provider *pp; 58 const char *name; 59 u_char *key, mkey[G_ELI_DATAIVKEYLEN]; 60 int *nargs, *detach; 61 int keysize, error; 62 u_int nkey; 63 64 g_topology_assert(); 65 66 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 67 if (nargs == NULL) { 68 gctl_error(req, "No '%s' argument.", "nargs"); 69 return; 70 } 71 if (*nargs != 1) { 72 gctl_error(req, "Invalid number of arguments."); 73 return; 74 } 75 76 detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 77 if (detach == NULL) { 78 gctl_error(req, "No '%s' argument.", "detach"); 79 return; 80 } 81 82 name = gctl_get_asciiparam(req, "arg0"); 83 if (name == NULL) { 84 gctl_error(req, "No 'arg%u' argument.", 0); 85 return; 86 } 87 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 88 name += strlen("/dev/"); 89 pp = g_provider_by_name(name); 90 if (pp == NULL) { 91 gctl_error(req, "Provider %s is invalid.", name); 92 return; 93 } 94 error = g_eli_read_metadata(mp, pp, &md); 95 if (error != 0) { 96 gctl_error(req, "Cannot read metadata from %s (error=%d).", 97 name, error); 98 return; 99 } 100 if (md.md_keys == 0x00) { 101 bzero(&md, sizeof(md)); 102 gctl_error(req, "No valid keys on %s.", pp->name); 103 return; 104 } 105 106 key = gctl_get_param(req, "key", &keysize); 107 if (key == NULL || keysize != G_ELI_USERKEYLEN) { 108 bzero(&md, sizeof(md)); 109 gctl_error(req, "No '%s' argument.", "key"); 110 return; 111 } 112 113 error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); 114 bzero(key, keysize); 115 if (error == -1) { 116 bzero(&md, sizeof(md)); 117 gctl_error(req, "Wrong key for %s.", pp->name); 118 return; 119 } else if (error > 0) { 120 bzero(&md, sizeof(md)); 121 gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).", 122 pp->name, error); 123 return; 124 } 125 G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); 126 127 if (*detach) 128 md.md_flags |= G_ELI_FLAG_WO_DETACH; 129 g_eli_create(req, mp, pp, &md, mkey, nkey); 130 bzero(mkey, sizeof(mkey)); 131 bzero(&md, sizeof(md)); 132} 133 134static struct g_eli_softc * 135g_eli_find_device(struct g_class *mp, const char *prov) 136{ 137 struct g_eli_softc *sc; 138 struct g_geom *gp; 139 struct g_provider *pp; 140 struct g_consumer *cp; 141 142 if (strncmp(prov, "/dev/", strlen("/dev/")) == 0) 143 prov += strlen("/dev/"); 144 LIST_FOREACH(gp, &mp->geom, geom) { 145 sc = gp->softc; 146 if (sc == NULL) 147 continue; 148 pp = LIST_FIRST(&gp->provider); 149 if (pp != NULL && strcmp(pp->name, prov) == 0) 150 return (sc); 151 cp = LIST_FIRST(&gp->consumer); 152 if (cp != NULL && cp->provider != NULL && 153 strcmp(cp->provider->name, prov) == 0) { 154 return (sc); 155 } 156 } 157 return (NULL); 158} 159 160static void 161g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp) 162{ 163 struct g_eli_softc *sc; 164 int *force, *last, *nargs, error; 165 const char *prov; 166 char param[16]; 167 u_int i; 168 169 g_topology_assert(); 170 171 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 172 if (nargs == NULL) { 173 gctl_error(req, "No '%s' argument.", "nargs"); 174 return; 175 } 176 if (*nargs <= 0) { 177 gctl_error(req, "Missing device(s)."); 178 return; 179 } 180 force = gctl_get_paraml(req, "force", sizeof(*force)); 181 if (force == NULL) { 182 gctl_error(req, "No '%s' argument.", "force"); 183 return; 184 } 185 last = gctl_get_paraml(req, "last", sizeof(*last)); 186 if (last == NULL) { 187 gctl_error(req, "No '%s' argument.", "last"); 188 return; 189 } 190 191 for (i = 0; i < (u_int)*nargs; i++) { 192 snprintf(param, sizeof(param), "arg%u", i); 193 prov = gctl_get_asciiparam(req, param); 194 if (prov == NULL) { 195 gctl_error(req, "No 'arg%u' argument.", i); 196 return; 197 } 198 sc = g_eli_find_device(mp, prov); 199 if (sc == NULL) { 200 gctl_error(req, "No such device: %s.", prov); 201 return; 202 } 203 if (*last) { 204 sc->sc_flags |= G_ELI_FLAG_RW_DETACH; 205 sc->sc_geom->access = g_eli_access; 206 } else { 207 error = g_eli_destroy(sc, *force); 208 if (error != 0) { 209 gctl_error(req, 210 "Cannot destroy device %s (error=%d).", 211 sc->sc_name, error); 212 return; 213 } 214 } 215 } 216} 217 218static void 219g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) 220{ 221 struct g_eli_metadata md; 222 struct g_provider *pp; 223 const char *name; 224 intmax_t *keylen, *sectorsize; 225 u_char mkey[G_ELI_DATAIVKEYLEN]; 226 int *nargs, *detach; 227 228 g_topology_assert(); 229 bzero(&md, sizeof(md)); 230 231 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 232 if (nargs == NULL) { 233 gctl_error(req, "No '%s' argument.", "nargs"); 234 return; 235 } 236 if (*nargs != 1) { 237 gctl_error(req, "Invalid number of arguments."); 238 return; 239 } 240 241 detach = gctl_get_paraml(req, "detach", sizeof(*detach)); 242 if (detach == NULL) { 243 gctl_error(req, "No '%s' argument.", "detach"); 244 return; 245 } 246 247 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 248 md.md_version = G_ELI_VERSION; 249 md.md_flags |= G_ELI_FLAG_ONETIME; 250 if (*detach) 251 md.md_flags |= G_ELI_FLAG_WO_DETACH; 252 253 name = gctl_get_asciiparam(req, "algo"); 254 if (name == NULL) { 255 gctl_error(req, "No '%s' argument.", "algo"); 256 return; 257 } 258 md.md_algo = g_eli_str2algo(name); 259 if (md.md_algo < CRYPTO_ALGORITHM_MIN || 260 md.md_algo > CRYPTO_ALGORITHM_MAX) { 261 gctl_error(req, "Invalid '%s' argument.", "algo"); 262 return; 263 } 264 265 keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen)); 266 if (keylen == NULL) { 267 gctl_error(req, "No '%s' argument.", "keylen"); 268 return; 269 } 270 md.md_keylen = g_eli_keylen(md.md_algo, *keylen); 271 if (md.md_keylen == 0) { 272 gctl_error(req, "Invalid '%s' argument.", "keylen"); 273 return; 274 } 275 276 /* Not important here. */ 277 md.md_provsize = 0; 278 /* Not important here. */ 279 bzero(md.md_salt, sizeof(md.md_salt)); 280 281 md.md_keys = 0x01; 282 arc4rand(mkey, sizeof(mkey), 0); 283 284 /* Not important here. */ 285 bzero(md.md_hash, sizeof(md.md_hash)); 286 287 name = gctl_get_asciiparam(req, "arg0"); 288 if (name == NULL) { 289 gctl_error(req, "No 'arg%u' argument.", 0); 290 return; 291 } 292 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 293 name += strlen("/dev/"); 294 pp = g_provider_by_name(name); 295 if (pp == NULL) { 296 gctl_error(req, "Provider %s is invalid.", name); 297 return; 298 } 299 300 sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize)); 301 if (sectorsize == NULL) { 302 gctl_error(req, "No '%s' argument.", "sectorsize"); 303 return; 304 } 305 if (*sectorsize == 0) 306 md.md_sectorsize = pp->sectorsize; 307 else { 308 if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) { 309 gctl_error(req, "Invalid sector size."); 310 return; 311 } 312 md.md_sectorsize = *sectorsize; 313 } 314 315 g_eli_create(req, mp, pp, &md, mkey, -1); 316 bzero(mkey, sizeof(mkey)); 317 bzero(&md, sizeof(md)); 318} 319 320static void 321g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp) 322{ 323 struct g_eli_softc *sc; 324 struct g_eli_metadata md; 325 struct g_provider *pp; 326 struct g_consumer *cp; 327 const char *name; 328 u_char *key, *mkeydst, *sector; 329 intmax_t *valp; 330 int nkey; 331 int keysize, error; 332 333 g_topology_assert(); 334 335 name = gctl_get_asciiparam(req, "arg0"); 336 if (name == NULL) { 337 gctl_error(req, "No 'arg%u' argument.", 0); 338 return; 339 } 340 sc = g_eli_find_device(mp, name); 341 if (sc == NULL) { 342 gctl_error(req, "Provider %s is invalid.", name); 343 return; 344 } 345 cp = LIST_FIRST(&sc->sc_geom->consumer); 346 pp = cp->provider; 347 348 error = g_eli_read_metadata(mp, pp, &md); 349 if (error != 0) { 350 gctl_error(req, "Cannot read metadata from %s (error=%d).", 351 name, error); 352 return; 353 } 354 355 valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 356 if (valp == NULL) { 357 gctl_error(req, "No '%s' argument.", "keyno"); 358 return; 359 } 360 if (*valp != -1) 361 nkey = *valp; 362 else 363 nkey = sc->sc_nkey; 364 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 365 gctl_error(req, "Invalid '%s' argument.", "keyno"); 366 return; 367 } 368 369 key = gctl_get_param(req, "key", &keysize); 370 if (key == NULL || keysize != G_ELI_USERKEYLEN) { 371 bzero(&md, sizeof(md)); 372 gctl_error(req, "No '%s' argument.", "key"); 373 return; 374 } 375 376 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 377 md.md_keys |= (1 << nkey); 378 379 bcopy(sc->sc_ivkey, mkeydst, sizeof(sc->sc_ivkey)); 380 bcopy(sc->sc_datakey, mkeydst + sizeof(sc->sc_ivkey), 381 sizeof(sc->sc_datakey)); 382 383 /* Encrypt Master Key with the new key. */ 384 error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst); 385 bzero(key, sizeof(key)); 386 if (error != 0) { 387 bzero(&md, sizeof(md)); 388 gctl_error(req, "Cannot encrypt Master Key (error=%d).", error); 389 return; 390 } 391 392 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 393 /* Store metadata with fresh key. */ 394 eli_metadata_encode(&md, sector); 395 bzero(&md, sizeof(md)); 396 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 397 pp->sectorsize); 398 bzero(sector, sizeof(sector)); 399 free(sector, M_ELI); 400 if (error != 0) { 401 gctl_error(req, "Cannot store metadata on %s (error=%d).", 402 pp->name, error); 403 return; 404 } 405 G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name); 406} 407 408static void 409g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) 410{ 411 struct g_eli_softc *sc; 412 struct g_eli_metadata md; 413 struct g_provider *pp; 414 struct g_consumer *cp; 415 const char *name; 416 u_char *mkeydst, *sector; 417 intmax_t *valp; 418 size_t keysize; 419 int error, nkey, *all, *force; 420 u_int i; 421 422 g_topology_assert(); 423 424 nkey = 0; /* fixes causeless gcc warning */ 425 426 name = gctl_get_asciiparam(req, "arg0"); 427 if (name == NULL) { 428 gctl_error(req, "No 'arg%u' argument.", 0); 429 return; 430 } 431 sc = g_eli_find_device(mp, name); 432 if (sc == NULL) { 433 gctl_error(req, "Provider %s is invalid.", name); 434 return; 435 } 436 cp = LIST_FIRST(&sc->sc_geom->consumer); 437 pp = cp->provider; 438 439 error = g_eli_read_metadata(mp, pp, &md); 440 if (error != 0) { 441 gctl_error(req, "Cannot read metadata from %s (error=%d).", 442 name, error); 443 return; 444 } 445 446 all = gctl_get_paraml(req, "all", sizeof(*all)); 447 if (all == NULL) { 448 gctl_error(req, "No '%s' argument.", "all"); 449 return; 450 } 451 452 if (*all) { 453 mkeydst = md.md_mkeys; 454 keysize = sizeof(md.md_mkeys); 455 } else { 456 force = gctl_get_paraml(req, "force", sizeof(*force)); 457 if (force == NULL) { 458 gctl_error(req, "No '%s' argument.", "force"); 459 return; 460 } 461 462 valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 463 if (valp == NULL) { 464 gctl_error(req, "No '%s' argument.", "keyno"); 465 return; 466 } 467 if (*valp != -1) 468 nkey = *valp; 469 else 470 nkey = sc->sc_nkey; 471 if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) { 472 gctl_error(req, "Invalid '%s' argument.", "keyno"); 473 return; 474 } 475 if (!(md.md_keys & (1 << nkey)) && !*force) { 476 gctl_error(req, "Master Key %u is not set.", nkey); 477 return; 478 } 479 md.md_keys &= ~(1 << nkey); 480 if (md.md_keys == 0 && !*force) { 481 gctl_error(req, "This is the last Master Key. Use '-f' " 482 "flag if you really want to remove it."); 483 return; 484 } 485 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 486 keysize = G_ELI_MKEYLEN; 487 } 488 489 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO); 490 for (i = 0; i <= g_eli_overwrites; i++) { 491 if (i == g_eli_overwrites) 492 bzero(mkeydst, keysize); 493 else 494 arc4rand(mkeydst, keysize, 0); 495 /* Store metadata with destroyed key. */ 496 eli_metadata_encode(&md, sector); 497 error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 498 pp->sectorsize); 499 if (error != 0) { 500 G_ELI_DEBUG(0, "Cannot store metadata on %s " 501 "(error=%d).", pp->name, error); 502 } 503 } 504 bzero(&md, sizeof(md)); 505 bzero(sector, sizeof(sector)); 506 free(sector, M_ELI); 507 if (*all) 508 G_ELI_DEBUG(1, "All keys removed from %s.", pp->name); 509 else 510 G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name); 511} 512 513static int 514g_eli_kill_one(struct g_eli_softc *sc) 515{ 516 struct g_provider *pp; 517 struct g_consumer *cp; 518 u_char *sector; 519 int err, error = 0; 520 u_int i; 521 522 g_topology_assert(); 523 524 if (sc == NULL) 525 return (ENOENT); 526 527 pp = LIST_FIRST(&sc->sc_geom->provider); 528 g_error_provider(pp, ENXIO); 529 530 cp = LIST_FIRST(&sc->sc_geom->consumer); 531 pp = cp->provider; 532 533 sector = malloc(pp->sectorsize, M_ELI, M_WAITOK); 534 for (i = 0; i <= g_eli_overwrites; i++) { 535 if (i == g_eli_overwrites) 536 bzero(sector, pp->sectorsize); 537 else 538 arc4rand(sector, pp->sectorsize, 0); 539 err = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 540 pp->sectorsize); 541 if (err != 0) { 542 G_ELI_DEBUG(0, "Cannot erase metadata on %s " 543 "(error=%d).", pp->name, err); 544 if (error == 0) 545 error = err; 546 } 547 } 548 free(sector, M_ELI); 549 if (error == 0) 550 G_ELI_DEBUG(0, "%s has been killed.", pp->name); 551 g_eli_destroy(sc, 1); 552 return (error); 553} 554 555static void 556g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp) 557{ 558 int *all, *nargs; 559 int error; 560 561 g_topology_assert(); 562 563 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 564 if (nargs == NULL) { 565 gctl_error(req, "No '%s' argument.", "nargs"); 566 return; 567 } 568 all = gctl_get_paraml(req, "all", sizeof(*all)); 569 if (all == NULL) { 570 gctl_error(req, "No '%s' argument.", "all"); 571 return; 572 } 573 if (!*all && *nargs == 0) { 574 gctl_error(req, "Too few arguments."); 575 return; 576 } 577 578 if (*all) { 579 struct g_geom *gp, *gp2; 580 581 LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 582 error = g_eli_kill_one(gp->softc); 583 if (error != 0) 584 gctl_error(req, "Not fully done."); 585 } 586 } else { 587 struct g_eli_softc *sc; 588 const char *prov; 589 char param[16]; 590 int i; 591 592 for (i = 0; i < *nargs; i++) { 593 snprintf(param, sizeof(param), "arg%u", i); 594 prov = gctl_get_asciiparam(req, param); 595 596 sc = g_eli_find_device(mp, prov); 597 if (sc == NULL) { 598 G_ELI_DEBUG(1, "No such provider: %s.", prov); 599 continue; 600 } 601 error = g_eli_kill_one(sc); 602 if (error != 0) 603 gctl_error(req, "Not fully done."); 604 } 605 } 606} 607 608void 609g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb) 610{ 611 uint32_t *version; 612 613 g_topology_assert(); 614 615 version = gctl_get_paraml(req, "version", sizeof(*version)); 616 if (version == NULL) { 617 gctl_error(req, "No '%s' argument.", "version"); 618 return; 619 } 620 if (*version != G_ELI_VERSION) { 621 gctl_error(req, "Userland and kernel parts are out of sync."); 622 return; 623 } 624 625 if (strcmp(verb, "attach") == 0) 626 g_eli_ctl_attach(req, mp); 627 else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0) 628 g_eli_ctl_detach(req, mp); 629 else if (strcmp(verb, "onetime") == 0) 630 g_eli_ctl_onetime(req, mp); 631 else if (strcmp(verb, "setkey") == 0) 632 g_eli_ctl_setkey(req, mp); 633 else if (strcmp(verb, "delkey") == 0) 634 g_eli_ctl_delkey(req, mp); 635 else if (strcmp(verb, "kill") == 0) 636 g_eli_ctl_kill(req, mp); 637 else 638 gctl_error(req, "Unknown verb."); 639} 640