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