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