geom_eli.c revision 166892
1169689Skan/*- 2169689Skan * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3169689Skan * All rights reserved. 4169689Skan * 5169689Skan * Redistribution and use in source and binary forms, with or without 6169689Skan * modification, are permitted provided that the following conditions 7169689Skan * are met: 8169689Skan * 1. Redistributions of source code must retain the above copyright 9169689Skan * notice, this list of conditions and the following disclaimer. 10169689Skan * 2. Redistributions in binary form must reproduce the above copyright 11169689Skan * notice, this list of conditions and the following disclaimer in the 12169689Skan * documentation and/or other materials provided with the distribution. 13169689Skan * 14169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24169689Skan * SUCH DAMAGE. 25169689Skan */ 26169689Skan 27169689Skan#include <sys/cdefs.h> 28169689Skan__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 166892 2007-02-22 19:25:37Z pjd $"); 29169689Skan 30169689Skan#include <stdio.h> 31169689Skan#include <stdint.h> 32169689Skan#include <stdlib.h> 33169689Skan#include <unistd.h> 34169689Skan#include <fcntl.h> 35169689Skan#include <readpassphrase.h> 36169689Skan#include <string.h> 37169689Skan#include <strings.h> 38169689Skan#include <libgeom.h> 39169689Skan#include <paths.h> 40169689Skan#include <errno.h> 41169689Skan#include <assert.h> 42169689Skan 43169689Skan#include <sys/param.h> 44169689Skan#include <sys/mman.h> 45169689Skan#include <sys/resource.h> 46169689Skan#include <opencrypto/cryptodev.h> 47169689Skan#include <geom/eli/g_eli.h> 48169689Skan#include <geom/eli/pkcs5v2.h> 49169689Skan 50169689Skan#include "core/geom.h" 51169689Skan#include "misc/subr.h" 52169689Skan 53169689Skan 54169689Skanuint32_t lib_version = G_LIB_VERSION; 55169689Skanuint32_t version = G_ELI_VERSION; 56169689Skan 57169689Skanstatic char aalgo[] = "none"; 58169689Skanstatic char ealgo[] = "aes"; 59169689Skanstatic intmax_t keylen = 0; 60169689Skanstatic intmax_t keyno = -1; 61169689Skanstatic intmax_t iterations = -1; 62169689Skanstatic intmax_t sectorsize = 0; 63169689Skanstatic char keyfile[] = "", newkeyfile[] = ""; 64169689Skan 65169689Skanstatic void eli_main(struct gctl_req *req, unsigned flags); 66169689Skanstatic void eli_init(struct gctl_req *req); 67169689Skanstatic void eli_attach(struct gctl_req *req); 68169689Skanstatic void eli_configure(struct gctl_req *req); 69169689Skanstatic void eli_setkey(struct gctl_req *req); 70169689Skanstatic void eli_delkey(struct gctl_req *req); 71169689Skanstatic void eli_kill(struct gctl_req *req); 72169689Skanstatic void eli_backup(struct gctl_req *req); 73169689Skanstatic void eli_restore(struct gctl_req *req); 74169689Skanstatic void eli_clear(struct gctl_req *req); 75169689Skanstatic void eli_dump(struct gctl_req *req); 76169689Skan 77169689Skan/* 78169689Skan * Available commands: 79169689Skan * 80169689Skan * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov 81169689Skan * label - alias for 'init' 82169689Skan * attach [-dprv] [-k keyfile] prov 83169689Skan * detach [-fl] prov ... 84169689Skan * stop - alias for 'detach' 85169689Skan * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov ... 86169689Skan * configure [-bB] prov ... 87169689Skan * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov 88169689Skan * delkey [-afv] [-n keyno] prov 89169689Skan * kill [-av] [prov ...] 90169689Skan * backup [-v] prov file 91169689Skan * restore [-v] file prov 92169689Skan * clear [-v] prov ... 93169689Skan * dump [-v] prov ... 94169689Skan */ 95169689Skanstruct g_command class_commands[] = { 96169689Skan { "init", G_FLAG_VERBOSE, eli_main, 97169689Skan { 98169689Skan { 'a', "aalgo", aalgo, G_TYPE_STRING }, 99169689Skan { 'b', "boot", NULL, G_TYPE_BOOL }, 100169689Skan { 'e', "ealgo", ealgo, G_TYPE_STRING }, 101169689Skan { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 102169689Skan { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 103169689Skan { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 104169689Skan { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 105169689Skan { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 106169689Skan G_OPT_SENTINEL 107169689Skan }, 108169689Skan "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" 109169689Skan }, 110169689Skan { "label", G_FLAG_VERBOSE, eli_main, 111169689Skan { 112169689Skan { 'a', "aalgo", aalgo, G_TYPE_STRING }, 113169689Skan { 'b', "boot", NULL, G_TYPE_BOOL }, 114169689Skan { 'e', "ealgo", ealgo, G_TYPE_STRING }, 115169689Skan { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 116169689Skan { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 117169689Skan { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 118169689Skan { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 119169689Skan { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 120169689Skan G_OPT_SENTINEL 121169689Skan }, 122169689Skan "- an alias for 'init'" 123169689Skan }, 124169689Skan { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 125169689Skan { 126169689Skan { 'd', "detach", NULL, G_TYPE_BOOL }, 127169689Skan { 'k', "keyfile", keyfile, G_TYPE_STRING }, 128169689Skan { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 129169689Skan { 'r', "readonly", NULL, G_TYPE_BOOL }, 130169689Skan G_OPT_SENTINEL 131169689Skan }, 132169689Skan "[-dprv] [-k keyfile] prov" 133169689Skan }, 134169689Skan { "detach", 0, NULL, 135169689Skan { 136169689Skan { 'f', "force", NULL, G_TYPE_BOOL }, 137169689Skan { 'l', "last", NULL, G_TYPE_BOOL }, 138169689Skan G_OPT_SENTINEL 139169689Skan }, 140169689Skan "[-fl] prov ..." 141169689Skan }, 142169689Skan { "stop", 0, NULL, 143169689Skan { 144169689Skan { 'f', "force", NULL, G_TYPE_BOOL }, 145169689Skan { 'l', "last", NULL, G_TYPE_BOOL }, 146169689Skan G_OPT_SENTINEL 147169689Skan }, 148169689Skan "- an alias for 'detach'" 149169689Skan }, 150169689Skan { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 151169689Skan { 152169689Skan { 'a', "aalgo", aalgo, G_TYPE_STRING }, 153169689Skan { 'd', "detach", NULL, G_TYPE_BOOL }, 154169689Skan { 'e', "ealgo", ealgo, G_TYPE_STRING }, 155169689Skan { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 156169689Skan { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 157169689Skan G_OPT_SENTINEL 158169689Skan }, 159169689Skan "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov ..." 160169689Skan }, 161169689Skan { "configure", G_FLAG_VERBOSE, eli_main, 162169689Skan { 163169689Skan { 'b', "boot", NULL, G_TYPE_BOOL }, 164169689Skan { 'B', "noboot", NULL, G_TYPE_BOOL }, 165169689Skan G_OPT_SENTINEL 166169689Skan }, 167169689Skan "[-bB] prov ..." 168169689Skan }, 169169689Skan { "setkey", G_FLAG_VERBOSE, eli_main, 170169689Skan { 171169689Skan { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 172169689Skan { 'k', "keyfile", keyfile, G_TYPE_STRING }, 173169689Skan { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 174169689Skan { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 175169689Skan { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 176169689Skan { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 177169689Skan G_OPT_SENTINEL 178169689Skan }, 179169689Skan "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" 180169689Skan }, 181169689Skan { "delkey", G_FLAG_VERBOSE, eli_main, 182169689Skan { 183169689Skan { 'a', "all", NULL, G_TYPE_BOOL }, 184169689Skan { 'f', "force", NULL, G_TYPE_BOOL }, 185169689Skan { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 186169689Skan G_OPT_SENTINEL 187169689Skan }, 188169689Skan "[-afv] [-n keyno] prov" 189169689Skan }, 190169689Skan { "kill", G_FLAG_VERBOSE, eli_main, 191169689Skan { 192169689Skan { 'a', "all", NULL, G_TYPE_BOOL }, 193169689Skan G_OPT_SENTINEL 194169689Skan }, 195169689Skan "[-av] [prov ...]" 196169689Skan }, 197169689Skan { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 198169689Skan "[-v] prov file" 199169689Skan }, 200169689Skan { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 201169689Skan "[-v] file prov" 202169689Skan }, 203169689Skan { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 204169689Skan "[-v] prov ..." 205169689Skan }, 206169689Skan { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 207169689Skan "[-v] prov ..." 208169689Skan }, 209169689Skan G_CMD_SENTINEL 210169689Skan}; 211169689Skan 212169689Skanstatic int verbose = 0; 213169689Skan 214169689Skanstatic int 215169689Skaneli_protect(struct gctl_req *req) 216169689Skan{ 217169689Skan struct rlimit rl; 218169689Skan 219169689Skan /* Disable core dumps. */ 220169689Skan rl.rlim_cur = 0; 221169689Skan rl.rlim_max = 0; 222169689Skan if (setrlimit(RLIMIT_CORE, &rl) == -1) { 223169689Skan gctl_error(req, "Cannot disable core dumps: %s.", 224169689Skan strerror(errno)); 225169689Skan return (-1); 226169689Skan } 227169689Skan /* Disable swapping. */ 228169689Skan if (mlockall(MCL_FUTURE) == -1) { 229169689Skan gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 230169689Skan return (-1); 231169689Skan } 232169689Skan return (0); 233169689Skan} 234169689Skan 235169689Skanstatic void 236169689Skaneli_main(struct gctl_req *req, unsigned flags) 237169689Skan{ 238169689Skan const char *name; 239169689Skan 240169689Skan if (eli_protect(req) == -1) 241169689Skan return; 242169689Skan 243169689Skan if ((flags & G_FLAG_VERBOSE) != 0) 244169689Skan verbose = 1; 245169689Skan 246169689Skan name = gctl_get_ascii(req, "verb"); 247169689Skan if (name == NULL) { 248169689Skan gctl_error(req, "No '%s' argument.", "verb"); 249169689Skan return; 250169689Skan } 251169689Skan if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 252169689Skan eli_init(req); 253169689Skan else if (strcmp(name, "attach") == 0) 254169689Skan eli_attach(req); 255169689Skan else if (strcmp(name, "configure") == 0) 256169689Skan eli_configure(req); 257169689Skan else if (strcmp(name, "setkey") == 0) 258169689Skan eli_setkey(req); 259169689Skan else if (strcmp(name, "delkey") == 0) 260169689Skan eli_delkey(req); 261169689Skan else if (strcmp(name, "kill") == 0) 262169689Skan eli_kill(req); 263169689Skan else if (strcmp(name, "backup") == 0) 264169689Skan eli_backup(req); 265169689Skan else if (strcmp(name, "restore") == 0) 266169689Skan eli_restore(req); 267169689Skan else if (strcmp(name, "dump") == 0) 268169689Skan eli_dump(req); 269169689Skan else if (strcmp(name, "clear") == 0) 270169689Skan eli_clear(req); 271169689Skan else 272169689Skan gctl_error(req, "Unknown command: %s.", name); 273169689Skan} 274169689Skan 275169689Skanstatic void 276169689Skanarc4rand(unsigned char *buf, size_t size) 277169689Skan{ 278169689Skan uint32_t *buf4; 279169689Skan size_t size4; 280169689Skan unsigned i; 281169689Skan 282169689Skan buf4 = (uint32_t *)buf; 283169689Skan size4 = size / 4; 284169689Skan 285169689Skan for (i = 0; i < size4; i++) 286169689Skan buf4[i] = arc4random(); 287169689Skan for (i *= 4; i < size; i++) 288169689Skan buf[i] = arc4random() % 0xff; 289169689Skan} 290169689Skan 291169689Skanstatic int 292169689Skaneli_is_attached(const char *prov) 293169689Skan{ 294169689Skan char name[MAXPATHLEN]; 295169689Skan unsigned secsize; 296169689Skan 297169689Skan /* 298169689Skan * Not the best way to do it, but the easiest. 299169689Skan * We try to open provider and check if it is a GEOM provider 300169689Skan * by asking about its sectorsize. 301169689Skan */ 302169689Skan snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 303169689Skan secsize = g_get_sectorsize(name); 304169689Skan if (secsize > 0) 305169689Skan return (1); 306169689Skan return (0); 307169689Skan} 308169689Skan 309169689Skanstatic unsigned char * 310169689Skaneli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 311169689Skan int new) 312169689Skan{ 313169689Skan struct hmac_ctx ctx; 314169689Skan const char *str; 315169689Skan int error, nopassphrase; 316169689Skan 317169689Skan nopassphrase = 318169689Skan gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 319169689Skan 320169689Skan g_eli_crypto_hmac_init(&ctx, NULL, 0); 321169689Skan 322169689Skan str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile"); 323169689Skan if (str[0] == '\0' && nopassphrase) { 324169689Skan gctl_error(req, "No key components given."); 325169689Skan return (NULL); 326169689Skan } else if (str[0] != '\0') { 327169689Skan char buf[MAXPHYS]; 328169689Skan ssize_t done; 329169689Skan int fd; 330169689Skan 331169689Skan if (strcmp(str, "-") == 0) 332169689Skan fd = STDIN_FILENO; 333169689Skan else { 334169689Skan fd = open(str, O_RDONLY); 335169689Skan if (fd == -1) { 336169689Skan gctl_error(req, "Cannot open keyfile %s: %s.", 337169689Skan str, strerror(errno)); 338169689Skan return (NULL); 339169689Skan } 340169689Skan } 341169689Skan while ((done = read(fd, buf, sizeof(buf))) > 0) 342169689Skan g_eli_crypto_hmac_update(&ctx, buf, done); 343169689Skan error = errno; 344169689Skan if (strcmp(str, "-") != 0) 345169689Skan close(fd); 346169689Skan bzero(buf, sizeof(buf)); 347169689Skan if (done == -1) { 348169689Skan gctl_error(req, "Cannot read keyfile %s: %s.", str, 349169689Skan strerror(error)); 350169689Skan return (NULL); 351169689Skan } 352169689Skan } 353169689Skan 354169689Skan if (!nopassphrase) { 355169689Skan char buf1[BUFSIZ], buf2[BUFSIZ], *p; 356169689Skan 357169689Skan if (!new && md->md_iterations == -1) { 358169689Skan gctl_error(req, "Missing -p flag."); 359169689Skan return (NULL); 360169689Skan } 361169689Skan for (;;) { 362169689Skan p = readpassphrase( 363169689Skan new ? "Enter new passphrase:" : "Enter passphrase:", 364169689Skan buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); 365169689Skan if (p == NULL) { 366169689Skan bzero(buf1, sizeof(buf1)); 367169689Skan gctl_error(req, "Cannot read passphrase: %s.", 368169689Skan strerror(errno)); 369169689Skan return (NULL); 370169689Skan } 371169689Skan 372169689Skan if (new) { 373169689Skan p = readpassphrase("Reenter new passphrase: ", 374169689Skan buf2, sizeof(buf2), 375169689Skan RPP_ECHO_OFF | RPP_REQUIRE_TTY); 376169689Skan if (p == NULL) { 377169689Skan bzero(buf1, sizeof(buf1)); 378169689Skan gctl_error(req, 379169689Skan "Cannot read passphrase: %s.", 380169689Skan strerror(errno)); 381169689Skan return (NULL); 382169689Skan } 383169689Skan 384169689Skan if (strcmp(buf1, buf2) != 0) { 385169689Skan bzero(buf2, sizeof(buf2)); 386169689Skan fprintf(stderr, "They didn't match.\n"); 387169689Skan continue; 388169689Skan } 389169689Skan bzero(buf2, sizeof(buf2)); 390169689Skan } 391169689Skan break; 392169689Skan } 393169689Skan /* 394169689Skan * Field md_iterations equal to -1 means "choose some sane 395169689Skan * value for me". 396169689Skan */ 397169689Skan if (md->md_iterations == -1) { 398169689Skan assert(new); 399169689Skan if (verbose) 400169689Skan printf("Calculating number of iterations...\n"); 401169689Skan md->md_iterations = pkcs5v2_calculate(2000000); 402169689Skan assert(md->md_iterations > 0); 403169689Skan if (verbose) { 404169689Skan printf("Done, using %d iterations.\n", 405169689Skan md->md_iterations); 406169689Skan } 407169689Skan } 408169689Skan /* 409169689Skan * If md_iterations is equal to 0, user don't want PKCS#5v2. 410169689Skan */ 411169689Skan if (md->md_iterations == 0) { 412169689Skan g_eli_crypto_hmac_update(&ctx, md->md_salt, 413169689Skan sizeof(md->md_salt)); 414169689Skan g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1)); 415169689Skan } else /* if (md->md_iterations > 0) */ { 416169689Skan unsigned char dkey[G_ELI_USERKEYLEN]; 417169689Skan 418169689Skan pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 419169689Skan sizeof(md->md_salt), buf1, md->md_iterations); 420169689Skan g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 421169689Skan bzero(dkey, sizeof(dkey)); 422169689Skan } 423169689Skan bzero(buf1, sizeof(buf1)); 424169689Skan } 425169689Skan g_eli_crypto_hmac_final(&ctx, key, 0); 426169689Skan return (key); 427169689Skan} 428169689Skan 429169689Skanstatic int 430169689Skaneli_metadata_read(struct gctl_req *req, const char *prov, 431169689Skan struct g_eli_metadata *md) 432169689Skan{ 433169689Skan unsigned char sector[sizeof(struct g_eli_metadata)]; 434169689Skan int error; 435169689Skan 436169689Skan if (g_get_sectorsize(prov) == 0) { 437169689Skan int fd; 438169689Skan 439169689Skan /* This is a file probably. */ 440169689Skan fd = open(prov, O_RDONLY); 441169689Skan if (fd == -1) { 442169689Skan gctl_error(req, "Cannot open %s: %s.", prov, 443169689Skan strerror(errno)); 444169689Skan return (-1); 445169689Skan } 446169689Skan if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 447169689Skan gctl_error(req, "Cannot read metadata from %s: %s.", 448169689Skan prov, strerror(errno)); 449169689Skan close(fd); 450169689Skan return (-1); 451169689Skan } 452169689Skan close(fd); 453169689Skan } else { 454169689Skan /* This is a GEOM provider. */ 455169689Skan error = g_metadata_read(prov, sector, sizeof(sector), 456169689Skan G_ELI_MAGIC); 457169689Skan if (error != 0) { 458169689Skan gctl_error(req, "Cannot read metadata from %s: %s.", 459169689Skan prov, strerror(error)); 460169689Skan return (-1); 461169689Skan } 462169689Skan } 463169689Skan if (eli_metadata_decode(sector, md) != 0) { 464169689Skan gctl_error(req, "MD5 hash mismatch for %s.", prov); 465169689Skan return (-1); 466169689Skan } 467169689Skan return (0); 468169689Skan} 469169689Skan 470169689Skanstatic int 471169689Skaneli_metadata_store(struct gctl_req *req, const char *prov, 472169689Skan struct g_eli_metadata *md) 473169689Skan{ 474169689Skan unsigned char sector[sizeof(struct g_eli_metadata)]; 475169689Skan int error; 476169689Skan 477169689Skan eli_metadata_encode(md, sector); 478169689Skan if (g_get_sectorsize(prov) == 0) { 479169689Skan int fd; 480169689Skan 481169689Skan /* This is a file probably. */ 482169689Skan fd = open(prov, O_WRONLY | O_TRUNC); 483169689Skan if (fd == -1) { 484169689Skan gctl_error(req, "Cannot open %s: %s.", prov, 485169689Skan strerror(errno)); 486169689Skan bzero(sector, sizeof(sector)); 487169689Skan return (-1); 488169689Skan } 489169689Skan if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 490169689Skan gctl_error(req, "Cannot write metadata to %s: %s.", 491169689Skan prov, strerror(errno)); 492169689Skan bzero(sector, sizeof(sector)); 493169689Skan close(fd); 494169689Skan return (-1); 495169689Skan } 496169689Skan close(fd); 497169689Skan } else { 498169689Skan /* This is a GEOM provider. */ 499169689Skan error = g_metadata_store(prov, sector, sizeof(sector)); 500169689Skan if (error != 0) { 501169689Skan gctl_error(req, "Cannot write metadata to %s: %s.", 502169689Skan prov, strerror(errno)); 503169689Skan bzero(sector, sizeof(sector)); 504169689Skan return (-1); 505169689Skan } 506169689Skan } 507169689Skan bzero(sector, sizeof(sector)); 508169689Skan return (0); 509169689Skan} 510169689Skan 511169689Skanstatic void 512169689Skaneli_init(struct gctl_req *req) 513169689Skan{ 514169689Skan struct g_eli_metadata md; 515169689Skan unsigned char sector[sizeof(struct g_eli_metadata)]; 516169689Skan unsigned char key[G_ELI_USERKEYLEN]; 517169689Skan const char *str, *prov; 518169689Skan unsigned secsize; 519169689Skan off_t mediasize; 520169689Skan intmax_t val; 521169689Skan int error, nargs; 522169689Skan 523169689Skan nargs = gctl_get_int(req, "nargs"); 524169689Skan if (nargs != 1) { 525169689Skan gctl_error(req, "Invalid number of arguments."); 526169689Skan return; 527169689Skan } 528169689Skan prov = gctl_get_ascii(req, "arg0"); 529169689Skan mediasize = g_get_mediasize(prov); 530169689Skan secsize = g_get_sectorsize(prov); 531169689Skan if (mediasize == 0 || secsize == 0) { 532169689Skan gctl_error(req, "Cannot get informations about %s: %s.", prov, 533169689Skan strerror(errno)); 534169689Skan return; 535169689Skan } 536169689Skan 537169689Skan bzero(&md, sizeof(md)); 538169689Skan strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 539169689Skan md.md_version = G_ELI_VERSION; 540169689Skan md.md_flags = 0; 541169689Skan if (gctl_get_int(req, "boot")) 542169689Skan md.md_flags |= G_ELI_FLAG_BOOT; 543169689Skan md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 544169689Skan str = gctl_get_ascii(req, "aalgo"); 545169689Skan if (strcmp(str, "none") != 0) { 546169689Skan md.md_aalgo = g_eli_str2aalgo(str); 547169689Skan if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 548169689Skan md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 549169689Skan md.md_flags |= G_ELI_FLAG_AUTH; 550169689Skan } else { 551169689Skan /* 552169689Skan * For backward compatibility, check if the -a option 553169689Skan * was used to provide encryption algorithm. 554169689Skan */ 555169689Skan md.md_ealgo = g_eli_str2ealgo(str); 556169689Skan if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 557169689Skan md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 558169689Skan gctl_error(req, 559169689Skan "Invalid authentication algorithm."); 560169689Skan return; 561169689Skan } else { 562169689Skan fprintf(stderr, "warning: The -e option, not " 563169689Skan "the -a option is now used to specify " 564169689Skan "encryption algorithm to use.\n"); 565169689Skan } 566169689Skan } 567169689Skan } 568169689Skan if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 569169689Skan md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 570169689Skan str = gctl_get_ascii(req, "ealgo"); 571169689Skan md.md_ealgo = g_eli_str2ealgo(str); 572169689Skan if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 573169689Skan md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 574169689Skan gctl_error(req, "Invalid encryption algorithm."); 575169689Skan return; 576169689Skan } 577169689Skan } 578169689Skan val = gctl_get_intmax(req, "keylen"); 579169689Skan md.md_keylen = val; 580169689Skan md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 581169689Skan if (md.md_keylen == 0) { 582169689Skan gctl_error(req, "Invalid key length."); 583169689Skan return; 584169689Skan } 585169689Skan md.md_provsize = mediasize; 586169689Skan 587169689Skan val = gctl_get_intmax(req, "iterations"); 588169689Skan if (val != -1) { 589169689Skan int nonewpassphrase; 590169689Skan 591169689Skan /* 592169689Skan * Don't allow to set iterations when there will be no 593169689Skan * passphrase. 594169689Skan */ 595169689Skan nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 596169689Skan if (nonewpassphrase) { 597169689Skan gctl_error(req, 598169689Skan "Options -i and -P are mutually exclusive."); 599169689Skan return; 600169689Skan } 601169689Skan } 602169689Skan md.md_iterations = val; 603169689Skan 604169689Skan val = gctl_get_intmax(req, "sectorsize"); 605169689Skan if (val == 0) 606169689Skan md.md_sectorsize = secsize; 607169689Skan else { 608169689Skan if (val < 0 || (val % secsize) != 0) { 609169689Skan gctl_error(req, "Invalid sector size."); 610169689Skan return; 611169689Skan } 612169689Skan md.md_sectorsize = val; 613169689Skan } 614169689Skan 615169689Skan md.md_keys = 0x01; 616169689Skan arc4rand(md.md_salt, sizeof(md.md_salt)); 617169689Skan arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 618169689Skan 619169689Skan /* Generate user key. */ 620169689Skan if (eli_genkey(req, &md, key, 1) == NULL) { 621169689Skan bzero(key, sizeof(key)); 622169689Skan bzero(&md, sizeof(md)); 623169689Skan return; 624169689Skan } 625169689Skan 626169689Skan /* Encrypt the first and the only Master Key. */ 627169689Skan error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 628169689Skan bzero(key, sizeof(key)); 629169689Skan if (error != 0) { 630169689Skan bzero(&md, sizeof(md)); 631169689Skan gctl_error(req, "Cannot encrypt Master Key: %s.", 632169689Skan strerror(error)); 633169689Skan return; 634169689Skan } 635169689Skan 636169689Skan eli_metadata_encode(&md, sector); 637169689Skan bzero(&md, sizeof(md)); 638169689Skan error = g_metadata_store(prov, sector, sizeof(sector)); 639169689Skan bzero(sector, sizeof(sector)); 640169689Skan if (error != 0) { 641169689Skan gctl_error(req, "Cannot store metadata on %s: %s.", prov, 642169689Skan strerror(error)); 643169689Skan return; 644169689Skan } 645169689Skan if (verbose) 646169689Skan printf("Metadata value stored on %s.\n", prov); 647169689Skan} 648169689Skan 649169689Skanstatic void 650169689Skaneli_attach(struct gctl_req *req) 651169689Skan{ 652169689Skan struct g_eli_metadata md; 653169689Skan unsigned char key[G_ELI_USERKEYLEN]; 654169689Skan const char *prov; 655169689Skan int nargs; 656169689Skan 657169689Skan nargs = gctl_get_int(req, "nargs"); 658169689Skan if (nargs != 1) { 659169689Skan gctl_error(req, "Invalid number of arguments."); 660169689Skan return; 661169689Skan } 662169689Skan prov = gctl_get_ascii(req, "arg0"); 663169689Skan 664169689Skan if (eli_metadata_read(req, prov, &md) == -1) 665169689Skan return; 666169689Skan 667169689Skan if (eli_genkey(req, &md, key, 0) == NULL) { 668169689Skan bzero(key, sizeof(key)); 669169689Skan return; 670169689Skan } 671169689Skan 672169689Skan gctl_ro_param(req, "key", sizeof(key), key); 673169689Skan if (gctl_issue(req) == NULL) { 674169689Skan if (verbose) 675169689Skan printf("Attached to %s.\n", prov); 676169689Skan } 677169689Skan bzero(key, sizeof(key)); 678169689Skan} 679169689Skan 680169689Skanstatic void 681169689Skaneli_configure_detached(struct gctl_req *req, const char *prov, int boot) 682169689Skan{ 683169689Skan struct g_eli_metadata md; 684169689Skan 685169689Skan if (eli_metadata_read(req, prov, &md) == -1) 686169689Skan return; 687169689Skan 688169689Skan if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { 689169689Skan if (verbose) 690169689Skan printf("BOOT flag already configured for %s.\n", prov); 691169689Skan } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { 692169689Skan if (verbose) 693169689Skan printf("BOOT flag not configured for %s.\n", prov); 694169689Skan } else { 695169689Skan if (boot) 696169689Skan md.md_flags |= G_ELI_FLAG_BOOT; 697169689Skan else 698169689Skan md.md_flags &= ~G_ELI_FLAG_BOOT; 699169689Skan eli_metadata_store(req, prov, &md); 700169689Skan } 701169689Skan bzero(&md, sizeof(md)); 702169689Skan} 703169689Skan 704169689Skanstatic void 705169689Skaneli_configure(struct gctl_req *req) 706169689Skan{ 707169689Skan const char *prov; 708169689Skan int i, nargs, boot, noboot; 709169689Skan 710169689Skan nargs = gctl_get_int(req, "nargs"); 711169689Skan if (nargs == 0) { 712169689Skan gctl_error(req, "Too few arguments."); 713169689Skan return; 714169689Skan } 715169689Skan 716169689Skan boot = gctl_get_int(req, "boot"); 717169689Skan noboot = gctl_get_int(req, "noboot"); 718169689Skan 719169689Skan if (boot && noboot) { 720169689Skan gctl_error(req, "Options -b and -B are mutually exclusive."); 721169689Skan return; 722169689Skan } 723169689Skan if (!boot && !noboot) { 724169689Skan gctl_error(req, "No option given."); 725169689Skan return; 726169689Skan } 727169689Skan 728169689Skan /* First attached providers. */ 729169689Skan gctl_issue(req); 730169689Skan /* Now the rest. */ 731169689Skan for (i = 0; i < nargs; i++) { 732169689Skan prov = gctl_get_ascii(req, "arg%d", i); 733169689Skan if (!eli_is_attached(prov)) 734169689Skan eli_configure_detached(req, prov, boot); 735169689Skan } 736169689Skan} 737169689Skan 738169689Skanstatic void 739169689Skaneli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 740169689Skan{ 741169689Skan unsigned char key[G_ELI_USERKEYLEN]; 742169689Skan intmax_t val, old = 0; 743169689Skan int error; 744169689Skan 745169689Skan val = gctl_get_intmax(req, "iterations"); 746169689Skan /* Check if iterations number should be changed. */ 747169689Skan if (val != -1) 748169689Skan md->md_iterations = val; 749169689Skan else 750169689Skan old = md->md_iterations; 751169689Skan 752169689Skan /* Generate key for Master Key encryption. */ 753169689Skan if (eli_genkey(req, md, key, 1) == NULL) { 754169689Skan bzero(key, sizeof(key)); 755169689Skan return; 756169689Skan } 757169689Skan /* 758169689Skan * If number of iterations has changed, but wasn't given as a 759169689Skan * command-line argument, update the request. 760169689Skan */ 761169689Skan if (val == -1 && md->md_iterations != old) { 762169689Skan error = gctl_change_param(req, "iterations", sizeof(intmax_t), 763169689Skan &md->md_iterations); 764169689Skan assert(error == 0); 765169689Skan } 766169689Skan 767169689Skan gctl_ro_param(req, "key", sizeof(key), key); 768169689Skan gctl_issue(req); 769169689Skan bzero(key, sizeof(key)); 770169689Skan} 771169689Skan 772169689Skanstatic void 773169689Skaneli_setkey_detached(struct gctl_req *req, const char *prov, 774169689Skan struct g_eli_metadata *md) 775169689Skan{ 776169689Skan unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 777169689Skan unsigned char *mkeydst; 778169689Skan intmax_t val; 779169689Skan unsigned nkey; 780169689Skan int error; 781169689Skan 782169689Skan if (md->md_keys == 0) { 783169689Skan gctl_error(req, "No valid keys on %s.", prov); 784169689Skan return; 785169689Skan } 786169689Skan 787169689Skan /* Generate key for Master Key decryption. */ 788169689Skan if (eli_genkey(req, md, key, 0) == NULL) { 789169689Skan bzero(key, sizeof(key)); 790169689Skan return; 791169689Skan } 792169689Skan 793169689Skan /* Decrypt Master Key. */ 794169689Skan error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 795169689Skan bzero(key, sizeof(key)); 796169689Skan if (error != 0) { 797169689Skan bzero(md, sizeof(*md)); 798169689Skan if (error == -1) 799169689Skan gctl_error(req, "Wrong key for %s.", prov); 800169689Skan else /* if (error > 0) */ { 801169689Skan gctl_error(req, "Cannot decrypt Master Key: %s.", 802169689Skan strerror(error)); 803169689Skan } 804169689Skan return; 805169689Skan } 806169689Skan if (verbose) 807169689Skan printf("Decrypted Master Key %u.\n", nkey); 808169689Skan 809169689Skan val = gctl_get_intmax(req, "keyno"); 810169689Skan if (val != -1) 811169689Skan nkey = val; 812169689Skan#if 0 813169689Skan else 814169689Skan ; /* Use the key number which was found during decryption. */ 815169689Skan#endif 816169689Skan if (nkey >= G_ELI_MAXMKEYS) { 817169689Skan gctl_error(req, "Invalid '%s' argument.", "keyno"); 818169689Skan return; 819169689Skan } 820169689Skan 821169689Skan val = gctl_get_intmax(req, "iterations"); 822169689Skan /* Check if iterations number should and can be changed. */ 823169689Skan if (val != -1) { 824169689Skan if (bitcount32(md->md_keys) != 1) { 825169689Skan gctl_error(req, "To be able to use '-i' option, only " 826169689Skan "one key can be defined."); 827169689Skan return; 828169689Skan } 829169689Skan if (md->md_keys != (1 << nkey)) { 830169689Skan gctl_error(req, "Only already defined key can be " 831169689Skan "changed when '-i' option is used."); 832169689Skan return; 833169689Skan } 834169689Skan md->md_iterations = val; 835169689Skan } 836169689Skan 837169689Skan mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 838169689Skan md->md_keys |= (1 << nkey); 839169689Skan 840169689Skan bcopy(mkey, mkeydst, sizeof(mkey)); 841169689Skan bzero(mkey, sizeof(mkey)); 842169689Skan 843169689Skan /* Generate key for Master Key encryption. */ 844169689Skan if (eli_genkey(req, md, key, 1) == NULL) { 845169689Skan bzero(key, sizeof(key)); 846169689Skan bzero(md, sizeof(*md)); 847169689Skan return; 848169689Skan } 849169689Skan 850169689Skan /* Encrypt the Master-Key with the new key. */ 851169689Skan error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 852169689Skan bzero(key, sizeof(key)); 853169689Skan if (error != 0) { 854169689Skan bzero(md, sizeof(*md)); 855169689Skan gctl_error(req, "Cannot encrypt Master Key: %s.", 856169689Skan strerror(error)); 857169689Skan return; 858169689Skan } 859169689Skan 860169689Skan /* Store metadata with fresh key. */ 861169689Skan eli_metadata_store(req, prov, md); 862169689Skan bzero(md, sizeof(*md)); 863169689Skan} 864169689Skan 865169689Skanstatic void 866169689Skaneli_setkey(struct gctl_req *req) 867169689Skan{ 868169689Skan struct g_eli_metadata md; 869169689Skan const char *prov; 870169689Skan int nargs; 871169689Skan 872169689Skan nargs = gctl_get_int(req, "nargs"); 873169689Skan if (nargs != 1) { 874169689Skan gctl_error(req, "Invalid number of arguments."); 875169689Skan return; 876169689Skan } 877169689Skan prov = gctl_get_ascii(req, "arg0"); 878169689Skan 879169689Skan if (eli_metadata_read(req, prov, &md) == -1) 880169689Skan return; 881169689Skan 882169689Skan if (eli_is_attached(prov)) 883169689Skan eli_setkey_attached(req, &md); 884169689Skan else 885169689Skan eli_setkey_detached(req, prov, &md); 886169689Skan} 887169689Skan 888169689Skanstatic void 889169689Skaneli_delkey_attached(struct gctl_req *req, const char *prov __unused) 890169689Skan{ 891169689Skan 892169689Skan gctl_issue(req); 893169689Skan} 894169689Skan 895169689Skanstatic void 896169689Skaneli_delkey_detached(struct gctl_req *req, const char *prov) 897169689Skan{ 898169689Skan struct g_eli_metadata md; 899169689Skan unsigned char *mkeydst; 900169689Skan intmax_t val; 901169689Skan unsigned nkey; 902169689Skan int all, force; 903169689Skan 904169689Skan if (eli_metadata_read(req, prov, &md) == -1) 905169689Skan return; 906169689Skan 907169689Skan all = gctl_get_int(req, "all"); 908169689Skan if (all) 909169689Skan arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 910169689Skan else { 911169689Skan force = gctl_get_int(req, "force"); 912169689Skan val = gctl_get_intmax(req, "keyno"); 913169689Skan if (val == -1) { 914169689Skan gctl_error(req, "Key number has to be specified."); 915169689Skan return; 916169689Skan } 917169689Skan nkey = val; 918169689Skan if (nkey >= G_ELI_MAXMKEYS) { 919169689Skan gctl_error(req, "Invalid '%s' argument.", "keyno"); 920169689Skan return; 921169689Skan } 922169689Skan if (!(md.md_keys & (1 << nkey)) && !force) { 923169689Skan gctl_error(req, "Master Key %u is not set.", nkey); 924169689Skan return; 925169689Skan } 926169689Skan md.md_keys &= ~(1 << nkey); 927169689Skan if (md.md_keys == 0 && !force) { 928169689Skan gctl_error(req, "This is the last Master Key. Use '-f' " 929169689Skan "option if you really want to remove it."); 930169689Skan return; 931169689Skan } 932169689Skan mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 933169689Skan arc4rand(mkeydst, G_ELI_MKEYLEN); 934169689Skan } 935169689Skan 936169689Skan eli_metadata_store(req, prov, &md); 937169689Skan bzero(&md, sizeof(md)); 938169689Skan} 939169689Skan 940169689Skanstatic void 941169689Skaneli_delkey(struct gctl_req *req) 942169689Skan{ 943169689Skan const char *prov; 944169689Skan int nargs; 945169689Skan 946169689Skan nargs = gctl_get_int(req, "nargs"); 947169689Skan if (nargs != 1) { 948169689Skan gctl_error(req, "Invalid number of arguments."); 949169689Skan return; 950169689Skan } 951169689Skan prov = gctl_get_ascii(req, "arg0"); 952169689Skan 953169689Skan if (eli_is_attached(prov)) 954169689Skan eli_delkey_attached(req, prov); 955169689Skan else 956169689Skan eli_delkey_detached(req, prov); 957169689Skan} 958169689Skan 959169689Skanstatic void 960169689Skaneli_kill_detached(struct gctl_req *req, const char *prov) 961169689Skan{ 962169689Skan struct g_eli_metadata md; 963169689Skan int error; 964169689Skan 965169689Skan /* 966169689Skan * NOTE: Maybe we should verify if this is geli provider first, 967169689Skan * but 'kill' command is quite critical so better don't waste 968169689Skan * the time. 969169689Skan */ 970169689Skan#if 0 971169689Skan error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 972169689Skan G_ELI_MAGIC); 973169689Skan if (error != 0) { 974169689Skan gctl_error(req, "Cannot read metadata from %s: %s.", prov, 975169689Skan strerror(error)); 976169689Skan return; 977169689Skan } 978169689Skan#endif 979169689Skan 980169689Skan arc4rand((unsigned char *)&md, sizeof(md)); 981169689Skan error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 982169689Skan if (error != 0) { 983169689Skan gctl_error(req, "Cannot write metadata to %s: %s.", prov, 984169689Skan strerror(error)); 985169689Skan } 986169689Skan} 987169689Skan 988169689Skanstatic void 989169689Skaneli_kill(struct gctl_req *req) 990169689Skan{ 991169689Skan const char *prov; 992169689Skan int i, nargs, all; 993169689Skan 994169689Skan nargs = gctl_get_int(req, "nargs"); 995169689Skan all = gctl_get_int(req, "all"); 996169689Skan if (!all && nargs == 0) { 997169689Skan gctl_error(req, "Too few arguments."); 998169689Skan return; 999169689Skan } 1000169689Skan /* 1001169689Skan * How '-a' option combine with a list of providers: 1002169689Skan * Delete Master Keys from all attached providers: 1003169689Skan * geli kill -a 1004169689Skan * Delete Master Keys from all attached provider and from 1005169689Skan * detached da0 and da1: 1006169689Skan * geli kill -a da0 da1 1007169689Skan * Delete Master Keys from (attached or detached) da0 and da1: 1008169689Skan * geli kill da0 da1 1009169689Skan */ 1010169689Skan 1011169689Skan /* First detached provider. */ 1012169689Skan for (i = 0; i < nargs; i++) { 1013169689Skan prov = gctl_get_ascii(req, "arg%d", i); 1014169689Skan if (!eli_is_attached(prov)) 1015169689Skan eli_kill_detached(req, prov); 1016169689Skan } 1017169689Skan /* Now attached providers. */ 1018169689Skan gctl_issue(req); 1019169689Skan} 1020169689Skan 1021169689Skanstatic void 1022169689Skaneli_backup(struct gctl_req *req) 1023169689Skan{ 1024169689Skan struct g_eli_metadata md; 1025169689Skan const char *file, *prov; 1026169689Skan unsigned secsize; 1027169689Skan unsigned char *sector; 1028169689Skan off_t mediasize; 1029169689Skan int nargs, filefd, provfd; 1030169689Skan 1031169689Skan nargs = gctl_get_int(req, "nargs"); 1032169689Skan if (nargs != 2) { 1033169689Skan gctl_error(req, "Invalid number of arguments."); 1034169689Skan return; 1035169689Skan } 1036169689Skan prov = gctl_get_ascii(req, "arg0"); 1037169689Skan file = gctl_get_ascii(req, "arg1"); 1038169689Skan 1039169689Skan provfd = filefd = -1; 1040169689Skan sector = NULL; 1041169689Skan secsize = 0; 1042169689Skan 1043169689Skan provfd = open(prov, O_RDONLY); 1044169689Skan if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1045169689Skan char devprov[MAXPATHLEN]; 1046169689Skan 1047169689Skan snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1048169689Skan provfd = open(devprov, O_RDONLY); 1049169689Skan } 1050169689Skan if (provfd == -1) { 1051169689Skan gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1052169689Skan return; 1053169689Skan } 1054169689Skan filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1055169689Skan if (filefd == -1) { 1056169689Skan gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1057169689Skan goto out; 1058169689Skan } 1059169689Skan 1060169689Skan mediasize = g_get_mediasize(prov); 1061169689Skan secsize = g_get_sectorsize(prov); 1062169689Skan if (mediasize == 0 || secsize == 0) { 1063169689Skan gctl_error(req, "Cannot get informations about %s: %s.", prov, 1064169689Skan strerror(errno)); 1065169689Skan return; 1066169689Skan } 1067169689Skan 1068169689Skan sector = malloc(secsize); 1069169689Skan if (sector == NULL) { 1070169689Skan gctl_error(req, "Cannot allocate memory."); 1071169689Skan return; 1072169689Skan } 1073169689Skan 1074169689Skan /* Read metadata from the provider. */ 1075169689Skan if (pread(provfd, sector, secsize, mediasize - secsize) != 1076169689Skan (ssize_t)secsize) { 1077169689Skan gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 1078169689Skan goto out; 1079169689Skan } 1080169689Skan /* Check if this is geli provider. */ 1081169689Skan if (eli_metadata_decode(sector, &md) != 0) { 1082169689Skan gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 1083169689Skan goto out; 1084169689Skan } 1085169689Skan /* Write metadata to the destination file. */ 1086169689Skan if (write(filefd, sector, secsize) != (ssize_t)secsize) { 1087169689Skan gctl_error(req, "Cannot write to %s: %s.", file, 1088169689Skan strerror(errno)); 1089169689Skan goto out; 1090169689Skan } 1091169689Skanout: 1092169689Skan if (provfd > 0) 1093169689Skan close(provfd); 1094169689Skan if (filefd > 0) 1095169689Skan close(filefd); 1096169689Skan if (sector != NULL) { 1097169689Skan bzero(sector, secsize); 1098169689Skan free(sector); 1099169689Skan } 1100169689Skan} 1101169689Skan 1102169689Skanstatic void 1103169689Skaneli_restore(struct gctl_req *req) 1104169689Skan{ 1105169689Skan struct g_eli_metadata md; 1106169689Skan const char *file, *prov; 1107169689Skan unsigned char *sector; 1108169689Skan unsigned secsize; 1109169689Skan off_t mediasize; 1110169689Skan int nargs, filefd, provfd; 1111169689Skan 1112169689Skan nargs = gctl_get_int(req, "nargs"); 1113169689Skan if (nargs != 2) { 1114169689Skan gctl_error(req, "Invalid number of arguments."); 1115169689Skan return; 1116169689Skan } 1117169689Skan file = gctl_get_ascii(req, "arg0"); 1118169689Skan prov = gctl_get_ascii(req, "arg1"); 1119169689Skan 1120169689Skan provfd = filefd = -1; 1121169689Skan sector = NULL; 1122169689Skan secsize = 0; 1123169689Skan 1124169689Skan filefd = open(file, O_RDONLY); 1125169689Skan if (filefd == -1) { 1126169689Skan gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1127169689Skan goto out; 1128169689Skan } 1129169689Skan provfd = open(prov, O_WRONLY); 1130169689Skan if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1131169689Skan char devprov[MAXPATHLEN]; 1132169689Skan 1133169689Skan snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1134169689Skan provfd = open(devprov, O_WRONLY); 1135169689Skan } 1136169689Skan if (provfd == -1) { 1137169689Skan gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1138169689Skan return; 1139169689Skan } 1140169689Skan 1141169689Skan mediasize = g_get_mediasize(prov); 1142169689Skan secsize = g_get_sectorsize(prov); 1143169689Skan if (mediasize == 0 || secsize == 0) { 1144169689Skan gctl_error(req, "Cannot get informations about %s: %s.", prov, 1145169689Skan strerror(errno)); 1146169689Skan return; 1147169689Skan } 1148169689Skan 1149169689Skan sector = malloc(secsize); 1150169689Skan if (sector == NULL) { 1151169689Skan gctl_error(req, "Cannot allocate memory."); 1152169689Skan return; 1153169689Skan } 1154169689Skan 1155169689Skan /* Read metadata from the backup file. */ 1156169689Skan if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1157169689Skan gctl_error(req, "Cannot read from %s: %s.", file, 1158169689Skan strerror(errno)); 1159169689Skan goto out; 1160169689Skan } 1161169689Skan /* Check if this file contains geli metadata. */ 1162169689Skan if (eli_metadata_decode(sector, &md) != 0) { 1163169689Skan gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1164169689Skan goto out; 1165169689Skan } 1166169689Skan /* Write metadata from the provider. */ 1167169689Skan if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1168169689Skan (ssize_t)secsize) { 1169169689Skan gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1170169689Skan goto out; 1171169689Skan } 1172169689Skanout: 1173169689Skan if (provfd > 0) 1174169689Skan close(provfd); 1175169689Skan if (filefd > 0) 1176169689Skan close(filefd); 1177169689Skan if (sector != NULL) { 1178169689Skan bzero(sector, secsize); 1179169689Skan free(sector); 1180169689Skan } 1181169689Skan} 1182169689Skan 1183169689Skanstatic void 1184169689Skaneli_clear(struct gctl_req *req) 1185169689Skan{ 1186169689Skan const char *name; 1187169689Skan int error, i, nargs; 1188169689Skan 1189169689Skan nargs = gctl_get_int(req, "nargs"); 1190169689Skan if (nargs < 1) { 1191169689Skan gctl_error(req, "Too few arguments."); 1192169689Skan return; 1193169689Skan } 1194169689Skan 1195169689Skan for (i = 0; i < nargs; i++) { 1196169689Skan name = gctl_get_ascii(req, "arg%d", i); 1197169689Skan error = g_metadata_clear(name, G_ELI_MAGIC); 1198169689Skan if (error != 0) { 1199169689Skan fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1200169689Skan name, strerror(error)); 1201169689Skan gctl_error(req, "Not fully done."); 1202169689Skan continue; 1203169689Skan } 1204169689Skan if (verbose) 1205169689Skan printf("Metadata cleared on %s.\n", name); 1206169689Skan } 1207169689Skan} 1208169689Skan 1209169689Skanstatic void 1210169689Skaneli_dump(struct gctl_req *req) 1211169689Skan{ 1212169689Skan struct g_eli_metadata md, tmpmd; 1213169689Skan const char *name; 1214169689Skan int error, i, nargs; 1215169689Skan 1216169689Skan nargs = gctl_get_int(req, "nargs"); 1217169689Skan if (nargs < 1) { 1218169689Skan gctl_error(req, "Too few arguments."); 1219169689Skan return; 1220169689Skan } 1221169689Skan 1222169689Skan for (i = 0; i < nargs; i++) { 1223169689Skan name = gctl_get_ascii(req, "arg%d", i); 1224169689Skan error = g_metadata_read(name, (unsigned char *)&tmpmd, 1225169689Skan sizeof(tmpmd), G_ELI_MAGIC); 1226169689Skan if (error != 0) { 1227169689Skan fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1228169689Skan name, strerror(error)); 1229169689Skan gctl_error(req, "Not fully done."); 1230169689Skan continue; 1231169689Skan } 1232169689Skan if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1233169689Skan fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1234169689Skan name); 1235169689Skan gctl_error(req, "Not fully done."); 1236169689Skan continue; 1237169689Skan } 1238169689Skan printf("Metadata on %s:\n", name); 1239169689Skan eli_metadata_dump(&md); 1240169689Skan printf("\n"); 1241169689Skan } 1242169689Skan} 1243169689Skan