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