geom_eli.c revision 149047
1/*- 2 * Copyright (c) 2004 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/sbin/geom/class/eli/geom_eli.c 149047 2005-08-14 14:13:07Z pjd $"); 29 30#include <stdio.h> 31#include <stdint.h> 32#include <stdlib.h> 33#include <unistd.h> 34#include <fcntl.h> 35#include <readpassphrase.h> 36#include <string.h> 37#include <strings.h> 38#include <libgeom.h> 39#include <paths.h> 40#include <errno.h> 41#include <assert.h> 42 43#include <sys/param.h> 44#include <sys/mman.h> 45#include <sys/resource.h> 46#include <opencrypto/cryptodev.h> 47#include <geom/eli/g_eli.h> 48#include <geom/eli/pkcs5v2.h> 49 50#include "core/geom.h" 51#include "misc/subr.h" 52 53 54uint32_t lib_version = G_LIB_VERSION; 55uint32_t version = G_ELI_VERSION; 56 57static char algo[] = "aes"; 58static intmax_t keylen = 0; 59static intmax_t keyno = -1; 60static intmax_t iterations = -1; 61static intmax_t sectorsize = 0; 62static char keyfile[] = "", newkeyfile[] = ""; 63 64static void eli_main(struct gctl_req *req, unsigned flags); 65static void eli_init(struct gctl_req *req); 66static void eli_attach(struct gctl_req *req); 67static void eli_setkey(struct gctl_req *req); 68static void eli_delkey(struct gctl_req *req); 69static void eli_kill(struct gctl_req *req); 70static void eli_backup(struct gctl_req *req); 71static void eli_restore(struct gctl_req *req); 72static void eli_clear(struct gctl_req *req); 73static void eli_dump(struct gctl_req *req); 74 75/* 76 * Available commands: 77 * 78 * init [-bhPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] prov 79 * label - alias for 'init' 80 * attach [-dpv] [-k keyfile] prov 81 * detach [-fl] prov ... 82 * stop - alias for 'detach' 83 * onetime [-d] [-a algo] [-l keylen] prov ... 84 * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov 85 * delkey [-afv] [-n keyno] prov 86 * kill [-av] [prov ...] 87 * backup [-v] prov file 88 * restore [-v] file prov 89 * clear [-v] prov ... 90 * dump [-v] prov ... 91 */ 92struct g_command class_commands[] = { 93 { "init", G_FLAG_VERBOSE, eli_main, 94 { 95 { 'a', "algo", algo, G_TYPE_STRING }, 96 { 'b', "boot", NULL, G_TYPE_NONE }, 97 { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 98 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 99 { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 100 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 101 { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 102 G_OPT_SENTINEL 103 }, 104 "[-bPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" 105 }, 106 { "label", G_FLAG_VERBOSE, eli_main, 107 { 108 { 'a', "algo", algo, G_TYPE_STRING }, 109 { 'b', "boot", NULL, G_TYPE_NONE }, 110 { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 111 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 112 { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 113 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 114 { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 115 G_OPT_SENTINEL 116 }, 117 "- an alias for 'init'" 118 }, 119 { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 120 { 121 { 'd', "detach", NULL, G_TYPE_NONE }, 122 { 'k', "keyfile", keyfile, G_TYPE_STRING }, 123 { 'p', "nopassphrase", NULL, G_TYPE_NONE }, 124 G_OPT_SENTINEL 125 }, 126 "[-dpv] [-k keyfile] prov" 127 }, 128 { "detach", 0, NULL, 129 { 130 { 'f', "force", NULL, G_TYPE_NONE }, 131 { 'l', "last", NULL, G_TYPE_NONE }, 132 G_OPT_SENTINEL 133 }, 134 "[-fl] prov ..." 135 }, 136 { "stop", 0, NULL, 137 { 138 { 'f', "force", NULL, G_TYPE_NONE }, 139 { 'l', "last", NULL, G_TYPE_NONE }, 140 G_OPT_SENTINEL 141 }, 142 "- an alias for 'detach'" 143 }, 144 { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 145 { 146 { 'a', "algo", algo, G_TYPE_STRING }, 147 { 'd', "detach", NULL, G_TYPE_NONE }, 148 { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 149 { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 150 G_OPT_SENTINEL 151 }, 152 "[-d] [-a algo] [-l keylen] [-s sectorsize] prov ..." 153 }, 154 { "setkey", G_FLAG_VERBOSE, eli_main, 155 { 156 { 'k', "keyfile", keyfile, G_TYPE_STRING }, 157 { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 158 { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 159 { 'p', "nopassphrase", NULL, G_TYPE_NONE }, 160 { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 161 G_OPT_SENTINEL 162 }, 163 "[-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov" 164 }, 165 { "delkey", G_FLAG_VERBOSE, eli_main, 166 { 167 { 'a', "all", NULL, G_TYPE_NONE }, 168 { 'f', "force", NULL, G_TYPE_NONE }, 169 { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 170 G_OPT_SENTINEL 171 }, 172 "[-afv] [-n keyno] prov" 173 }, 174 { "kill", G_FLAG_VERBOSE, eli_main, 175 { 176 { 'a', "all", NULL, G_TYPE_NONE }, 177 G_OPT_SENTINEL 178 }, 179 "[-av] [prov ...]" 180 }, 181 { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 182 "[-v] prov file" 183 }, 184 { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 185 "[-v] file prov" 186 }, 187 { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 188 "[-v] prov ..." 189 }, 190 { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 191 "[-v] prov ..." 192 }, 193 G_CMD_SENTINEL 194}; 195 196static int verbose = 0; 197 198static int 199eli_protect(struct gctl_req *req) 200{ 201 struct rlimit rl; 202 203 /* Disable core dumps. */ 204 rl.rlim_cur = 0; 205 rl.rlim_max = 0; 206 if (setrlimit(RLIMIT_CORE, &rl) == -1) { 207 gctl_error(req, "Cannot disable core dumps: %s.", 208 strerror(errno)); 209 return (-1); 210 } 211 /* Disable swapping. */ 212 if (mlockall(MCL_FUTURE) == -1) { 213 gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 214 return (-1); 215 } 216 return (0); 217} 218 219static void 220eli_main(struct gctl_req *req, unsigned flags) 221{ 222 const char *name; 223 224 if (eli_protect(req) == -1) 225 return; 226 227 if ((flags & G_FLAG_VERBOSE) != 0) 228 verbose = 1; 229 230 name = gctl_get_asciiparam(req, "verb"); 231 if (name == NULL) { 232 gctl_error(req, "No '%s' argument.", "verb"); 233 return; 234 } 235 if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 236 eli_init(req); 237 else if (strcmp(name, "attach") == 0) 238 eli_attach(req); 239 else if (strcmp(name, "setkey") == 0) 240 eli_setkey(req); 241 else if (strcmp(name, "delkey") == 0) 242 eli_delkey(req); 243 else if (strcmp(name, "kill") == 0) 244 eli_kill(req); 245 else if (strcmp(name, "backup") == 0) 246 eli_backup(req); 247 else if (strcmp(name, "restore") == 0) 248 eli_restore(req); 249 else if (strcmp(name, "dump") == 0) 250 eli_dump(req); 251 else if (strcmp(name, "clear") == 0) 252 eli_clear(req); 253 else 254 gctl_error(req, "Unknown command: %s.", name); 255} 256 257static void 258arc4rand(unsigned char *buf, size_t size) 259{ 260 uint32_t *buf4; 261 size_t size4; 262 unsigned i; 263 264 buf4 = (uint32_t *)buf; 265 size4 = size / 4; 266 267 for (i = 0; i < size4; i++) 268 buf4[i] = arc4random(); 269 for (i *= 4; i < size; i++) 270 buf[i] = arc4random() % 0xff; 271} 272 273static int 274eli_is_attached(const char *prov) 275{ 276 char name[MAXPATHLEN]; 277 unsigned secsize; 278 279 /* 280 * Not the best way to do it, but the easiest. 281 * We try to open provider and check if it is a GEOM provider 282 * by asking about its sectorsize. 283 */ 284 snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 285 secsize = g_get_sectorsize(name); 286 if (secsize > 0) 287 return (1); 288 return (0); 289} 290 291static unsigned char * 292eli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 293 int new) 294{ 295 struct hmac_ctx ctx; 296 const char *str; 297 int *nopassphrase; 298 int error; 299 300 nopassphrase = gctl_get_paraml(req, 301 new ? "nonewpassphrase" : "nopassphrase", sizeof(*nopassphrase)); 302 if (nopassphrase == NULL) { 303 gctl_error(req, "No '%s' argument.", 304 new ? "nonewpassphrase" : "nopassphrase"); 305 return (NULL); 306 } 307 308 g_eli_crypto_hmac_init(&ctx, NULL, 0); 309 310 str = gctl_get_asciiparam(req, new ? "newkeyfile" : "keyfile"); 311 if (str == NULL) { 312 gctl_error(req, "No '%s' argument.", 313 new ? "newkeyfile" : "keyfile"); 314 return (NULL); 315 } 316 if (str[0] != '\0') { 317 char buf[MAXPHYS]; 318 ssize_t done; 319 int fd; 320 321 if (strcmp(str, "-") == 0) 322 fd = STDIN_FILENO; 323 else { 324 fd = open(str, O_RDONLY); 325 if (fd == -1) { 326 gctl_error(req, "Cannot open keyfile %s: %s.", 327 str, strerror(errno)); 328 return (NULL); 329 } 330 } 331 while ((done = read(fd, buf, sizeof(buf))) > 0) 332 g_eli_crypto_hmac_update(&ctx, buf, done); 333 error = errno; 334 if (strcmp(str, "-") != 0) 335 close(fd); 336 bzero(buf, sizeof(buf)); 337 if (done == -1) { 338 gctl_error(req, "Cannot read keyfile %s: %s.", str, 339 strerror(error)); 340 return (NULL); 341 } 342 } 343 344 if (!*nopassphrase) { 345 char buf1[BUFSIZ], buf2[BUFSIZ], *p; 346 347 if (!new && md->md_iterations == -1) { 348 gctl_error(req, "Missing -p flag."); 349 return (NULL); 350 } 351 for (;;) { 352 p = readpassphrase( 353 new ? "Enter new passphrase:" : "Enter passphrase:", 354 buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); 355 if (p == NULL) { 356 bzero(buf1, sizeof(buf1)); 357 gctl_error(req, "Cannot read passphrase: %s.", 358 strerror(errno)); 359 return (NULL); 360 } 361 362 if (new) { 363 p = readpassphrase("Reenter new passphrase: ", 364 buf2, sizeof(buf2), 365 RPP_ECHO_OFF | RPP_REQUIRE_TTY); 366 if (p == NULL) { 367 bzero(buf1, sizeof(buf1)); 368 gctl_error(req, 369 "Cannot read passphrase: %s.", 370 strerror(errno)); 371 return (NULL); 372 } 373 374 if (strcmp(buf1, buf2) != 0) { 375 bzero(buf2, sizeof(buf2)); 376 fprintf(stderr, "They didn't match.\n"); 377 continue; 378 } 379 bzero(buf2, sizeof(buf2)); 380 } 381 break; 382 } 383 /* 384 * Field md_iterations equal to -1 means "choose some sane 385 * value for me". 386 */ 387 if (md->md_iterations == -1) { 388 assert(new); 389 if (verbose) 390 printf("Calculating number of iterations...\n"); 391 md->md_iterations = pkcs5v2_calculate(2000000); 392 assert(md->md_iterations > 0); 393 if (verbose) { 394 printf("Done, using %d iterations.\n", 395 md->md_iterations); 396 } 397 } 398 /* 399 * If md_iterations is equal to 0, user don't want PKCS5v2. 400 */ 401 if (md->md_iterations == 0) { 402 g_eli_crypto_hmac_update(&ctx, md->md_salt, 403 sizeof(md->md_salt)); 404 g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1)); 405 } else /* if (md->md_iterations > 0) */ { 406 unsigned char dkey[G_ELI_USERKEYLEN]; 407 408 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 409 sizeof(md->md_salt), buf1, md->md_iterations); 410 g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 411 bzero(dkey, sizeof(dkey)); 412 } 413 bzero(buf1, sizeof(buf1)); 414 } 415 g_eli_crypto_hmac_final(&ctx, key, 0); 416 return (key); 417} 418 419static int 420eli_metadata_read(struct gctl_req *req, const char *prov, 421 struct g_eli_metadata *md) 422{ 423 unsigned char sector[sizeof(struct g_eli_metadata)]; 424 int error; 425 426 if (g_get_sectorsize(prov) == 0) { 427 int fd; 428 429 /* This is a file probably. */ 430 fd = open(prov, O_RDONLY); 431 if (fd == -1) { 432 gctl_error(req, "Cannot open %s: %s.", prov, 433 strerror(errno)); 434 return (-1); 435 } 436 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 437 gctl_error(req, "Cannot read metadata from %s: %s.", 438 prov, strerror(errno)); 439 close(fd); 440 return (-1); 441 } 442 close(fd); 443 } else { 444 /* This is a GEOM provider. */ 445 error = g_metadata_read(prov, sector, sizeof(sector), 446 G_ELI_MAGIC); 447 if (error != 0) { 448 gctl_error(req, "Cannot read metadata from %s: %s.", 449 prov, strerror(error)); 450 return (-1); 451 } 452 } 453 if (eli_metadata_decode(sector, md) != 0) { 454 gctl_error(req, "MD5 hash mismatch for %s.", prov); 455 return (-1); 456 } 457 return (0); 458} 459 460static int 461eli_metadata_store(struct gctl_req *req, const char *prov, 462 struct g_eli_metadata *md) 463{ 464 unsigned char sector[sizeof(struct g_eli_metadata)]; 465 int error; 466 467 eli_metadata_encode(md, sector); 468 if (g_get_sectorsize(prov) == 0) { 469 int fd; 470 471 /* This is a file probably. */ 472 fd = open(prov, O_WRONLY | O_TRUNC); 473 if (fd == -1) { 474 gctl_error(req, "Cannot open %s: %s.", prov, 475 strerror(errno)); 476 bzero(sector, sizeof(sector)); 477 return (-1); 478 } 479 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 480 gctl_error(req, "Cannot write metadata to %s: %s.", 481 prov, strerror(errno)); 482 bzero(sector, sizeof(sector)); 483 close(fd); 484 return (-1); 485 } 486 close(fd); 487 } else { 488 /* This is a GEOM provider. */ 489 error = g_metadata_store(prov, sector, sizeof(sector)); 490 if (error != 0) { 491 gctl_error(req, "Cannot write metadata to %s: %s.", 492 prov, strerror(errno)); 493 bzero(sector, sizeof(sector)); 494 return (-1); 495 } 496 } 497 bzero(sector, sizeof(sector)); 498 return (0); 499} 500 501static void 502eli_init(struct gctl_req *req) 503{ 504 struct g_eli_metadata md; 505 unsigned char sector[sizeof(struct g_eli_metadata)]; 506 unsigned char key[G_ELI_USERKEYLEN]; 507 const char *str, *prov; 508 int *nargs, *boot; 509 unsigned secsize; 510 off_t mediasize; 511 intmax_t *valp; 512 int error; 513 514 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 515 if (nargs == NULL) { 516 gctl_error(req, "No '%s' argument.", "nargs"); 517 return; 518 } 519 if (*nargs != 1) { 520 gctl_error(req, "Too few arguments."); 521 return; 522 } 523 prov = gctl_get_asciiparam(req, "arg0"); 524 if (prov == NULL) { 525 gctl_error(req, "No 'arg%u' argument.", 0); 526 return; 527 } 528 mediasize = g_get_mediasize(prov); 529 secsize = g_get_sectorsize(prov); 530 if (mediasize == 0 || secsize == 0) { 531 gctl_error(req, "Cannot get informations about %s: %s.", prov, 532 strerror(errno)); 533 return; 534 } 535 536 bzero(&md, sizeof(md)); 537 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 538 md.md_version = G_ELI_VERSION; 539 md.md_flags = 0; 540 boot = gctl_get_paraml(req, "boot", sizeof(*boot)); 541 if (boot == NULL) { 542 gctl_error(req, "No '%s' argument.", "boot"); 543 return; 544 } 545 if (*boot) { 546 int *nonewpassphrase; 547 548 /* Part of key cannot be read on boot from a file. */ 549 str = gctl_get_asciiparam(req, "newkeyfile"); 550 if (str == NULL) { 551 gctl_error(req, "No '%s' argument.", "newkeyfile"); 552 return; 553 } 554 if (str[0] != '\0') { 555 gctl_error(req, 556 "Options -b and -K are mutually exclusive."); 557 return; 558 } 559 /* Key has to be given as a passphrase on boot. */ 560 nonewpassphrase = gctl_get_paraml(req, "nonewpassphrase", 561 sizeof(*nonewpassphrase)); 562 if (nonewpassphrase == NULL) { 563 gctl_error(req, "No '%s' argument.", "nonewpassphrase"); 564 return; 565 } 566 if (*nonewpassphrase) { 567 gctl_error(req, 568 "Options -b and -P are mutually exclusive."); 569 return; 570 } 571 md.md_flags |= G_ELI_FLAG_BOOT; 572 } 573 str = gctl_get_asciiparam(req, "algo"); 574 if (str == NULL) { 575 gctl_error(req, "No '%s' argument.", "algo"); 576 return; 577 } 578 md.md_algo = g_eli_str2algo(str); 579 if (md.md_algo < CRYPTO_ALGORITHM_MIN || 580 md.md_algo > CRYPTO_ALGORITHM_MAX) { 581 gctl_error(req, "Invalid encryption algorithm."); 582 return; 583 } 584 valp = gctl_get_paraml(req, "keylen", sizeof(*valp)); 585 if (valp == NULL) { 586 gctl_error(req, "No '%s' argument.", "keylen"); 587 return; 588 } 589 md.md_keylen = *valp; 590 md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen); 591 if (md.md_keylen == 0) { 592 gctl_error(req, "Invalid key length."); 593 return; 594 } 595 md.md_provsize = mediasize; 596 597 valp = gctl_get_paraml(req, "iterations", sizeof(*valp)); 598 if (valp == NULL) { 599 gctl_error(req, "No '%s' argument.", "iterations"); 600 return; 601 } 602 md.md_iterations = *valp; 603 604 valp = gctl_get_paraml(req, "sectorsize", sizeof(*valp)); 605 if (valp == NULL) { 606 gctl_error(req, "No '%s' argument.", "sectorsize"); 607 return; 608 } 609 if (*valp == 0) 610 md.md_sectorsize = secsize; 611 else { 612 if (*valp < 0 || (*valp % secsize) != 0) { 613 gctl_error(req, "Invalid sector size."); 614 return; 615 } 616 md.md_sectorsize = *valp; 617 } 618 619 md.md_keys = 0x01; 620 arc4rand(md.md_salt, sizeof(md.md_salt)); 621 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 622 623 /* Generate user key. */ 624 if (eli_genkey(req, &md, key, 1) == NULL) { 625 bzero(key, sizeof(key)); 626 bzero(&md, sizeof(md)); 627 return; 628 } 629 630 /* Encrypt the first and the only Master Key. */ 631 error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys); 632 bzero(key, sizeof(key)); 633 if (error != 0) { 634 bzero(&md, sizeof(md)); 635 gctl_error(req, "Cannot encrypt Master Key: %s.", 636 strerror(error)); 637 return; 638 } 639 640 eli_metadata_encode(&md, sector); 641 bzero(&md, sizeof(md)); 642 error = g_metadata_store(prov, sector, sizeof(sector)); 643 bzero(sector, sizeof(sector)); 644 if (error != 0) { 645 gctl_error(req, "Cannot store metadata on %s: %s.", prov, 646 strerror(error)); 647 return; 648 } 649 if (verbose) 650 printf("Metadata value stored on %s.\n", prov); 651} 652 653static void 654eli_attach(struct gctl_req *req) 655{ 656 struct g_eli_metadata md; 657 unsigned char key[G_ELI_USERKEYLEN]; 658 const char *prov; 659 int *nargs; 660 661 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 662 if (nargs == NULL) { 663 gctl_error(req, "No '%s' argument.", "nargs"); 664 return; 665 } 666 if (*nargs != 1) { 667 gctl_error(req, "Too few arguments."); 668 return; 669 } 670 prov = gctl_get_asciiparam(req, "arg0"); 671 if (prov == NULL) { 672 gctl_error(req, "No 'arg%u' argument.", 0); 673 return; 674 } 675 676 if (eli_metadata_read(req, prov, &md) == -1) 677 return; 678 679 if (eli_genkey(req, &md, key, 0) == NULL) { 680 bzero(key, sizeof(key)); 681 return; 682 } 683 684 gctl_ro_param(req, "key", sizeof(key), key); 685 if (gctl_issue(req) == NULL) { 686 if (verbose) 687 printf("Attched to %s.\n", prov); 688 } 689 bzero(key, sizeof(key)); 690} 691 692static void 693eli_setkey_attached(struct gctl_req *req, const char *prov) 694{ 695 struct g_eli_metadata md; 696 unsigned char key[G_ELI_USERKEYLEN]; 697 698 if (eli_metadata_read(req, prov, &md) == -1) 699 return; 700 701 /* Generate key for Master Key encryption. */ 702 if (eli_genkey(req, &md, key, 1) == NULL) { 703 bzero(key, sizeof(key)); 704 return; 705 } 706 707 gctl_ro_param(req, "key", sizeof(key), key); 708 gctl_issue(req); 709 bzero(key, sizeof(key)); 710} 711 712static void 713eli_setkey_detached(struct gctl_req *req, const char *prov) 714{ 715 struct g_eli_metadata md; 716 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 717 unsigned char *mkeydst; 718 intmax_t *valp; 719 unsigned nkey; 720 int error; 721 722 if (eli_metadata_read(req, prov, &md) == -1) 723 return; 724 725 /* Generate key for Master Key decryption. */ 726 if (eli_genkey(req, &md, key, 0) == NULL) { 727 bzero(key, sizeof(key)); 728 return; 729 } 730 731 /* Decrypt Master Key. */ 732 error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); 733 bzero(key, sizeof(key)); 734 if (error != 0) { 735 bzero(&md, sizeof(md)); 736 if (error == -1) 737 gctl_error(req, "Wrong key for %s.", prov); 738 else /* if (error > 0) */ { 739 gctl_error(req, "Cannot decrypt Master Key: %s.", 740 strerror(error)); 741 } 742 return; 743 } 744 if (verbose) 745 printf("Decrypted Master Key %u.\n", nkey); 746 747 valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 748 if (valp == NULL) { 749 gctl_error(req, "No '%s' argument.", "keyno"); 750 return; 751 } 752 if (*valp != -1) 753 nkey = *valp; 754#if 0 755 else 756 ; /* Use the key number which was found during decryption. */ 757#endif 758 if (nkey >= G_ELI_MAXMKEYS) { 759 gctl_error(req, "Invalid '%s' argument.", "keyno"); 760 return; 761 } 762 763 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 764 md.md_keys |= (1 << nkey); 765 766 bcopy(mkey, mkeydst, sizeof(mkey)); 767 bzero(mkey, sizeof(mkey)); 768 769 /* Generate key for Master Key encryption. */ 770 if (eli_genkey(req, &md, key, 1) == NULL) { 771 bzero(key, sizeof(key)); 772 bzero(&md, sizeof(md)); 773 return; 774 } 775 776 /* Encrypt the Master-Key with the new key. */ 777 error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, mkeydst); 778 bzero(key, sizeof(key)); 779 if (error != 0) { 780 bzero(&md, sizeof(md)); 781 gctl_error(req, "Cannot encrypt Master Key: %s.", 782 strerror(error)); 783 return; 784 } 785 786 /* Store metadata with fresh key. */ 787 eli_metadata_store(req, prov, &md); 788 bzero(&md, sizeof(md)); 789} 790 791static void 792eli_setkey(struct gctl_req *req) 793{ 794 const char *prov; 795 int *nargs; 796 797 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 798 if (nargs == NULL) { 799 gctl_error(req, "No '%s' argument.", "nargs"); 800 return; 801 } 802 if (*nargs != 1) { 803 gctl_error(req, "Too few arguments."); 804 return; 805 } 806 prov = gctl_get_asciiparam(req, "arg0"); 807 if (prov == NULL) { 808 gctl_error(req, "No 'arg%u' argument.", 0); 809 return; 810 } 811 812 if (eli_is_attached(prov)) 813 eli_setkey_attached(req, prov); 814 else 815 eli_setkey_detached(req, prov); 816} 817 818static void 819eli_delkey_attached(struct gctl_req *req, const char *prov __unused) 820{ 821 822 gctl_issue(req); 823} 824 825static void 826eli_delkey_detached(struct gctl_req *req, const char *prov) 827{ 828 struct g_eli_metadata md; 829 unsigned char *mkeydst; 830 intmax_t *valp; 831 unsigned nkey; 832 int *all, *force; 833 834 if (eli_metadata_read(req, prov, &md) == -1) 835 return; 836 837 all = gctl_get_paraml(req, "all", sizeof(*all)); 838 if (all == NULL) { 839 gctl_error(req, "No '%s' argument.", "all"); 840 return; 841 } 842 843 if (*all) 844 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 845 else { 846 force = gctl_get_paraml(req, "force", sizeof(*force)); 847 if (force == NULL) { 848 gctl_error(req, "No '%s' argument.", "force"); 849 return; 850 } 851 852 valp = gctl_get_paraml(req, "keyno", sizeof(*valp)); 853 if (valp == NULL) { 854 gctl_error(req, "No '%s' argument.", "keyno"); 855 return; 856 } 857 if (*valp == -1) { 858 gctl_error(req, "Key number has to be specified."); 859 return; 860 } 861 nkey = *valp; 862 if (nkey >= G_ELI_MAXMKEYS) { 863 gctl_error(req, "Invalid '%s' argument.", "keyno"); 864 return; 865 } 866 if (!(md.md_keys & (1 << nkey)) && !*force) { 867 gctl_error(req, "Master Key %u is not set.", nkey); 868 return; 869 } 870 md.md_keys &= ~(1 << nkey); 871 if (md.md_keys == 0 && !*force) { 872 gctl_error(req, "This is the last Master Key. Use '-f' " 873 "option if you really want to remove it."); 874 return; 875 } 876 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 877 arc4rand(mkeydst, G_ELI_MKEYLEN); 878 } 879 880 eli_metadata_store(req, prov, &md); 881 bzero(&md, sizeof(md)); 882} 883 884static void 885eli_delkey(struct gctl_req *req) 886{ 887 const char *prov; 888 int *nargs; 889 890 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 891 if (nargs == NULL) { 892 gctl_error(req, "No '%s' argument.", "nargs"); 893 return; 894 } 895 if (*nargs != 1) { 896 gctl_error(req, "Too few arguments."); 897 return; 898 } 899 prov = gctl_get_asciiparam(req, "arg0"); 900 if (prov == NULL) { 901 gctl_error(req, "No 'arg%u' argument.", 0); 902 return; 903 } 904 905 if (eli_is_attached(prov)) 906 eli_delkey_attached(req, prov); 907 else 908 eli_delkey_detached(req, prov); 909} 910 911static void 912eli_kill_detached(struct gctl_req *req, const char *prov) 913{ 914 struct g_eli_metadata md; 915 int error; 916 917 /* 918 * NOTE: Maybe we should verify if this is geli provider first, 919 * but 'kill' command is quite critical so better don't waste 920 * the time. 921 */ 922#if 0 923 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 924 G_ELI_MAGIC); 925 if (error != 0) { 926 gctl_error(req, "Cannot read metadata from %s: %s.", prov, 927 strerror(error)); 928 return; 929 } 930#endif 931 932 arc4rand((unsigned char *)&md, sizeof(md)); 933 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 934 if (error != 0) { 935 gctl_error(req, "Cannot write metadata to %s: %s.", prov, 936 strerror(error)); 937 } 938} 939 940static void 941eli_kill(struct gctl_req *req) 942{ 943 const char *prov; 944 char param[16]; 945 unsigned i; 946 int *nargs, *all; 947 948 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 949 if (nargs == NULL) { 950 gctl_error(req, "No '%s' argument.", "nargs"); 951 return; 952 } 953 all = gctl_get_paraml(req, "all", sizeof(*all)); 954 if (all == NULL) { 955 gctl_error(req, "No '%s' argument.", "all"); 956 return; 957 } 958 if (!*all && *nargs == 0) { 959 gctl_error(req, "Too few arguments."); 960 return; 961 } 962 /* 963 * How '-a' option combine with a list of providers: 964 * Delete Master Keys from all attached providers: 965 * geli kill -a 966 * Delete Master Keys from all attached provider and from 967 * detached da0 and da1: 968 * geli kill -a da0 da1 969 * Delete Master Keys from (attached or detached) da0 and da1: 970 * geli kill da0 da1 971 */ 972 973 /* 974 * First attached providers. 975 */ 976 gctl_issue(req); 977 /* 978 * Now the rest. 979 */ 980 for (i = 0; i < (unsigned)*nargs; i++) { 981 snprintf(param, sizeof(param), "arg%u", i); 982 prov = gctl_get_asciiparam(req, param); 983 984 if (!eli_is_attached(prov)) 985 eli_kill_detached(req, prov); 986 } 987} 988 989static void 990eli_backup(struct gctl_req *req) 991{ 992 struct g_eli_metadata md; 993 const char *file, *prov; 994 unsigned secsize; 995 unsigned char *sector; 996 off_t mediasize; 997 int *nargs, filefd, provfd; 998 999 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1000 if (nargs == NULL) { 1001 gctl_error(req, "No '%s' argument.", "nargs"); 1002 return; 1003 } 1004 if (*nargs != 2) { 1005 gctl_error(req, "Invalid number of arguments."); 1006 return; 1007 } 1008 1009 prov = gctl_get_asciiparam(req, "arg0"); 1010 if (prov == NULL) { 1011 gctl_error(req, "No 'arg%u' argument.", 0); 1012 return; 1013 } 1014 file = gctl_get_asciiparam(req, "arg1"); 1015 if (file == NULL) { 1016 gctl_error(req, "No 'arg%u' argument.", 1); 1017 return; 1018 } 1019 1020 provfd = filefd = -1; 1021 sector = NULL; 1022 secsize = 0; 1023 1024 provfd = open(prov, O_RDONLY); 1025 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1026 char devprov[MAXPATHLEN]; 1027 1028 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1029 provfd = open(devprov, O_RDONLY); 1030 } 1031 if (provfd == -1) { 1032 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1033 return; 1034 } 1035 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1036 if (filefd == -1) { 1037 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1038 goto out; 1039 } 1040 1041 mediasize = g_get_mediasize(prov); 1042 secsize = g_get_sectorsize(prov); 1043 if (mediasize == 0 || secsize == 0) { 1044 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1045 strerror(errno)); 1046 return; 1047 } 1048 1049 sector = malloc(secsize); 1050 if (sector == NULL) { 1051 gctl_error(req, "Cannot allocate memory."); 1052 return; 1053 } 1054 1055 /* Read metadata from the provider. */ 1056 if (pread(provfd, sector, secsize, mediasize - secsize) != 1057 (ssize_t)secsize) { 1058 gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 1059 goto out; 1060 } 1061 /* Check if this is geli provider. */ 1062 if (eli_metadata_decode(sector, &md) != 0) { 1063 gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 1064 goto out; 1065 } 1066 /* Write metadata to the destination file. */ 1067 if (write(filefd, sector, secsize) != (ssize_t)secsize) { 1068 gctl_error(req, "Cannot write to %s: %s.", file, 1069 strerror(errno)); 1070 goto out; 1071 } 1072out: 1073 if (provfd > 0) 1074 close(provfd); 1075 if (filefd > 0) 1076 close(filefd); 1077 if (sector != NULL) { 1078 bzero(sector, secsize); 1079 free(sector); 1080 } 1081} 1082 1083static void 1084eli_restore(struct gctl_req *req) 1085{ 1086 struct g_eli_metadata md; 1087 const char *file, *prov; 1088 unsigned char *sector; 1089 unsigned secsize; 1090 off_t mediasize; 1091 int *nargs, filefd, provfd; 1092 1093 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1094 if (nargs == NULL) { 1095 gctl_error(req, "No '%s' argument.", "nargs"); 1096 return; 1097 } 1098 if (*nargs != 2) { 1099 gctl_error(req, "Invalid number of arguments."); 1100 return; 1101 } 1102 1103 file = gctl_get_asciiparam(req, "arg0"); 1104 if (file == NULL) { 1105 gctl_error(req, "No 'arg%u' argument.", 1); 1106 return; 1107 } 1108 prov = gctl_get_asciiparam(req, "arg1"); 1109 if (prov == NULL) { 1110 gctl_error(req, "No 'arg%u' argument.", 0); 1111 return; 1112 } 1113 1114 provfd = filefd = -1; 1115 sector = NULL; 1116 secsize = 0; 1117 1118 filefd = open(file, O_RDONLY); 1119 if (filefd == -1) { 1120 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1121 goto out; 1122 } 1123 provfd = open(prov, O_WRONLY); 1124 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1125 char devprov[MAXPATHLEN]; 1126 1127 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1128 provfd = open(devprov, O_WRONLY); 1129 } 1130 if (provfd == -1) { 1131 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1132 return; 1133 } 1134 1135 mediasize = g_get_mediasize(prov); 1136 secsize = g_get_sectorsize(prov); 1137 if (mediasize == 0 || secsize == 0) { 1138 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1139 strerror(errno)); 1140 return; 1141 } 1142 1143 sector = malloc(secsize); 1144 if (sector == NULL) { 1145 gctl_error(req, "Cannot allocate memory."); 1146 return; 1147 } 1148 1149 /* Read metadata from the backup file. */ 1150 if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1151 gctl_error(req, "Cannot read from %s: %s.", file, 1152 strerror(errno)); 1153 goto out; 1154 } 1155 /* Check if this file contains geli metadata. */ 1156 if (eli_metadata_decode(sector, &md) != 0) { 1157 gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1158 goto out; 1159 } 1160 /* Read metadata from the provider. */ 1161 if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1162 (ssize_t)secsize) { 1163 gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1164 goto out; 1165 } 1166out: 1167 if (provfd > 0) 1168 close(provfd); 1169 if (filefd > 0) 1170 close(filefd); 1171 if (sector != NULL) { 1172 bzero(sector, secsize); 1173 free(sector); 1174 } 1175} 1176 1177static void 1178eli_clear(struct gctl_req *req) 1179{ 1180 const char *name; 1181 char param[16]; 1182 int *nargs, error, i; 1183 1184 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1185 if (nargs == NULL) { 1186 gctl_error(req, "No '%s' argument.", "nargs"); 1187 return; 1188 } 1189 if (*nargs < 1) { 1190 gctl_error(req, "Too few arguments."); 1191 return; 1192 } 1193 1194 for (i = 0; i < *nargs; i++) { 1195 snprintf(param, sizeof(param), "arg%u", i); 1196 name = gctl_get_asciiparam(req, param); 1197 1198 error = g_metadata_clear(name, G_ELI_MAGIC); 1199 if (error != 0) { 1200 fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1201 name, strerror(error)); 1202 gctl_error(req, "Not fully done."); 1203 continue; 1204 } 1205 if (verbose) 1206 printf("Metadata cleared on %s.\n", name); 1207 } 1208} 1209 1210static void 1211eli_dump(struct gctl_req *req) 1212{ 1213 struct g_eli_metadata md, tmpmd; 1214 const char *name; 1215 char param[16]; 1216 int *nargs, error, i; 1217 1218 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1219 if (nargs == NULL) { 1220 gctl_error(req, "No '%s' argument.", "nargs"); 1221 return; 1222 } 1223 if (*nargs < 1) { 1224 gctl_error(req, "Too few arguments."); 1225 return; 1226 } 1227 1228 for (i = 0; i < *nargs; i++) { 1229 snprintf(param, sizeof(param), "arg%u", i); 1230 name = gctl_get_asciiparam(req, param); 1231 1232 error = g_metadata_read(name, (unsigned char *)&tmpmd, 1233 sizeof(tmpmd), G_ELI_MAGIC); 1234 if (error != 0) { 1235 fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1236 name, strerror(error)); 1237 gctl_error(req, "Not fully done."); 1238 continue; 1239 } 1240 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1241 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1242 name); 1243 gctl_error(req, "Not fully done."); 1244 continue; 1245 } 1246 printf("Metadata on %s:\n", name); 1247 eli_metadata_dump(&md); 1248 printf("\n"); 1249 } 1250} 1251