geom_eli.c revision 155183
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 155183 2006-02-01 15:01:55Z 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, boot; 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 boot = gctl_get_int(req, "boot"); 525 if (boot) { 526 int nonewpassphrase; 527 528 /* Part of key cannot be read on boot from a file. */ 529 str = gctl_get_ascii(req, "newkeyfile"); 530 if (str[0] != '\0') { 531 gctl_error(req, 532 "Options -b and -K are mutually exclusive."); 533 return; 534 } 535 /* Key has to be given as a passphrase on boot. */ 536 nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 537 if (nonewpassphrase) { 538 gctl_error(req, 539 "Options -b and -P are mutually exclusive."); 540 return; 541 } 542 md.md_flags |= G_ELI_FLAG_BOOT; 543 } 544 str = gctl_get_ascii(req, "algo"); 545 md.md_algo = g_eli_str2algo(str); 546 if (md.md_algo < CRYPTO_ALGORITHM_MIN || 547 md.md_algo > CRYPTO_ALGORITHM_MAX) { 548 gctl_error(req, "Invalid encryption algorithm."); 549 return; 550 } 551 val = gctl_get_intmax(req, "keylen"); 552 md.md_keylen = val; 553 md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen); 554 if (md.md_keylen == 0) { 555 gctl_error(req, "Invalid key length."); 556 return; 557 } 558 md.md_provsize = mediasize; 559 560 val = gctl_get_intmax(req, "iterations"); 561 md.md_iterations = val; 562 563 val = gctl_get_intmax(req, "sectorsize"); 564 if (val == 0) 565 md.md_sectorsize = secsize; 566 else { 567 if (val < 0 || (val % secsize) != 0) { 568 gctl_error(req, "Invalid sector size."); 569 return; 570 } 571 md.md_sectorsize = val; 572 } 573 574 md.md_keys = 0x01; 575 arc4rand(md.md_salt, sizeof(md.md_salt)); 576 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 577 578 /* Generate user key. */ 579 if (eli_genkey(req, &md, key, 1) == NULL) { 580 bzero(key, sizeof(key)); 581 bzero(&md, sizeof(md)); 582 return; 583 } 584 585 /* Encrypt the first and the only Master Key. */ 586 error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys); 587 bzero(key, sizeof(key)); 588 if (error != 0) { 589 bzero(&md, sizeof(md)); 590 gctl_error(req, "Cannot encrypt Master Key: %s.", 591 strerror(error)); 592 return; 593 } 594 595 eli_metadata_encode(&md, sector); 596 bzero(&md, sizeof(md)); 597 error = g_metadata_store(prov, sector, sizeof(sector)); 598 bzero(sector, sizeof(sector)); 599 if (error != 0) { 600 gctl_error(req, "Cannot store metadata on %s: %s.", prov, 601 strerror(error)); 602 return; 603 } 604 if (verbose) 605 printf("Metadata value stored on %s.\n", prov); 606} 607 608static void 609eli_attach(struct gctl_req *req) 610{ 611 struct g_eli_metadata md; 612 unsigned char key[G_ELI_USERKEYLEN]; 613 const char *prov; 614 int nargs; 615 616 nargs = gctl_get_int(req, "nargs"); 617 if (nargs != 1) { 618 gctl_error(req, "Too few arguments."); 619 return; 620 } 621 prov = gctl_get_ascii(req, "arg0"); 622 623 if (eli_metadata_read(req, prov, &md) == -1) 624 return; 625 626 if (eli_genkey(req, &md, key, 0) == NULL) { 627 bzero(key, sizeof(key)); 628 return; 629 } 630 631 gctl_ro_param(req, "key", sizeof(key), key); 632 if (gctl_issue(req) == NULL) { 633 if (verbose) 634 printf("Attched to %s.\n", prov); 635 } 636 bzero(key, sizeof(key)); 637} 638 639static void 640eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 641{ 642 unsigned char key[G_ELI_USERKEYLEN]; 643 intmax_t val; 644 645 val = gctl_get_intmax(req, "iterations"); 646 /* Check if iterations number should be changed. */ 647 if (val != -1) 648 md->md_iterations = val; 649 650 /* Generate key for Master Key encryption. */ 651 if (eli_genkey(req, md, key, 1) == NULL) { 652 bzero(key, sizeof(key)); 653 return; 654 } 655 656 gctl_ro_param(req, "key", sizeof(key), key); 657 gctl_issue(req); 658 bzero(key, sizeof(key)); 659} 660 661static void 662eli_setkey_detached(struct gctl_req *req, const char *prov, 663 struct g_eli_metadata *md) 664{ 665 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 666 unsigned char *mkeydst; 667 intmax_t val; 668 unsigned nkey; 669 int error; 670 671 if (md->md_keys == 0) { 672 gctl_error(req, "No valid keys on %s.", prov); 673 return; 674 } 675 676 /* Generate key for Master Key decryption. */ 677 if (eli_genkey(req, md, key, 0) == NULL) { 678 bzero(key, sizeof(key)); 679 return; 680 } 681 682 /* Decrypt Master Key. */ 683 error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 684 bzero(key, sizeof(key)); 685 if (error != 0) { 686 bzero(md, sizeof(*md)); 687 if (error == -1) 688 gctl_error(req, "Wrong key for %s.", prov); 689 else /* if (error > 0) */ { 690 gctl_error(req, "Cannot decrypt Master Key: %s.", 691 strerror(error)); 692 } 693 return; 694 } 695 if (verbose) 696 printf("Decrypted Master Key %u.\n", nkey); 697 698 val = gctl_get_intmax(req, "keyno"); 699 if (val != -1) 700 nkey = val; 701#if 0 702 else 703 ; /* Use the key number which was found during decryption. */ 704#endif 705 if (nkey >= G_ELI_MAXMKEYS) { 706 gctl_error(req, "Invalid '%s' argument.", "keyno"); 707 return; 708 } 709 710 val = gctl_get_intmax(req, "iterations"); 711 /* Check if iterations number should and can be changed. */ 712 if (val != -1) { 713 if (bitcount32(md->md_keys) != 1) { 714 gctl_error(req, "To be able to use '-i' option, only " 715 "one key can be defined."); 716 return; 717 } 718 if (md->md_keys != (1 << nkey)) { 719 gctl_error(req, "Only already defined key can be " 720 "changed when '-i' option is used."); 721 return; 722 } 723 md->md_iterations = val; 724 } 725 726 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 727 md->md_keys |= (1 << nkey); 728 729 bcopy(mkey, mkeydst, sizeof(mkey)); 730 bzero(mkey, sizeof(mkey)); 731 732 /* Generate key for Master Key encryption. */ 733 if (eli_genkey(req, md, key, 1) == NULL) { 734 bzero(key, sizeof(key)); 735 bzero(md, sizeof(*md)); 736 return; 737 } 738 739 /* Encrypt the Master-Key with the new key. */ 740 error = g_eli_mkey_encrypt(md->md_algo, key, md->md_keylen, mkeydst); 741 bzero(key, sizeof(key)); 742 if (error != 0) { 743 bzero(md, sizeof(*md)); 744 gctl_error(req, "Cannot encrypt Master Key: %s.", 745 strerror(error)); 746 return; 747 } 748 749 /* Store metadata with fresh key. */ 750 eli_metadata_store(req, prov, md); 751 bzero(md, sizeof(*md)); 752} 753 754static void 755eli_setkey(struct gctl_req *req) 756{ 757 struct g_eli_metadata md; 758 const char *prov; 759 int nargs; 760 761 nargs = gctl_get_int(req, "nargs"); 762 if (nargs != 1) { 763 gctl_error(req, "Too few arguments."); 764 return; 765 } 766 prov = gctl_get_ascii(req, "arg0"); 767 768 if (eli_metadata_read(req, prov, &md) == -1) 769 return; 770 771 if (eli_is_attached(prov)) 772 eli_setkey_attached(req, &md); 773 else 774 eli_setkey_detached(req, prov, &md); 775} 776 777static void 778eli_delkey_attached(struct gctl_req *req, const char *prov __unused) 779{ 780 781 gctl_issue(req); 782} 783 784static void 785eli_delkey_detached(struct gctl_req *req, const char *prov) 786{ 787 struct g_eli_metadata md; 788 unsigned char *mkeydst; 789 intmax_t val; 790 unsigned nkey; 791 int all, force; 792 793 if (eli_metadata_read(req, prov, &md) == -1) 794 return; 795 796 all = gctl_get_int(req, "all"); 797 if (all) 798 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 799 else { 800 force = gctl_get_int(req, "force"); 801 val = gctl_get_intmax(req, "keyno"); 802 if (val == -1) { 803 gctl_error(req, "Key number has to be specified."); 804 return; 805 } 806 nkey = val; 807 if (nkey >= G_ELI_MAXMKEYS) { 808 gctl_error(req, "Invalid '%s' argument.", "keyno"); 809 return; 810 } 811 if (!(md.md_keys & (1 << nkey)) && !force) { 812 gctl_error(req, "Master Key %u is not set.", nkey); 813 return; 814 } 815 md.md_keys &= ~(1 << nkey); 816 if (md.md_keys == 0 && !force) { 817 gctl_error(req, "This is the last Master Key. Use '-f' " 818 "option if you really want to remove it."); 819 return; 820 } 821 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 822 arc4rand(mkeydst, G_ELI_MKEYLEN); 823 } 824 825 eli_metadata_store(req, prov, &md); 826 bzero(&md, sizeof(md)); 827} 828 829static void 830eli_delkey(struct gctl_req *req) 831{ 832 const char *prov; 833 int nargs; 834 835 nargs = gctl_get_int(req, "nargs"); 836 if (nargs != 1) { 837 gctl_error(req, "Too few arguments."); 838 return; 839 } 840 prov = gctl_get_ascii(req, "arg0"); 841 842 if (eli_is_attached(prov)) 843 eli_delkey_attached(req, prov); 844 else 845 eli_delkey_detached(req, prov); 846} 847 848static void 849eli_kill_detached(struct gctl_req *req, const char *prov) 850{ 851 struct g_eli_metadata md; 852 int error; 853 854 /* 855 * NOTE: Maybe we should verify if this is geli provider first, 856 * but 'kill' command is quite critical so better don't waste 857 * the time. 858 */ 859#if 0 860 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 861 G_ELI_MAGIC); 862 if (error != 0) { 863 gctl_error(req, "Cannot read metadata from %s: %s.", prov, 864 strerror(error)); 865 return; 866 } 867#endif 868 869 arc4rand((unsigned char *)&md, sizeof(md)); 870 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 871 if (error != 0) { 872 gctl_error(req, "Cannot write metadata to %s: %s.", prov, 873 strerror(error)); 874 } 875} 876 877static void 878eli_kill(struct gctl_req *req) 879{ 880 const char *prov; 881 int i, nargs, all; 882 883 nargs = gctl_get_int(req, "nargs"); 884 all = gctl_get_int(req, "all"); 885 if (!all && nargs == 0) { 886 gctl_error(req, "Too few arguments."); 887 return; 888 } 889 /* 890 * How '-a' option combine with a list of providers: 891 * Delete Master Keys from all attached providers: 892 * geli kill -a 893 * Delete Master Keys from all attached provider and from 894 * detached da0 and da1: 895 * geli kill -a da0 da1 896 * Delete Master Keys from (attached or detached) da0 and da1: 897 * geli kill da0 da1 898 */ 899 900 /* 901 * First attached providers. 902 */ 903 gctl_issue(req); 904 /* 905 * Now the rest. 906 */ 907 for (i = 0; i < nargs; i++) { 908 prov = gctl_get_ascii(req, "arg%d", i); 909 if (!eli_is_attached(prov)) 910 eli_kill_detached(req, prov); 911 } 912} 913 914static void 915eli_backup(struct gctl_req *req) 916{ 917 struct g_eli_metadata md; 918 const char *file, *prov; 919 unsigned secsize; 920 unsigned char *sector; 921 off_t mediasize; 922 int nargs, filefd, provfd; 923 924 nargs = gctl_get_int(req, "nargs"); 925 if (nargs != 2) { 926 gctl_error(req, "Invalid number of arguments."); 927 return; 928 } 929 prov = gctl_get_ascii(req, "arg0"); 930 file = gctl_get_ascii(req, "arg1"); 931 932 provfd = filefd = -1; 933 sector = NULL; 934 secsize = 0; 935 936 provfd = open(prov, O_RDONLY); 937 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 938 char devprov[MAXPATHLEN]; 939 940 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 941 provfd = open(devprov, O_RDONLY); 942 } 943 if (provfd == -1) { 944 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 945 return; 946 } 947 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 948 if (filefd == -1) { 949 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 950 goto out; 951 } 952 953 mediasize = g_get_mediasize(prov); 954 secsize = g_get_sectorsize(prov); 955 if (mediasize == 0 || secsize == 0) { 956 gctl_error(req, "Cannot get informations about %s: %s.", prov, 957 strerror(errno)); 958 return; 959 } 960 961 sector = malloc(secsize); 962 if (sector == NULL) { 963 gctl_error(req, "Cannot allocate memory."); 964 return; 965 } 966 967 /* Read metadata from the provider. */ 968 if (pread(provfd, sector, secsize, mediasize - secsize) != 969 (ssize_t)secsize) { 970 gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 971 goto out; 972 } 973 /* Check if this is geli provider. */ 974 if (eli_metadata_decode(sector, &md) != 0) { 975 gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 976 goto out; 977 } 978 /* Write metadata to the destination file. */ 979 if (write(filefd, sector, secsize) != (ssize_t)secsize) { 980 gctl_error(req, "Cannot write to %s: %s.", file, 981 strerror(errno)); 982 goto out; 983 } 984out: 985 if (provfd > 0) 986 close(provfd); 987 if (filefd > 0) 988 close(filefd); 989 if (sector != NULL) { 990 bzero(sector, secsize); 991 free(sector); 992 } 993} 994 995static void 996eli_restore(struct gctl_req *req) 997{ 998 struct g_eli_metadata md; 999 const char *file, *prov; 1000 unsigned char *sector; 1001 unsigned secsize; 1002 off_t mediasize; 1003 int nargs, filefd, provfd; 1004 1005 nargs = gctl_get_int(req, "nargs"); 1006 if (nargs != 2) { 1007 gctl_error(req, "Invalid number of arguments."); 1008 return; 1009 } 1010 file = gctl_get_ascii(req, "arg0"); 1011 prov = gctl_get_ascii(req, "arg1"); 1012 1013 provfd = filefd = -1; 1014 sector = NULL; 1015 secsize = 0; 1016 1017 filefd = open(file, O_RDONLY); 1018 if (filefd == -1) { 1019 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1020 goto out; 1021 } 1022 provfd = open(prov, O_WRONLY); 1023 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1024 char devprov[MAXPATHLEN]; 1025 1026 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1027 provfd = open(devprov, O_WRONLY); 1028 } 1029 if (provfd == -1) { 1030 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1031 return; 1032 } 1033 1034 mediasize = g_get_mediasize(prov); 1035 secsize = g_get_sectorsize(prov); 1036 if (mediasize == 0 || secsize == 0) { 1037 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1038 strerror(errno)); 1039 return; 1040 } 1041 1042 sector = malloc(secsize); 1043 if (sector == NULL) { 1044 gctl_error(req, "Cannot allocate memory."); 1045 return; 1046 } 1047 1048 /* Read metadata from the backup file. */ 1049 if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1050 gctl_error(req, "Cannot read from %s: %s.", file, 1051 strerror(errno)); 1052 goto out; 1053 } 1054 /* Check if this file contains geli metadata. */ 1055 if (eli_metadata_decode(sector, &md) != 0) { 1056 gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1057 goto out; 1058 } 1059 /* Read metadata from the provider. */ 1060 if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1061 (ssize_t)secsize) { 1062 gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1063 goto out; 1064 } 1065out: 1066 if (provfd > 0) 1067 close(provfd); 1068 if (filefd > 0) 1069 close(filefd); 1070 if (sector != NULL) { 1071 bzero(sector, secsize); 1072 free(sector); 1073 } 1074} 1075 1076static void 1077eli_clear(struct gctl_req *req) 1078{ 1079 const char *name; 1080 int error, i, nargs; 1081 1082 nargs = gctl_get_int(req, "nargs"); 1083 if (nargs < 1) { 1084 gctl_error(req, "Too few arguments."); 1085 return; 1086 } 1087 1088 for (i = 0; i < nargs; i++) { 1089 name = gctl_get_ascii(req, "arg%d", i); 1090 error = g_metadata_clear(name, G_ELI_MAGIC); 1091 if (error != 0) { 1092 fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1093 name, strerror(error)); 1094 gctl_error(req, "Not fully done."); 1095 continue; 1096 } 1097 if (verbose) 1098 printf("Metadata cleared on %s.\n", name); 1099 } 1100} 1101 1102static void 1103eli_dump(struct gctl_req *req) 1104{ 1105 struct g_eli_metadata md, tmpmd; 1106 const char *name; 1107 int error, i, nargs; 1108 1109 nargs = gctl_get_int(req, "nargs"); 1110 if (nargs < 1) { 1111 gctl_error(req, "Too few arguments."); 1112 return; 1113 } 1114 1115 for (i = 0; i < nargs; i++) { 1116 name = gctl_get_ascii(req, "arg%d", i); 1117 error = g_metadata_read(name, (unsigned char *)&tmpmd, 1118 sizeof(tmpmd), G_ELI_MAGIC); 1119 if (error != 0) { 1120 fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1121 name, strerror(error)); 1122 gctl_error(req, "Not fully done."); 1123 continue; 1124 } 1125 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1126 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1127 name); 1128 gctl_error(req, "Not fully done."); 1129 continue; 1130 } 1131 printf("Metadata on %s:\n", name); 1132 eli_metadata_dump(&md); 1133 printf("\n"); 1134 } 1135} 1136