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