geom_eli.c revision 226722
1289715Sglebius/*- 2289715Sglebius * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3289715Sglebius * All rights reserved. 4289715Sglebius * 5289715Sglebius * Redistribution and use in source and binary forms, with or without 6289715Sglebius * modification, are permitted provided that the following conditions 7289715Sglebius * are met: 8289715Sglebius * 1. Redistributions of source code must retain the above copyright 9293894Sglebius * notice, this list of conditions and the following disclaimer. 10289715Sglebius * 2. Redistributions in binary form must reproduce the above copyright 11289715Sglebius * notice, this list of conditions and the following disclaimer in the 12293894Sglebius * documentation and/or other materials provided with the distribution. 13289715Sglebius * 14289715Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15293894Sglebius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16293894Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17293894Sglebius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18293894Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19293894Sglebius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20293894Sglebius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21289715Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22289715Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23293894Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24293894Sglebius * SUCH DAMAGE. 25293894Sglebius */ 26289715Sglebius 27293894Sglebius#include <sys/cdefs.h> 28293894Sglebius__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 226722 2011-10-25 07:56:27Z pjd $"); 29293894Sglebius 30289715Sglebius#include <sys/param.h> 31289715Sglebius#include <sys/mman.h> 32289715Sglebius#include <sys/sysctl.h> 33289715Sglebius#include <sys/resource.h> 34293894Sglebius#include <opencrypto/cryptodev.h> 35293894Sglebius 36293894Sglebius#include <assert.h> 37289715Sglebius#include <err.h> 38293894Sglebius#include <errno.h> 39289715Sglebius#include <fcntl.h> 40293894Sglebius#include <libgeom.h> 41289715Sglebius#include <paths.h> 42289715Sglebius#include <readpassphrase.h> 43293894Sglebius#include <stdbool.h> 44293894Sglebius#include <stdint.h> 45289715Sglebius#include <stdio.h> 46289715Sglebius#include <stdlib.h> 47289715Sglebius#include <string.h> 48289715Sglebius#include <strings.h> 49289715Sglebius#include <unistd.h> 50293894Sglebius 51293894Sglebius#include <geom/eli/g_eli.h> 52293894Sglebius#include <geom/eli/pkcs5v2.h> 53289715Sglebius 54289715Sglebius#include "core/geom.h" 55289715Sglebius#include "misc/subr.h" 56293894Sglebius 57289715Sglebius 58289715Sglebiusuint32_t lib_version = G_LIB_VERSION; 59289715Sglebiusuint32_t version = G_ELI_VERSION; 60289715Sglebius 61289715Sglebius#define GELI_BACKUP_DIR "/var/backups/" 62293894Sglebius#define GELI_ENC_ALGO "aes" 63293894Sglebius 64289715Sglebiusstatic void eli_main(struct gctl_req *req, unsigned flags); 65289715Sglebiusstatic void eli_init(struct gctl_req *req); 66289715Sglebiusstatic void eli_attach(struct gctl_req *req); 67293894Sglebiusstatic void eli_configure(struct gctl_req *req); 68293894Sglebiusstatic void eli_setkey(struct gctl_req *req); 69289715Sglebiusstatic void eli_delkey(struct gctl_req *req); 70293894Sglebiusstatic void eli_resume(struct gctl_req *req); 71293894Sglebiusstatic void eli_kill(struct gctl_req *req); 72293894Sglebiusstatic void eli_backup(struct gctl_req *req); 73289715Sglebiusstatic void eli_restore(struct gctl_req *req); 74293894Sglebiusstatic void eli_resize(struct gctl_req *req); 75289715Sglebiusstatic void eli_clear(struct gctl_req *req); 76293894Sglebiusstatic void eli_dump(struct gctl_req *req); 77289715Sglebius 78289715Sglebiusstatic int eli_backup_create(struct gctl_req *req, const char *prov, 79289715Sglebius const char *file); 80289715Sglebius 81289715Sglebius/* 82293894Sglebius * Available commands: 83289715Sglebius * 84289715Sglebius * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov 85293894Sglebius * label - alias for 'init' 86293894Sglebius * attach [-dprv] [-j passfile] [-k keyfile] prov 87289715Sglebius * 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 error = eli_metadata_decode(sector, md); 598 switch (error) { 599 case 0: 600 break; 601 case EOPNOTSUPP: 602 gctl_error(req, 603 "Provider's %s metadata version %u is too new.\n" 604 "geli: The highest supported version is %u.", 605 prov, (unsigned int)md->md_version, G_ELI_VERSION); 606 return (-1); 607 case EINVAL: 608 gctl_error(req, "Inconsistent provider's %s metadata.", prov); 609 return (-1); 610 default: 611 gctl_error(req, 612 "Unexpected error while decoding provider's %s metadata: %s.", 613 prov, strerror(error)); 614 return (-1); 615 } 616 return (0); 617} 618 619static int 620eli_metadata_store(struct gctl_req *req, const char *prov, 621 struct g_eli_metadata *md) 622{ 623 unsigned char sector[sizeof(struct g_eli_metadata)]; 624 int error; 625 626 eli_metadata_encode(md, sector); 627 if (g_get_sectorsize(prov) == 0) { 628 int fd; 629 630 /* This is a file probably. */ 631 fd = open(prov, O_WRONLY | O_TRUNC); 632 if (fd == -1) { 633 gctl_error(req, "Cannot open %s: %s.", prov, 634 strerror(errno)); 635 bzero(sector, sizeof(sector)); 636 return (-1); 637 } 638 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 639 gctl_error(req, "Cannot write metadata to %s: %s.", 640 prov, strerror(errno)); 641 bzero(sector, sizeof(sector)); 642 close(fd); 643 return (-1); 644 } 645 close(fd); 646 } else { 647 /* This is a GEOM provider. */ 648 error = g_metadata_store(prov, sector, sizeof(sector)); 649 if (error != 0) { 650 gctl_error(req, "Cannot write metadata to %s: %s.", 651 prov, strerror(errno)); 652 bzero(sector, sizeof(sector)); 653 return (-1); 654 } 655 } 656 bzero(sector, sizeof(sector)); 657 return (0); 658} 659 660static void 661eli_init(struct gctl_req *req) 662{ 663 struct g_eli_metadata md; 664 unsigned char sector[sizeof(struct g_eli_metadata)]; 665 unsigned char key[G_ELI_USERKEYLEN]; 666 char backfile[MAXPATHLEN]; 667 const char *str, *prov; 668 unsigned secsize; 669 off_t mediasize; 670 intmax_t val; 671 int error, nargs; 672 673 nargs = gctl_get_int(req, "nargs"); 674 if (nargs != 1) { 675 gctl_error(req, "Invalid number of arguments."); 676 return; 677 } 678 prov = gctl_get_ascii(req, "arg0"); 679 mediasize = g_get_mediasize(prov); 680 secsize = g_get_sectorsize(prov); 681 if (mediasize == 0 || secsize == 0) { 682 gctl_error(req, "Cannot get informations about %s: %s.", prov, 683 strerror(errno)); 684 return; 685 } 686 687 bzero(&md, sizeof(md)); 688 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 689 md.md_version = G_ELI_VERSION; 690 md.md_flags = 0; 691 if (gctl_get_int(req, "boot")) 692 md.md_flags |= G_ELI_FLAG_BOOT; 693 md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 694 str = gctl_get_ascii(req, "aalgo"); 695 if (*str != '\0') { 696 md.md_aalgo = g_eli_str2aalgo(str); 697 if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 698 md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 699 md.md_flags |= G_ELI_FLAG_AUTH; 700 } else { 701 /* 702 * For backward compatibility, check if the -a option 703 * was used to provide encryption algorithm. 704 */ 705 md.md_ealgo = g_eli_str2ealgo(str); 706 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 707 md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 708 gctl_error(req, 709 "Invalid authentication algorithm."); 710 return; 711 } else { 712 fprintf(stderr, "warning: The -e option, not " 713 "the -a option is now used to specify " 714 "encryption algorithm to use.\n"); 715 } 716 } 717 } 718 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 719 md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 720 str = gctl_get_ascii(req, "ealgo"); 721 md.md_ealgo = g_eli_str2ealgo(str); 722 if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 723 md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 724 gctl_error(req, "Invalid encryption algorithm."); 725 return; 726 } 727 } 728 val = gctl_get_intmax(req, "keylen"); 729 md.md_keylen = val; 730 md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 731 if (md.md_keylen == 0) { 732 gctl_error(req, "Invalid key length."); 733 return; 734 } 735 md.md_provsize = mediasize; 736 737 val = gctl_get_intmax(req, "iterations"); 738 if (val != -1) { 739 int nonewpassphrase; 740 741 /* 742 * Don't allow to set iterations when there will be no 743 * passphrase. 744 */ 745 nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 746 if (nonewpassphrase) { 747 gctl_error(req, 748 "Options -i and -P are mutually exclusive."); 749 return; 750 } 751 } 752 md.md_iterations = val; 753 754 val = gctl_get_intmax(req, "sectorsize"); 755 if (val == 0) 756 md.md_sectorsize = secsize; 757 else { 758 if (val < 0 || (val % secsize) != 0) { 759 gctl_error(req, "Invalid sector size."); 760 return; 761 } 762 if (val > sysconf(_SC_PAGE_SIZE)) { 763 fprintf(stderr, 764 "warning: Using sectorsize bigger than the page size!\n"); 765 } 766 md.md_sectorsize = val; 767 } 768 769 md.md_keys = 0x01; 770 arc4rand(md.md_salt, sizeof(md.md_salt)); 771 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 772 773 /* Generate user key. */ 774 if (eli_genkey(req, &md, key, true) == NULL) { 775 bzero(key, sizeof(key)); 776 bzero(&md, sizeof(md)); 777 return; 778 } 779 780 /* Encrypt the first and the only Master Key. */ 781 error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 782 bzero(key, sizeof(key)); 783 if (error != 0) { 784 bzero(&md, sizeof(md)); 785 gctl_error(req, "Cannot encrypt Master Key: %s.", 786 strerror(error)); 787 return; 788 } 789 790 eli_metadata_encode(&md, sector); 791 bzero(&md, sizeof(md)); 792 error = g_metadata_store(prov, sector, sizeof(sector)); 793 bzero(sector, sizeof(sector)); 794 if (error != 0) { 795 gctl_error(req, "Cannot store metadata on %s: %s.", prov, 796 strerror(error)); 797 return; 798 } 799 if (verbose) 800 printf("Metadata value stored on %s.\n", prov); 801 /* Backup metadata to a file. */ 802 str = gctl_get_ascii(req, "backupfile"); 803 if (str[0] != '\0') { 804 /* Backupfile given be the user, just copy it. */ 805 strlcpy(backfile, str, sizeof(backfile)); 806 } else { 807 /* Generate file name automatically. */ 808 const char *p = prov; 809 unsigned int i; 810 811 if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 812 p += sizeof(_PATH_DEV) - 1; 813 snprintf(backfile, sizeof(backfile), "%s%s.eli", 814 GELI_BACKUP_DIR, p); 815 /* Replace all / with _. */ 816 for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { 817 if (backfile[i] == '/') 818 backfile[i] = '_'; 819 } 820 } 821 if (strcmp(backfile, "none") != 0 && 822 eli_backup_create(req, prov, backfile) == 0) { 823 printf("\nMetadata backup can be found in %s and\n", backfile); 824 printf("can be restored with the following command:\n"); 825 printf("\n\t# geli restore %s %s\n\n", backfile, prov); 826 } 827} 828 829static void 830eli_attach(struct gctl_req *req) 831{ 832 struct g_eli_metadata md; 833 unsigned char key[G_ELI_USERKEYLEN]; 834 const char *prov; 835 off_t mediasize; 836 int nargs; 837 838 nargs = gctl_get_int(req, "nargs"); 839 if (nargs != 1) { 840 gctl_error(req, "Invalid number of arguments."); 841 return; 842 } 843 prov = gctl_get_ascii(req, "arg0"); 844 845 if (eli_metadata_read(req, prov, &md) == -1) 846 return; 847 848 mediasize = g_get_mediasize(prov); 849 if (md.md_provsize != (uint64_t)mediasize) { 850 gctl_error(req, "Provider size mismatch."); 851 return; 852 } 853 854 if (eli_genkey(req, &md, key, false) == NULL) { 855 bzero(key, sizeof(key)); 856 return; 857 } 858 859 gctl_ro_param(req, "key", sizeof(key), key); 860 if (gctl_issue(req) == NULL) { 861 if (verbose) 862 printf("Attached to %s.\n", prov); 863 } 864 bzero(key, sizeof(key)); 865} 866 867static void 868eli_configure_detached(struct gctl_req *req, const char *prov, bool boot) 869{ 870 struct g_eli_metadata md; 871 872 if (eli_metadata_read(req, prov, &md) == -1) 873 return; 874 875 if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { 876 if (verbose) 877 printf("BOOT flag already configured for %s.\n", prov); 878 } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { 879 if (verbose) 880 printf("BOOT flag not configured for %s.\n", prov); 881 } else { 882 if (boot) 883 md.md_flags |= G_ELI_FLAG_BOOT; 884 else 885 md.md_flags &= ~G_ELI_FLAG_BOOT; 886 eli_metadata_store(req, prov, &md); 887 } 888 bzero(&md, sizeof(md)); 889} 890 891static void 892eli_configure(struct gctl_req *req) 893{ 894 const char *prov; 895 bool boot, noboot; 896 int i, nargs; 897 898 nargs = gctl_get_int(req, "nargs"); 899 if (nargs == 0) { 900 gctl_error(req, "Too few arguments."); 901 return; 902 } 903 904 boot = gctl_get_int(req, "boot"); 905 noboot = gctl_get_int(req, "noboot"); 906 907 if (boot && noboot) { 908 gctl_error(req, "Options -b and -B are mutually exclusive."); 909 return; 910 } 911 if (!boot && !noboot) { 912 gctl_error(req, "No option given."); 913 return; 914 } 915 916 /* First attached providers. */ 917 gctl_issue(req); 918 /* Now the rest. */ 919 for (i = 0; i < nargs; i++) { 920 prov = gctl_get_ascii(req, "arg%d", i); 921 if (!eli_is_attached(prov)) 922 eli_configure_detached(req, prov, boot); 923 } 924} 925 926static void 927eli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 928{ 929 unsigned char key[G_ELI_USERKEYLEN]; 930 intmax_t val, old = 0; 931 int error; 932 933 val = gctl_get_intmax(req, "iterations"); 934 /* Check if iterations number should be changed. */ 935 if (val != -1) 936 md->md_iterations = val; 937 else 938 old = md->md_iterations; 939 940 /* Generate key for Master Key encryption. */ 941 if (eli_genkey(req, md, key, true) == NULL) { 942 bzero(key, sizeof(key)); 943 return; 944 } 945 /* 946 * If number of iterations has changed, but wasn't given as a 947 * command-line argument, update the request. 948 */ 949 if (val == -1 && md->md_iterations != old) { 950 error = gctl_change_param(req, "iterations", sizeof(intmax_t), 951 &md->md_iterations); 952 assert(error == 0); 953 } 954 955 gctl_ro_param(req, "key", sizeof(key), key); 956 gctl_issue(req); 957 bzero(key, sizeof(key)); 958} 959 960static void 961eli_setkey_detached(struct gctl_req *req, const char *prov, 962 struct g_eli_metadata *md) 963{ 964 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 965 unsigned char *mkeydst; 966 unsigned int nkey; 967 intmax_t val; 968 int error; 969 970 if (md->md_keys == 0) { 971 gctl_error(req, "No valid keys on %s.", prov); 972 return; 973 } 974 975 /* Generate key for Master Key decryption. */ 976 if (eli_genkey(req, md, key, false) == NULL) { 977 bzero(key, sizeof(key)); 978 return; 979 } 980 981 /* Decrypt Master Key. */ 982 error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 983 bzero(key, sizeof(key)); 984 if (error != 0) { 985 bzero(md, sizeof(*md)); 986 if (error == -1) 987 gctl_error(req, "Wrong key for %s.", prov); 988 else /* if (error > 0) */ { 989 gctl_error(req, "Cannot decrypt Master Key: %s.", 990 strerror(error)); 991 } 992 return; 993 } 994 if (verbose) 995 printf("Decrypted Master Key %u.\n", nkey); 996 997 val = gctl_get_intmax(req, "keyno"); 998 if (val != -1) 999 nkey = val; 1000#if 0 1001 else 1002 ; /* Use the key number which was found during decryption. */ 1003#endif 1004 if (nkey >= G_ELI_MAXMKEYS) { 1005 gctl_error(req, "Invalid '%s' argument.", "keyno"); 1006 return; 1007 } 1008 1009 val = gctl_get_intmax(req, "iterations"); 1010 /* Check if iterations number should and can be changed. */ 1011 if (val != -1) { 1012 if (bitcount32(md->md_keys) != 1) { 1013 gctl_error(req, "To be able to use '-i' option, only " 1014 "one key can be defined."); 1015 return; 1016 } 1017 if (md->md_keys != (1 << nkey)) { 1018 gctl_error(req, "Only already defined key can be " 1019 "changed when '-i' option is used."); 1020 return; 1021 } 1022 md->md_iterations = val; 1023 } 1024 1025 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 1026 md->md_keys |= (1 << nkey); 1027 1028 bcopy(mkey, mkeydst, sizeof(mkey)); 1029 bzero(mkey, sizeof(mkey)); 1030 1031 /* Generate key for Master Key encryption. */ 1032 if (eli_genkey(req, md, key, true) == NULL) { 1033 bzero(key, sizeof(key)); 1034 bzero(md, sizeof(*md)); 1035 return; 1036 } 1037 1038 /* Encrypt the Master-Key with the new key. */ 1039 error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 1040 bzero(key, sizeof(key)); 1041 if (error != 0) { 1042 bzero(md, sizeof(*md)); 1043 gctl_error(req, "Cannot encrypt Master Key: %s.", 1044 strerror(error)); 1045 return; 1046 } 1047 1048 /* Store metadata with fresh key. */ 1049 eli_metadata_store(req, prov, md); 1050 bzero(md, sizeof(*md)); 1051} 1052 1053static void 1054eli_setkey(struct gctl_req *req) 1055{ 1056 struct g_eli_metadata md; 1057 const char *prov; 1058 int nargs; 1059 1060 nargs = gctl_get_int(req, "nargs"); 1061 if (nargs != 1) { 1062 gctl_error(req, "Invalid number of arguments."); 1063 return; 1064 } 1065 prov = gctl_get_ascii(req, "arg0"); 1066 1067 if (eli_metadata_read(req, prov, &md) == -1) 1068 return; 1069 1070 if (eli_is_attached(prov)) 1071 eli_setkey_attached(req, &md); 1072 else 1073 eli_setkey_detached(req, prov, &md); 1074 1075 if (req->error == NULL || req->error[0] == '\0') { 1076 printf("Note, that the master key encrypted with old keys " 1077 "and/or passphrase may still exists in a metadata backup " 1078 "file.\n"); 1079 } 1080} 1081 1082static void 1083eli_delkey_attached(struct gctl_req *req, const char *prov __unused) 1084{ 1085 1086 gctl_issue(req); 1087} 1088 1089static void 1090eli_delkey_detached(struct gctl_req *req, const char *prov) 1091{ 1092 struct g_eli_metadata md; 1093 unsigned char *mkeydst; 1094 unsigned int nkey; 1095 intmax_t val; 1096 bool all, force; 1097 1098 if (eli_metadata_read(req, prov, &md) == -1) 1099 return; 1100 1101 all = gctl_get_int(req, "all"); 1102 if (all) 1103 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 1104 else { 1105 force = gctl_get_int(req, "force"); 1106 val = gctl_get_intmax(req, "keyno"); 1107 if (val == -1) { 1108 gctl_error(req, "Key number has to be specified."); 1109 return; 1110 } 1111 nkey = val; 1112 if (nkey >= G_ELI_MAXMKEYS) { 1113 gctl_error(req, "Invalid '%s' argument.", "keyno"); 1114 return; 1115 } 1116 if (!(md.md_keys & (1 << nkey)) && !force) { 1117 gctl_error(req, "Master Key %u is not set.", nkey); 1118 return; 1119 } 1120 md.md_keys &= ~(1 << nkey); 1121 if (md.md_keys == 0 && !force) { 1122 gctl_error(req, "This is the last Master Key. Use '-f' " 1123 "option if you really want to remove it."); 1124 return; 1125 } 1126 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 1127 arc4rand(mkeydst, G_ELI_MKEYLEN); 1128 } 1129 1130 eli_metadata_store(req, prov, &md); 1131 bzero(&md, sizeof(md)); 1132} 1133 1134static void 1135eli_delkey(struct gctl_req *req) 1136{ 1137 const char *prov; 1138 int nargs; 1139 1140 nargs = gctl_get_int(req, "nargs"); 1141 if (nargs != 1) { 1142 gctl_error(req, "Invalid number of arguments."); 1143 return; 1144 } 1145 prov = gctl_get_ascii(req, "arg0"); 1146 1147 if (eli_is_attached(prov)) 1148 eli_delkey_attached(req, prov); 1149 else 1150 eli_delkey_detached(req, prov); 1151} 1152 1153static void 1154eli_resume(struct gctl_req *req) 1155{ 1156 struct g_eli_metadata md; 1157 unsigned char key[G_ELI_USERKEYLEN]; 1158 const char *prov; 1159 off_t mediasize; 1160 int nargs; 1161 1162 nargs = gctl_get_int(req, "nargs"); 1163 if (nargs != 1) { 1164 gctl_error(req, "Invalid number of arguments."); 1165 return; 1166 } 1167 prov = gctl_get_ascii(req, "arg0"); 1168 1169 if (eli_metadata_read(req, prov, &md) == -1) 1170 return; 1171 1172 mediasize = g_get_mediasize(prov); 1173 if (md.md_provsize != (uint64_t)mediasize) { 1174 gctl_error(req, "Provider size mismatch."); 1175 return; 1176 } 1177 1178 if (eli_genkey(req, &md, key, false) == NULL) { 1179 bzero(key, sizeof(key)); 1180 return; 1181 } 1182 1183 gctl_ro_param(req, "key", sizeof(key), key); 1184 if (gctl_issue(req) == NULL) { 1185 if (verbose) 1186 printf("Resumed %s.\n", prov); 1187 } 1188 bzero(key, sizeof(key)); 1189} 1190 1191static int 1192eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset) 1193{ 1194 unsigned int overwrites; 1195 unsigned char *sector; 1196 ssize_t size; 1197 int error; 1198 1199 size = sizeof(overwrites); 1200 if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size, 1201 NULL, 0) == -1 || overwrites == 0) { 1202 overwrites = G_ELI_OVERWRITES; 1203 } 1204 1205 size = g_sectorsize(fd); 1206 if (size <= 0) { 1207 gctl_error(req, "Cannot obtain provider sector size %s: %s.", 1208 prov, strerror(errno)); 1209 return (-1); 1210 } 1211 sector = malloc(size); 1212 if (sector == NULL) { 1213 gctl_error(req, "Cannot allocate %zd bytes of memory.", size); 1214 return (-1); 1215 } 1216 1217 error = 0; 1218 do { 1219 arc4rand(sector, size); 1220 if (pwrite(fd, sector, size, offset) != size) { 1221 if (error == 0) 1222 error = errno; 1223 } 1224 (void)g_flush(fd); 1225 } while (--overwrites > 0); 1226 if (error != 0) { 1227 gctl_error(req, "Cannot trash metadata on provider %s: %s.", 1228 prov, strerror(error)); 1229 return (-1); 1230 } 1231 return (0); 1232} 1233 1234static void 1235eli_kill_detached(struct gctl_req *req, const char *prov) 1236{ 1237 off_t offset; 1238 int fd; 1239 1240 /* 1241 * NOTE: Maybe we should verify if this is geli provider first, 1242 * but 'kill' command is quite critical so better don't waste 1243 * the time. 1244 */ 1245#if 0 1246 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 1247 G_ELI_MAGIC); 1248 if (error != 0) { 1249 gctl_error(req, "Cannot read metadata from %s: %s.", prov, 1250 strerror(error)); 1251 return; 1252 } 1253#endif 1254 1255 fd = g_open(prov, 1); 1256 if (fd == -1) { 1257 gctl_error(req, "Cannot open provider %s: %s.", prov, 1258 strerror(errno)); 1259 return; 1260 } 1261 offset = g_mediasize(fd) - g_sectorsize(fd); 1262 if (offset <= 0) { 1263 gctl_error(req, 1264 "Cannot obtain media size or sector size for provider %s: %s.", 1265 prov, strerror(errno)); 1266 (void)g_close(fd); 1267 return; 1268 } 1269 (void)eli_trash_metadata(req, prov, fd, offset); 1270 (void)g_close(fd); 1271} 1272 1273static void 1274eli_kill(struct gctl_req *req) 1275{ 1276 const char *prov; 1277 int i, nargs, all; 1278 1279 nargs = gctl_get_int(req, "nargs"); 1280 all = gctl_get_int(req, "all"); 1281 if (!all && nargs == 0) { 1282 gctl_error(req, "Too few arguments."); 1283 return; 1284 } 1285 /* 1286 * How '-a' option combine with a list of providers: 1287 * Delete Master Keys from all attached providers: 1288 * geli kill -a 1289 * Delete Master Keys from all attached providers and from 1290 * detached da0 and da1: 1291 * geli kill -a da0 da1 1292 * Delete Master Keys from (attached or detached) da0 and da1: 1293 * geli kill da0 da1 1294 */ 1295 1296 /* First detached providers. */ 1297 for (i = 0; i < nargs; i++) { 1298 prov = gctl_get_ascii(req, "arg%d", i); 1299 if (!eli_is_attached(prov)) 1300 eli_kill_detached(req, prov); 1301 } 1302 /* Now attached providers. */ 1303 gctl_issue(req); 1304} 1305 1306static int 1307eli_backup_create(struct gctl_req *req, const char *prov, const char *file) 1308{ 1309 unsigned char *sector; 1310 ssize_t secsize; 1311 int error, filefd, ret; 1312 1313 ret = -1; 1314 filefd = -1; 1315 sector = NULL; 1316 secsize = 0; 1317 1318 secsize = g_get_sectorsize(prov); 1319 if (secsize == 0) { 1320 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1321 strerror(errno)); 1322 goto out; 1323 } 1324 sector = malloc(secsize); 1325 if (sector == NULL) { 1326 gctl_error(req, "Cannot allocate memory."); 1327 goto out; 1328 } 1329 /* Read metadata from the provider. */ 1330 error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC); 1331 if (error != 0) { 1332 gctl_error(req, "Unable to read metadata from %s: %s.", prov, 1333 strerror(error)); 1334 goto out; 1335 } 1336 1337 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1338 if (filefd == -1) { 1339 gctl_error(req, "Unable to open %s: %s.", file, 1340 strerror(errno)); 1341 goto out; 1342 } 1343 /* Write metadata to the destination file. */ 1344 if (write(filefd, sector, secsize) != secsize) { 1345 gctl_error(req, "Unable to write to %s: %s.", file, 1346 strerror(errno)); 1347 (void)close(filefd); 1348 (void)unlink(file); 1349 goto out; 1350 } 1351 (void)fsync(filefd); 1352 (void)close(filefd); 1353 /* Success. */ 1354 ret = 0; 1355out: 1356 if (sector != NULL) { 1357 bzero(sector, secsize); 1358 free(sector); 1359 } 1360 return (ret); 1361} 1362 1363static void 1364eli_backup(struct gctl_req *req) 1365{ 1366 const char *file, *prov; 1367 int nargs; 1368 1369 nargs = gctl_get_int(req, "nargs"); 1370 if (nargs != 2) { 1371 gctl_error(req, "Invalid number of arguments."); 1372 return; 1373 } 1374 prov = gctl_get_ascii(req, "arg0"); 1375 file = gctl_get_ascii(req, "arg1"); 1376 1377 eli_backup_create(req, prov, file); 1378} 1379 1380static void 1381eli_restore(struct gctl_req *req) 1382{ 1383 struct g_eli_metadata md; 1384 const char *file, *prov; 1385 off_t mediasize; 1386 int nargs; 1387 1388 nargs = gctl_get_int(req, "nargs"); 1389 if (nargs != 2) { 1390 gctl_error(req, "Invalid number of arguments."); 1391 return; 1392 } 1393 file = gctl_get_ascii(req, "arg0"); 1394 prov = gctl_get_ascii(req, "arg1"); 1395 1396 /* Read metadata from the backup file. */ 1397 if (eli_metadata_read(req, file, &md) == -1) 1398 return; 1399 /* Obtain provider's mediasize. */ 1400 mediasize = g_get_mediasize(prov); 1401 if (mediasize == 0) { 1402 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1403 strerror(errno)); 1404 return; 1405 } 1406 /* Check if the provider size has changed since we did the backup. */ 1407 if (md.md_provsize != (uint64_t)mediasize) { 1408 if (gctl_get_int(req, "force")) { 1409 md.md_provsize = mediasize; 1410 } else { 1411 gctl_error(req, "Provider size mismatch: " 1412 "wrong backup file?"); 1413 return; 1414 } 1415 } 1416 /* Write metadata to the provider. */ 1417 (void)eli_metadata_store(req, prov, &md); 1418} 1419 1420static void 1421eli_resize(struct gctl_req *req) 1422{ 1423 struct g_eli_metadata md; 1424 const char *prov; 1425 unsigned char *sector; 1426 ssize_t secsize; 1427 off_t mediasize, oldsize; 1428 int error, nargs, provfd; 1429 1430 nargs = gctl_get_int(req, "nargs"); 1431 if (nargs != 1) { 1432 gctl_error(req, "Invalid number of arguments."); 1433 return; 1434 } 1435 prov = gctl_get_ascii(req, "arg0"); 1436 1437 provfd = -1; 1438 sector = NULL; 1439 secsize = 0; 1440 1441 provfd = g_open(prov, 1); 1442 if (provfd == -1) { 1443 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1444 goto out; 1445 } 1446 1447 mediasize = g_mediasize(provfd); 1448 secsize = g_sectorsize(provfd); 1449 if (mediasize == -1 || secsize == -1) { 1450 gctl_error(req, "Cannot get information about %s: %s.", prov, 1451 strerror(errno)); 1452 goto out; 1453 } 1454 1455 sector = malloc(secsize); 1456 if (sector == NULL) { 1457 gctl_error(req, "Cannot allocate memory."); 1458 goto out; 1459 } 1460 1461 oldsize = gctl_get_intmax(req, "oldsize"); 1462 if (oldsize < 0 || oldsize > mediasize) { 1463 gctl_error(req, "Invalid oldsize: Out of range."); 1464 goto out; 1465 } 1466 if (oldsize == mediasize) { 1467 gctl_error(req, "Size hasn't changed."); 1468 goto out; 1469 } 1470 1471 /* Read metadata from the 'oldsize' offset. */ 1472 if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) { 1473 gctl_error(req, "Cannot read old metadata: %s.", 1474 strerror(errno)); 1475 goto out; 1476 } 1477 1478 /* Check if this sector contains geli metadata. */ 1479 error = eli_metadata_decode(sector, &md); 1480 switch (error) { 1481 case 0: 1482 break; 1483 case EOPNOTSUPP: 1484 gctl_error(req, 1485 "Provider's %s metadata version %u is too new.\n" 1486 "geli: The highest supported version is %u.", 1487 prov, (unsigned int)md.md_version, G_ELI_VERSION); 1488 goto out; 1489 case EINVAL: 1490 gctl_error(req, "Inconsistent provider's %s metadata.", prov); 1491 goto out; 1492 default: 1493 gctl_error(req, 1494 "Unexpected error while decoding provider's %s metadata: %s.", 1495 prov, strerror(error)); 1496 goto out; 1497 } 1498 1499 /* 1500 * If the old metadata doesn't have a correct provider size, refuse 1501 * to resize. 1502 */ 1503 if (md.md_provsize != (uint64_t)oldsize) { 1504 gctl_error(req, "Provider size mismatch at oldsize."); 1505 goto out; 1506 } 1507 1508 /* 1509 * Update the old metadata with the current provider size and write 1510 * it back to the correct place on the provider. 1511 */ 1512 md.md_provsize = mediasize; 1513 /* Write metadata to the provider. */ 1514 (void)eli_metadata_store(req, prov, &md); 1515 /* Now trash the old metadata. */ 1516 (void)eli_trash_metadata(req, prov, provfd, oldsize - secsize); 1517out: 1518 if (provfd != -1) 1519 (void)g_close(provfd); 1520 if (sector != NULL) { 1521 bzero(sector, secsize); 1522 free(sector); 1523 } 1524} 1525 1526static void 1527eli_clear(struct gctl_req *req) 1528{ 1529 const char *name; 1530 int error, i, nargs; 1531 1532 nargs = gctl_get_int(req, "nargs"); 1533 if (nargs < 1) { 1534 gctl_error(req, "Too few arguments."); 1535 return; 1536 } 1537 1538 for (i = 0; i < nargs; i++) { 1539 name = gctl_get_ascii(req, "arg%d", i); 1540 error = g_metadata_clear(name, G_ELI_MAGIC); 1541 if (error != 0) { 1542 fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1543 name, strerror(error)); 1544 gctl_error(req, "Not fully done."); 1545 continue; 1546 } 1547 if (verbose) 1548 printf("Metadata cleared on %s.\n", name); 1549 } 1550} 1551 1552static void 1553eli_dump(struct gctl_req *req) 1554{ 1555 struct g_eli_metadata md; 1556 const char *name; 1557 int i, nargs; 1558 1559 nargs = gctl_get_int(req, "nargs"); 1560 if (nargs < 1) { 1561 gctl_error(req, "Too few arguments."); 1562 return; 1563 } 1564 1565 for (i = 0; i < nargs; i++) { 1566 name = gctl_get_ascii(req, "arg%d", i); 1567 if (eli_metadata_read(NULL, name, &md) == -1) { 1568 gctl_error(req, "Not fully done."); 1569 continue; 1570 } 1571 printf("Metadata on %s:\n", name); 1572 eli_metadata_dump(&md); 1573 printf("\n"); 1574 } 1575} 1576