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