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