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