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