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