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