geom_eli.c revision 155536
1148456Spjd/*- 2148456Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3148456Spjd * All rights reserved. 4148456Spjd * 5148456Spjd * Redistribution and use in source and binary forms, with or without 6148456Spjd * modification, are permitted provided that the following conditions 7148456Spjd * are met: 8148456Spjd * 1. Redistributions of source code must retain the above copyright 9148456Spjd * notice, this list of conditions and the following disclaimer. 10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright 11148456Spjd * notice, this list of conditions and the following disclaimer in the 12148456Spjd * documentation and/or other materials provided with the distribution. 13155175Spjd * 14148456Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17148456Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24148456Spjd * SUCH DAMAGE. 25148456Spjd */ 26148456Spjd 27148456Spjd#include <sys/cdefs.h> 28148456Spjd__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 155536 2006-02-11 13:04:10Z pjd $"); 29148456Spjd 30148456Spjd#include <stdio.h> 31148456Spjd#include <stdint.h> 32148456Spjd#include <stdlib.h> 33148456Spjd#include <unistd.h> 34148456Spjd#include <fcntl.h> 35148456Spjd#include <readpassphrase.h> 36148456Spjd#include <string.h> 37148456Spjd#include <strings.h> 38148456Spjd#include <libgeom.h> 39148456Spjd#include <paths.h> 40148456Spjd#include <errno.h> 41148456Spjd#include <assert.h> 42148456Spjd 43148456Spjd#include <sys/param.h> 44148456Spjd#include <sys/mman.h> 45148456Spjd#include <sys/resource.h> 46148456Spjd#include <opencrypto/cryptodev.h> 47148456Spjd#include <geom/eli/g_eli.h> 48148456Spjd#include <geom/eli/pkcs5v2.h> 49148456Spjd 50148456Spjd#include "core/geom.h" 51148456Spjd#include "misc/subr.h" 52148456Spjd 53148456Spjd 54148456Spjduint32_t lib_version = G_LIB_VERSION; 55148456Spjduint32_t version = G_ELI_VERSION; 56148456Spjd 57148456Spjdstatic char algo[] = "aes"; 58148456Spjdstatic intmax_t keylen = 0; 59148456Spjdstatic intmax_t keyno = -1; 60148456Spjdstatic intmax_t iterations = -1; 61148456Spjdstatic intmax_t sectorsize = 0; 62148456Spjdstatic char keyfile[] = "", newkeyfile[] = ""; 63148456Spjd 64148456Spjdstatic void eli_main(struct gctl_req *req, unsigned flags); 65148456Spjdstatic void eli_init(struct gctl_req *req); 66148456Spjdstatic void eli_attach(struct gctl_req *req); 67148456Spjdstatic void eli_setkey(struct gctl_req *req); 68148456Spjdstatic void eli_delkey(struct gctl_req *req); 69148456Spjdstatic void eli_kill(struct gctl_req *req); 70148456Spjdstatic void eli_backup(struct gctl_req *req); 71148456Spjdstatic void eli_restore(struct gctl_req *req); 72148456Spjdstatic void eli_clear(struct gctl_req *req); 73148456Spjdstatic void eli_dump(struct gctl_req *req); 74148456Spjd 75148456Spjd/* 76148456Spjd * Available commands: 77148456Spjd * 78148456Spjd * init [-bhPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] prov 79148456Spjd * label - alias for 'init' 80148456Spjd * attach [-dpv] [-k keyfile] prov 81148456Spjd * detach [-fl] prov ... 82148456Spjd * stop - alias for 'detach' 83148456Spjd * onetime [-d] [-a algo] [-l keylen] prov ... 84148456Spjd * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov 85148456Spjd * delkey [-afv] [-n keyno] prov 86148456Spjd * kill [-av] [prov ...] 87148456Spjd * backup [-v] prov file 88148456Spjd * restore [-v] file prov 89148456Spjd * clear [-v] prov ... 90148456Spjd * dump [-v] prov ... 91148456Spjd */ 92148456Spjdstruct g_command class_commands[] = { 93148456Spjd { "init", G_FLAG_VERBOSE, eli_main, 94148456Spjd { 95148456Spjd { 'a', "algo", algo, G_TYPE_STRING }, 96148456Spjd { 'b', "boot", NULL, G_TYPE_NONE }, 97148456Spjd { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 98148456Spjd { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 99148456Spjd { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 100148456Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 101148456Spjd { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 102148456Spjd G_OPT_SENTINEL 103148456Spjd }, 104148456Spjd "[-bPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" 105148456Spjd }, 106148456Spjd { "label", G_FLAG_VERBOSE, eli_main, 107148456Spjd { 108148456Spjd { 'a', "algo", algo, G_TYPE_STRING }, 109148456Spjd { 'b', "boot", NULL, G_TYPE_NONE }, 110148456Spjd { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 111148456Spjd { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 112148456Spjd { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 113148456Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 114148456Spjd { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 115148456Spjd G_OPT_SENTINEL 116148456Spjd }, 117148456Spjd "- an alias for 'init'" 118148456Spjd }, 119148456Spjd { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 120148456Spjd { 121148456Spjd { 'd', "detach", NULL, G_TYPE_NONE }, 122148456Spjd { 'k', "keyfile", keyfile, G_TYPE_STRING }, 123148456Spjd { 'p', "nopassphrase", NULL, G_TYPE_NONE }, 124148456Spjd G_OPT_SENTINEL 125148456Spjd }, 126148456Spjd "[-dpv] [-k keyfile] prov" 127148456Spjd }, 128148456Spjd { "detach", 0, NULL, 129148456Spjd { 130148456Spjd { 'f', "force", NULL, G_TYPE_NONE }, 131148456Spjd { 'l', "last", NULL, G_TYPE_NONE }, 132148456Spjd G_OPT_SENTINEL 133148456Spjd }, 134148456Spjd "[-fl] prov ..." 135148456Spjd }, 136148456Spjd { "stop", 0, NULL, 137148456Spjd { 138148456Spjd { 'f', "force", NULL, G_TYPE_NONE }, 139148456Spjd { 'l', "last", NULL, G_TYPE_NONE }, 140148456Spjd G_OPT_SENTINEL 141148456Spjd }, 142148456Spjd "- an alias for 'detach'" 143148456Spjd }, 144148456Spjd { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 145148456Spjd { 146148456Spjd { 'a', "algo", algo, G_TYPE_STRING }, 147148456Spjd { 'd', "detach", NULL, G_TYPE_NONE }, 148148456Spjd { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 149148456Spjd { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 150148456Spjd G_OPT_SENTINEL 151148456Spjd }, 152148456Spjd "[-d] [-a algo] [-l keylen] [-s sectorsize] prov ..." 153148456Spjd }, 154148456Spjd { "setkey", G_FLAG_VERBOSE, eli_main, 155148456Spjd { 156149304Spjd { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 157148456Spjd { 'k', "keyfile", keyfile, G_TYPE_STRING }, 158148456Spjd { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 159148456Spjd { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 160148456Spjd { 'p', "nopassphrase", NULL, G_TYPE_NONE }, 161148456Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 162148456Spjd G_OPT_SENTINEL 163148456Spjd }, 164149304Spjd "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" 165148456Spjd }, 166148456Spjd { "delkey", G_FLAG_VERBOSE, eli_main, 167148456Spjd { 168148456Spjd { 'a', "all", NULL, G_TYPE_NONE }, 169148456Spjd { 'f', "force", NULL, G_TYPE_NONE }, 170148456Spjd { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 171148456Spjd G_OPT_SENTINEL 172148456Spjd }, 173148456Spjd "[-afv] [-n keyno] prov" 174148456Spjd }, 175148456Spjd { "kill", G_FLAG_VERBOSE, eli_main, 176148456Spjd { 177148456Spjd { 'a', "all", NULL, G_TYPE_NONE }, 178148456Spjd G_OPT_SENTINEL 179148456Spjd }, 180148456Spjd "[-av] [prov ...]" 181148456Spjd }, 182148456Spjd { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 183148456Spjd "[-v] prov file" 184148456Spjd }, 185148456Spjd { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 186148456Spjd "[-v] file prov" 187148456Spjd }, 188148456Spjd { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 189148456Spjd "[-v] prov ..." 190148456Spjd }, 191148456Spjd { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 192148456Spjd "[-v] prov ..." 193148456Spjd }, 194148456Spjd G_CMD_SENTINEL 195148456Spjd}; 196148456Spjd 197148456Spjdstatic int verbose = 0; 198148456Spjd 199148456Spjdstatic int 200148456Spjdeli_protect(struct gctl_req *req) 201148456Spjd{ 202148456Spjd struct rlimit rl; 203148456Spjd 204148456Spjd /* Disable core dumps. */ 205148456Spjd rl.rlim_cur = 0; 206148456Spjd rl.rlim_max = 0; 207148456Spjd if (setrlimit(RLIMIT_CORE, &rl) == -1) { 208148456Spjd gctl_error(req, "Cannot disable core dumps: %s.", 209148456Spjd strerror(errno)); 210148456Spjd return (-1); 211148456Spjd } 212148456Spjd /* Disable swapping. */ 213148456Spjd if (mlockall(MCL_FUTURE) == -1) { 214148456Spjd gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 215148456Spjd return (-1); 216148456Spjd } 217148456Spjd return (0); 218148456Spjd} 219148456Spjd 220148456Spjdstatic void 221148456Spjdeli_main(struct gctl_req *req, unsigned flags) 222148456Spjd{ 223148456Spjd const char *name; 224148456Spjd 225148456Spjd if (eli_protect(req) == -1) 226148456Spjd return; 227148456Spjd 228148456Spjd if ((flags & G_FLAG_VERBOSE) != 0) 229148456Spjd verbose = 1; 230148456Spjd 231153190Spjd name = gctl_get_ascii(req, "verb"); 232148456Spjd if (name == NULL) { 233148456Spjd gctl_error(req, "No '%s' argument.", "verb"); 234148456Spjd return; 235148456Spjd } 236148456Spjd if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 237148456Spjd eli_init(req); 238148456Spjd else if (strcmp(name, "attach") == 0) 239148456Spjd eli_attach(req); 240148456Spjd else if (strcmp(name, "setkey") == 0) 241148456Spjd eli_setkey(req); 242148456Spjd else if (strcmp(name, "delkey") == 0) 243148456Spjd eli_delkey(req); 244148456Spjd else if (strcmp(name, "kill") == 0) 245148456Spjd eli_kill(req); 246148456Spjd else if (strcmp(name, "backup") == 0) 247148456Spjd eli_backup(req); 248148456Spjd else if (strcmp(name, "restore") == 0) 249148456Spjd eli_restore(req); 250148456Spjd else if (strcmp(name, "dump") == 0) 251148456Spjd eli_dump(req); 252148456Spjd else if (strcmp(name, "clear") == 0) 253148456Spjd eli_clear(req); 254148456Spjd else 255148456Spjd gctl_error(req, "Unknown command: %s.", name); 256148456Spjd} 257148456Spjd 258148456Spjdstatic void 259148456Spjdarc4rand(unsigned char *buf, size_t size) 260148456Spjd{ 261148456Spjd uint32_t *buf4; 262148456Spjd size_t size4; 263148456Spjd unsigned i; 264148456Spjd 265148456Spjd buf4 = (uint32_t *)buf; 266148456Spjd size4 = size / 4; 267148456Spjd 268148456Spjd for (i = 0; i < size4; i++) 269148456Spjd buf4[i] = arc4random(); 270148456Spjd for (i *= 4; i < size; i++) 271148456Spjd buf[i] = arc4random() % 0xff; 272148456Spjd} 273148456Spjd 274148456Spjdstatic int 275148456Spjdeli_is_attached(const char *prov) 276148456Spjd{ 277148456Spjd char name[MAXPATHLEN]; 278148456Spjd unsigned secsize; 279148456Spjd 280148456Spjd /* 281148456Spjd * Not the best way to do it, but the easiest. 282148456Spjd * We try to open provider and check if it is a GEOM provider 283148456Spjd * by asking about its sectorsize. 284148456Spjd */ 285148456Spjd snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 286148456Spjd secsize = g_get_sectorsize(name); 287148456Spjd if (secsize > 0) 288148456Spjd return (1); 289148456Spjd return (0); 290148456Spjd} 291148456Spjd 292148456Spjdstatic unsigned char * 293148456Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 294148456Spjd int new) 295148456Spjd{ 296148456Spjd struct hmac_ctx ctx; 297148456Spjd const char *str; 298153190Spjd int error, nopassphrase; 299148456Spjd 300153190Spjd nopassphrase = 301153190Spjd gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 302148456Spjd 303148456Spjd g_eli_crypto_hmac_init(&ctx, NULL, 0); 304148456Spjd 305153190Spjd str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile"); 306155183Spjd if (str[0] == '\0' && nopassphrase) { 307155183Spjd gctl_error(req, "No key components given."); 308155183Spjd return (NULL); 309155183Spjd } else if (str[0] != '\0') { 310148456Spjd char buf[MAXPHYS]; 311148456Spjd ssize_t done; 312148456Spjd int fd; 313148456Spjd 314148456Spjd if (strcmp(str, "-") == 0) 315148456Spjd fd = STDIN_FILENO; 316148456Spjd else { 317148456Spjd fd = open(str, O_RDONLY); 318148456Spjd if (fd == -1) { 319148456Spjd gctl_error(req, "Cannot open keyfile %s: %s.", 320148456Spjd str, strerror(errno)); 321148456Spjd return (NULL); 322148456Spjd } 323148456Spjd } 324148456Spjd while ((done = read(fd, buf, sizeof(buf))) > 0) 325148456Spjd g_eli_crypto_hmac_update(&ctx, buf, done); 326148456Spjd error = errno; 327148456Spjd if (strcmp(str, "-") != 0) 328148456Spjd close(fd); 329148456Spjd bzero(buf, sizeof(buf)); 330148456Spjd if (done == -1) { 331148456Spjd gctl_error(req, "Cannot read keyfile %s: %s.", str, 332148456Spjd strerror(error)); 333148456Spjd return (NULL); 334148456Spjd } 335148456Spjd } 336148456Spjd 337153190Spjd if (!nopassphrase) { 338148456Spjd char buf1[BUFSIZ], buf2[BUFSIZ], *p; 339148456Spjd 340149047Spjd if (!new && md->md_iterations == -1) { 341149047Spjd gctl_error(req, "Missing -p flag."); 342149047Spjd return (NULL); 343149047Spjd } 344148456Spjd for (;;) { 345148456Spjd p = readpassphrase( 346148456Spjd new ? "Enter new passphrase:" : "Enter passphrase:", 347148456Spjd buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); 348148456Spjd if (p == NULL) { 349148456Spjd bzero(buf1, sizeof(buf1)); 350148456Spjd gctl_error(req, "Cannot read passphrase: %s.", 351148456Spjd strerror(errno)); 352148456Spjd return (NULL); 353148456Spjd } 354148456Spjd 355148456Spjd if (new) { 356148456Spjd p = readpassphrase("Reenter new passphrase: ", 357148456Spjd buf2, sizeof(buf2), 358148456Spjd RPP_ECHO_OFF | RPP_REQUIRE_TTY); 359148456Spjd if (p == NULL) { 360148456Spjd bzero(buf1, sizeof(buf1)); 361148456Spjd gctl_error(req, 362148456Spjd "Cannot read passphrase: %s.", 363148456Spjd strerror(errno)); 364148456Spjd return (NULL); 365148456Spjd } 366148456Spjd 367148456Spjd if (strcmp(buf1, buf2) != 0) { 368148456Spjd bzero(buf2, sizeof(buf2)); 369148456Spjd fprintf(stderr, "They didn't match.\n"); 370148456Spjd continue; 371148456Spjd } 372148456Spjd bzero(buf2, sizeof(buf2)); 373148456Spjd } 374148456Spjd break; 375148456Spjd } 376148456Spjd /* 377148456Spjd * Field md_iterations equal to -1 means "choose some sane 378148456Spjd * value for me". 379148456Spjd */ 380148456Spjd if (md->md_iterations == -1) { 381148456Spjd assert(new); 382148456Spjd if (verbose) 383148456Spjd printf("Calculating number of iterations...\n"); 384148456Spjd md->md_iterations = pkcs5v2_calculate(2000000); 385148456Spjd assert(md->md_iterations > 0); 386148456Spjd if (verbose) { 387148456Spjd printf("Done, using %d iterations.\n", 388148456Spjd md->md_iterations); 389148456Spjd } 390148456Spjd } 391148456Spjd /* 392148456Spjd * If md_iterations is equal to 0, user don't want PKCS5v2. 393148456Spjd */ 394148456Spjd if (md->md_iterations == 0) { 395148456Spjd g_eli_crypto_hmac_update(&ctx, md->md_salt, 396148456Spjd sizeof(md->md_salt)); 397148456Spjd g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1)); 398148456Spjd } else /* if (md->md_iterations > 0) */ { 399148456Spjd unsigned char dkey[G_ELI_USERKEYLEN]; 400148456Spjd 401148456Spjd pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 402148456Spjd sizeof(md->md_salt), buf1, md->md_iterations); 403148456Spjd g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 404148456Spjd bzero(dkey, sizeof(dkey)); 405148456Spjd } 406148456Spjd bzero(buf1, sizeof(buf1)); 407148456Spjd } 408148456Spjd g_eli_crypto_hmac_final(&ctx, key, 0); 409148456Spjd return (key); 410148456Spjd} 411148456Spjd 412148456Spjdstatic int 413148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov, 414148456Spjd struct g_eli_metadata *md) 415148456Spjd{ 416148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 417148456Spjd int error; 418148456Spjd 419148456Spjd if (g_get_sectorsize(prov) == 0) { 420148456Spjd int fd; 421148456Spjd 422148456Spjd /* This is a file probably. */ 423148456Spjd fd = open(prov, O_RDONLY); 424148456Spjd if (fd == -1) { 425148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 426148456Spjd strerror(errno)); 427148456Spjd return (-1); 428148456Spjd } 429148456Spjd if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 430148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 431148456Spjd prov, strerror(errno)); 432148456Spjd close(fd); 433148456Spjd return (-1); 434148456Spjd } 435148456Spjd close(fd); 436148456Spjd } else { 437148456Spjd /* This is a GEOM provider. */ 438148456Spjd error = g_metadata_read(prov, sector, sizeof(sector), 439148456Spjd G_ELI_MAGIC); 440148456Spjd if (error != 0) { 441148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 442148456Spjd prov, strerror(error)); 443148456Spjd return (-1); 444148456Spjd } 445148456Spjd } 446148456Spjd if (eli_metadata_decode(sector, md) != 0) { 447148456Spjd gctl_error(req, "MD5 hash mismatch for %s.", prov); 448148456Spjd return (-1); 449148456Spjd } 450148456Spjd return (0); 451148456Spjd} 452148456Spjd 453148456Spjdstatic int 454148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov, 455148456Spjd struct g_eli_metadata *md) 456148456Spjd{ 457148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 458148456Spjd int error; 459148456Spjd 460148456Spjd eli_metadata_encode(md, sector); 461148456Spjd if (g_get_sectorsize(prov) == 0) { 462148456Spjd int fd; 463148456Spjd 464148456Spjd /* This is a file probably. */ 465148456Spjd fd = open(prov, O_WRONLY | O_TRUNC); 466148456Spjd if (fd == -1) { 467148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 468148456Spjd strerror(errno)); 469148456Spjd bzero(sector, sizeof(sector)); 470148456Spjd return (-1); 471148456Spjd } 472148456Spjd if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 473148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 474148456Spjd prov, strerror(errno)); 475148456Spjd bzero(sector, sizeof(sector)); 476148456Spjd close(fd); 477148456Spjd return (-1); 478148456Spjd } 479148456Spjd close(fd); 480148456Spjd } else { 481148456Spjd /* This is a GEOM provider. */ 482148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 483148456Spjd if (error != 0) { 484148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 485148456Spjd prov, strerror(errno)); 486148456Spjd bzero(sector, sizeof(sector)); 487148456Spjd return (-1); 488148456Spjd } 489148456Spjd } 490148456Spjd bzero(sector, sizeof(sector)); 491148456Spjd return (0); 492148456Spjd} 493148456Spjd 494148456Spjdstatic void 495148456Spjdeli_init(struct gctl_req *req) 496148456Spjd{ 497148456Spjd struct g_eli_metadata md; 498148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 499148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 500148456Spjd const char *str, *prov; 501148456Spjd unsigned secsize; 502148456Spjd off_t mediasize; 503153190Spjd intmax_t val; 504155536Spjd int error, nargs; 505148456Spjd 506153190Spjd nargs = gctl_get_int(req, "nargs"); 507153190Spjd if (nargs != 1) { 508148456Spjd gctl_error(req, "Too few arguments."); 509148456Spjd return; 510148456Spjd } 511153190Spjd prov = gctl_get_ascii(req, "arg0"); 512148456Spjd mediasize = g_get_mediasize(prov); 513148456Spjd secsize = g_get_sectorsize(prov); 514148456Spjd if (mediasize == 0 || secsize == 0) { 515148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 516148456Spjd strerror(errno)); 517148456Spjd return; 518148456Spjd } 519148456Spjd 520148456Spjd bzero(&md, sizeof(md)); 521148456Spjd strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 522148456Spjd md.md_version = G_ELI_VERSION; 523148456Spjd md.md_flags = 0; 524155536Spjd if (gctl_get_int(req, "boot")) 525148456Spjd md.md_flags |= G_ELI_FLAG_BOOT; 526153190Spjd str = gctl_get_ascii(req, "algo"); 527148456Spjd md.md_algo = g_eli_str2algo(str); 528148456Spjd if (md.md_algo < CRYPTO_ALGORITHM_MIN || 529148456Spjd md.md_algo > CRYPTO_ALGORITHM_MAX) { 530148456Spjd gctl_error(req, "Invalid encryption algorithm."); 531148456Spjd return; 532148456Spjd } 533153190Spjd val = gctl_get_intmax(req, "keylen"); 534153190Spjd md.md_keylen = val; 535148456Spjd md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen); 536148456Spjd if (md.md_keylen == 0) { 537148456Spjd gctl_error(req, "Invalid key length."); 538148456Spjd return; 539148456Spjd } 540148456Spjd md.md_provsize = mediasize; 541148456Spjd 542153190Spjd val = gctl_get_intmax(req, "iterations"); 543155536Spjd if (val != -1) { 544155536Spjd int nonewpassphrase; 545155536Spjd 546155536Spjd /* 547155536Spjd * Don't allow to set iterations when there will be no 548155536Spjd * passphrase. 549155536Spjd */ 550155536Spjd nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 551155536Spjd if (nonewpassphrase) { 552155536Spjd gctl_error(req, 553155536Spjd "Options -i and -P are mutually exclusive."); 554155536Spjd return; 555155536Spjd } 556155536Spjd } 557153190Spjd md.md_iterations = val; 558148456Spjd 559153190Spjd val = gctl_get_intmax(req, "sectorsize"); 560153190Spjd if (val == 0) 561148456Spjd md.md_sectorsize = secsize; 562148456Spjd else { 563153190Spjd if (val < 0 || (val % secsize) != 0) { 564148456Spjd gctl_error(req, "Invalid sector size."); 565148456Spjd return; 566148456Spjd } 567153190Spjd md.md_sectorsize = val; 568148456Spjd } 569148456Spjd 570148456Spjd md.md_keys = 0x01; 571148456Spjd arc4rand(md.md_salt, sizeof(md.md_salt)); 572148456Spjd arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 573148456Spjd 574148456Spjd /* Generate user key. */ 575148456Spjd if (eli_genkey(req, &md, key, 1) == NULL) { 576148456Spjd bzero(key, sizeof(key)); 577148456Spjd bzero(&md, sizeof(md)); 578148456Spjd return; 579148456Spjd } 580148456Spjd 581148456Spjd /* Encrypt the first and the only Master Key. */ 582148456Spjd error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys); 583148456Spjd bzero(key, sizeof(key)); 584148456Spjd if (error != 0) { 585148456Spjd bzero(&md, sizeof(md)); 586148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 587148456Spjd strerror(error)); 588148456Spjd return; 589148456Spjd } 590148456Spjd 591148456Spjd eli_metadata_encode(&md, sector); 592148456Spjd bzero(&md, sizeof(md)); 593148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 594148456Spjd bzero(sector, sizeof(sector)); 595148456Spjd if (error != 0) { 596148456Spjd gctl_error(req, "Cannot store metadata on %s: %s.", prov, 597148456Spjd strerror(error)); 598148456Spjd return; 599148456Spjd } 600148456Spjd if (verbose) 601148456Spjd printf("Metadata value stored on %s.\n", prov); 602148456Spjd} 603148456Spjd 604148456Spjdstatic void 605148456Spjdeli_attach(struct gctl_req *req) 606148456Spjd{ 607148456Spjd struct g_eli_metadata md; 608148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 609148456Spjd const char *prov; 610153190Spjd int nargs; 611148456Spjd 612153190Spjd nargs = gctl_get_int(req, "nargs"); 613153190Spjd if (nargs != 1) { 614148456Spjd gctl_error(req, "Too few arguments."); 615148456Spjd return; 616148456Spjd } 617153190Spjd prov = gctl_get_ascii(req, "arg0"); 618148456Spjd 619148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 620148456Spjd return; 621148456Spjd 622148456Spjd if (eli_genkey(req, &md, key, 0) == NULL) { 623148456Spjd bzero(key, sizeof(key)); 624148456Spjd return; 625148456Spjd } 626148456Spjd 627148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 628148456Spjd if (gctl_issue(req) == NULL) { 629148456Spjd if (verbose) 630148456Spjd printf("Attched to %s.\n", prov); 631148456Spjd } 632148456Spjd bzero(key, sizeof(key)); 633148456Spjd} 634148456Spjd 635148456Spjdstatic void 636155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 637148456Spjd{ 638148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 639153190Spjd intmax_t val; 640148456Spjd 641153190Spjd val = gctl_get_intmax(req, "iterations"); 642149304Spjd /* Check if iterations number should be changed. */ 643153190Spjd if (val != -1) 644153190Spjd md->md_iterations = val; 645148456Spjd 646148456Spjd /* Generate key for Master Key encryption. */ 647149304Spjd if (eli_genkey(req, md, key, 1) == NULL) { 648148456Spjd bzero(key, sizeof(key)); 649148456Spjd return; 650148456Spjd } 651148456Spjd 652148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 653148456Spjd gctl_issue(req); 654148456Spjd bzero(key, sizeof(key)); 655148456Spjd} 656148456Spjd 657148456Spjdstatic void 658149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov, 659149304Spjd struct g_eli_metadata *md) 660148456Spjd{ 661148456Spjd unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 662148456Spjd unsigned char *mkeydst; 663153190Spjd intmax_t val; 664148456Spjd unsigned nkey; 665148456Spjd int error; 666148456Spjd 667149928Spjd if (md->md_keys == 0) { 668149928Spjd gctl_error(req, "No valid keys on %s.", prov); 669149928Spjd return; 670149928Spjd } 671149928Spjd 672148456Spjd /* Generate key for Master Key decryption. */ 673149304Spjd if (eli_genkey(req, md, key, 0) == NULL) { 674148456Spjd bzero(key, sizeof(key)); 675148456Spjd return; 676148456Spjd } 677148456Spjd 678148456Spjd /* Decrypt Master Key. */ 679149304Spjd error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 680148456Spjd bzero(key, sizeof(key)); 681148456Spjd if (error != 0) { 682149304Spjd bzero(md, sizeof(*md)); 683148456Spjd if (error == -1) 684148456Spjd gctl_error(req, "Wrong key for %s.", prov); 685148456Spjd else /* if (error > 0) */ { 686148456Spjd gctl_error(req, "Cannot decrypt Master Key: %s.", 687148456Spjd strerror(error)); 688148456Spjd } 689148456Spjd return; 690148456Spjd } 691148456Spjd if (verbose) 692148456Spjd printf("Decrypted Master Key %u.\n", nkey); 693148456Spjd 694153190Spjd val = gctl_get_intmax(req, "keyno"); 695153190Spjd if (val != -1) 696153190Spjd nkey = val; 697148456Spjd#if 0 698148456Spjd else 699148456Spjd ; /* Use the key number which was found during decryption. */ 700148456Spjd#endif 701148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 702148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 703148456Spjd return; 704148456Spjd } 705148456Spjd 706153190Spjd val = gctl_get_intmax(req, "iterations"); 707149304Spjd /* Check if iterations number should and can be changed. */ 708153190Spjd if (val != -1) { 709149304Spjd if (bitcount32(md->md_keys) != 1) { 710149304Spjd gctl_error(req, "To be able to use '-i' option, only " 711149304Spjd "one key can be defined."); 712149304Spjd return; 713149304Spjd } 714149304Spjd if (md->md_keys != (1 << nkey)) { 715149304Spjd gctl_error(req, "Only already defined key can be " 716149304Spjd "changed when '-i' option is used."); 717149304Spjd return; 718149304Spjd } 719153190Spjd md->md_iterations = val; 720149304Spjd } 721148456Spjd 722149304Spjd mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 723149304Spjd md->md_keys |= (1 << nkey); 724149304Spjd 725148456Spjd bcopy(mkey, mkeydst, sizeof(mkey)); 726148456Spjd bzero(mkey, sizeof(mkey)); 727148456Spjd 728148456Spjd /* Generate key for Master Key encryption. */ 729149304Spjd if (eli_genkey(req, md, key, 1) == NULL) { 730148456Spjd bzero(key, sizeof(key)); 731149304Spjd bzero(md, sizeof(*md)); 732148456Spjd return; 733148456Spjd } 734148456Spjd 735148456Spjd /* Encrypt the Master-Key with the new key. */ 736149304Spjd error = g_eli_mkey_encrypt(md->md_algo, key, md->md_keylen, mkeydst); 737148456Spjd bzero(key, sizeof(key)); 738148456Spjd if (error != 0) { 739149304Spjd bzero(md, sizeof(*md)); 740148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 741148456Spjd strerror(error)); 742148456Spjd return; 743148456Spjd } 744148456Spjd 745148456Spjd /* Store metadata with fresh key. */ 746149304Spjd eli_metadata_store(req, prov, md); 747149304Spjd bzero(md, sizeof(*md)); 748148456Spjd} 749148456Spjd 750148456Spjdstatic void 751148456Spjdeli_setkey(struct gctl_req *req) 752148456Spjd{ 753149304Spjd struct g_eli_metadata md; 754148456Spjd const char *prov; 755153190Spjd int nargs; 756148456Spjd 757153190Spjd nargs = gctl_get_int(req, "nargs"); 758153190Spjd if (nargs != 1) { 759148456Spjd gctl_error(req, "Too few arguments."); 760148456Spjd return; 761148456Spjd } 762153190Spjd prov = gctl_get_ascii(req, "arg0"); 763148456Spjd 764149304Spjd if (eli_metadata_read(req, prov, &md) == -1) 765149304Spjd return; 766149304Spjd 767148456Spjd if (eli_is_attached(prov)) 768155101Spjd eli_setkey_attached(req, &md); 769148456Spjd else 770149304Spjd eli_setkey_detached(req, prov, &md); 771148456Spjd} 772148456Spjd 773148456Spjdstatic void 774148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused) 775148456Spjd{ 776148456Spjd 777148456Spjd gctl_issue(req); 778148456Spjd} 779148456Spjd 780148456Spjdstatic void 781148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov) 782148456Spjd{ 783148456Spjd struct g_eli_metadata md; 784148456Spjd unsigned char *mkeydst; 785153190Spjd intmax_t val; 786148456Spjd unsigned nkey; 787153190Spjd int all, force; 788148456Spjd 789148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 790148456Spjd return; 791148456Spjd 792153190Spjd all = gctl_get_int(req, "all"); 793153190Spjd if (all) 794148456Spjd arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 795148456Spjd else { 796153190Spjd force = gctl_get_int(req, "force"); 797153190Spjd val = gctl_get_intmax(req, "keyno"); 798153190Spjd if (val == -1) { 799148456Spjd gctl_error(req, "Key number has to be specified."); 800148456Spjd return; 801148456Spjd } 802153190Spjd nkey = val; 803148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 804148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 805148456Spjd return; 806148456Spjd } 807153190Spjd if (!(md.md_keys & (1 << nkey)) && !force) { 808148456Spjd gctl_error(req, "Master Key %u is not set.", nkey); 809148456Spjd return; 810148456Spjd } 811148456Spjd md.md_keys &= ~(1 << nkey); 812153190Spjd if (md.md_keys == 0 && !force) { 813148456Spjd gctl_error(req, "This is the last Master Key. Use '-f' " 814148456Spjd "option if you really want to remove it."); 815148456Spjd return; 816148456Spjd } 817148456Spjd mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 818148456Spjd arc4rand(mkeydst, G_ELI_MKEYLEN); 819148456Spjd } 820148456Spjd 821148456Spjd eli_metadata_store(req, prov, &md); 822148456Spjd bzero(&md, sizeof(md)); 823148456Spjd} 824148456Spjd 825148456Spjdstatic void 826148456Spjdeli_delkey(struct gctl_req *req) 827148456Spjd{ 828148456Spjd const char *prov; 829153190Spjd int nargs; 830148456Spjd 831153190Spjd nargs = gctl_get_int(req, "nargs"); 832153190Spjd if (nargs != 1) { 833148456Spjd gctl_error(req, "Too few arguments."); 834148456Spjd return; 835148456Spjd } 836153190Spjd prov = gctl_get_ascii(req, "arg0"); 837148456Spjd 838148456Spjd if (eli_is_attached(prov)) 839148456Spjd eli_delkey_attached(req, prov); 840148456Spjd else 841148456Spjd eli_delkey_detached(req, prov); 842148456Spjd} 843148456Spjd 844148456Spjdstatic void 845148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov) 846148456Spjd{ 847148456Spjd struct g_eli_metadata md; 848148456Spjd int error; 849148456Spjd 850148456Spjd /* 851148456Spjd * NOTE: Maybe we should verify if this is geli provider first, 852148456Spjd * but 'kill' command is quite critical so better don't waste 853148456Spjd * the time. 854148456Spjd */ 855148456Spjd#if 0 856148456Spjd error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 857148456Spjd G_ELI_MAGIC); 858148456Spjd if (error != 0) { 859148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", prov, 860148456Spjd strerror(error)); 861148456Spjd return; 862148456Spjd } 863148456Spjd#endif 864148456Spjd 865148456Spjd arc4rand((unsigned char *)&md, sizeof(md)); 866148456Spjd error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 867148456Spjd if (error != 0) { 868148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", prov, 869148456Spjd strerror(error)); 870148456Spjd } 871148456Spjd} 872148456Spjd 873148456Spjdstatic void 874148456Spjdeli_kill(struct gctl_req *req) 875148456Spjd{ 876148456Spjd const char *prov; 877153190Spjd int i, nargs, all; 878148456Spjd 879153190Spjd nargs = gctl_get_int(req, "nargs"); 880153190Spjd all = gctl_get_int(req, "all"); 881153190Spjd if (!all && nargs == 0) { 882148456Spjd gctl_error(req, "Too few arguments."); 883148456Spjd return; 884148456Spjd } 885148456Spjd /* 886148456Spjd * How '-a' option combine with a list of providers: 887148456Spjd * Delete Master Keys from all attached providers: 888148456Spjd * geli kill -a 889148456Spjd * Delete Master Keys from all attached provider and from 890148456Spjd * detached da0 and da1: 891148456Spjd * geli kill -a da0 da1 892148456Spjd * Delete Master Keys from (attached or detached) da0 and da1: 893148456Spjd * geli kill da0 da1 894148456Spjd */ 895148456Spjd 896148456Spjd /* 897148456Spjd * First attached providers. 898148456Spjd */ 899148456Spjd gctl_issue(req); 900148456Spjd /* 901148456Spjd * Now the rest. 902148456Spjd */ 903153190Spjd for (i = 0; i < nargs; i++) { 904153190Spjd prov = gctl_get_ascii(req, "arg%d", i); 905148456Spjd if (!eli_is_attached(prov)) 906148456Spjd eli_kill_detached(req, prov); 907148456Spjd } 908148456Spjd} 909148456Spjd 910148456Spjdstatic void 911148456Spjdeli_backup(struct gctl_req *req) 912148456Spjd{ 913148456Spjd struct g_eli_metadata md; 914148456Spjd const char *file, *prov; 915148456Spjd unsigned secsize; 916148456Spjd unsigned char *sector; 917148456Spjd off_t mediasize; 918153190Spjd int nargs, filefd, provfd; 919148456Spjd 920153190Spjd nargs = gctl_get_int(req, "nargs"); 921153190Spjd if (nargs != 2) { 922148456Spjd gctl_error(req, "Invalid number of arguments."); 923148456Spjd return; 924148456Spjd } 925153190Spjd prov = gctl_get_ascii(req, "arg0"); 926153190Spjd file = gctl_get_ascii(req, "arg1"); 927148456Spjd 928148456Spjd provfd = filefd = -1; 929148456Spjd sector = NULL; 930148456Spjd secsize = 0; 931148456Spjd 932148456Spjd provfd = open(prov, O_RDONLY); 933148456Spjd if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 934148456Spjd char devprov[MAXPATHLEN]; 935148456Spjd 936148456Spjd snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 937148456Spjd provfd = open(devprov, O_RDONLY); 938148456Spjd } 939148456Spjd if (provfd == -1) { 940148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 941148456Spjd return; 942148456Spjd } 943148456Spjd filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 944148456Spjd if (filefd == -1) { 945148456Spjd gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 946148456Spjd goto out; 947148456Spjd } 948148456Spjd 949148456Spjd mediasize = g_get_mediasize(prov); 950148456Spjd secsize = g_get_sectorsize(prov); 951148456Spjd if (mediasize == 0 || secsize == 0) { 952148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 953148456Spjd strerror(errno)); 954148456Spjd return; 955148456Spjd } 956148456Spjd 957148456Spjd sector = malloc(secsize); 958148456Spjd if (sector == NULL) { 959148456Spjd gctl_error(req, "Cannot allocate memory."); 960148456Spjd return; 961148456Spjd } 962148456Spjd 963148456Spjd /* Read metadata from the provider. */ 964148456Spjd if (pread(provfd, sector, secsize, mediasize - secsize) != 965148456Spjd (ssize_t)secsize) { 966148456Spjd gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 967148456Spjd goto out; 968148456Spjd } 969148456Spjd /* Check if this is geli provider. */ 970148456Spjd if (eli_metadata_decode(sector, &md) != 0) { 971148456Spjd gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 972148456Spjd goto out; 973148456Spjd } 974148456Spjd /* Write metadata to the destination file. */ 975148456Spjd if (write(filefd, sector, secsize) != (ssize_t)secsize) { 976148456Spjd gctl_error(req, "Cannot write to %s: %s.", file, 977148456Spjd strerror(errno)); 978148456Spjd goto out; 979148456Spjd } 980148456Spjdout: 981148456Spjd if (provfd > 0) 982148456Spjd close(provfd); 983148456Spjd if (filefd > 0) 984148456Spjd close(filefd); 985148456Spjd if (sector != NULL) { 986148456Spjd bzero(sector, secsize); 987148456Spjd free(sector); 988148456Spjd } 989148456Spjd} 990148456Spjd 991148456Spjdstatic void 992148456Spjdeli_restore(struct gctl_req *req) 993148456Spjd{ 994148456Spjd struct g_eli_metadata md; 995148456Spjd const char *file, *prov; 996148456Spjd unsigned char *sector; 997148456Spjd unsigned secsize; 998148456Spjd off_t mediasize; 999153190Spjd int nargs, filefd, provfd; 1000148456Spjd 1001153190Spjd nargs = gctl_get_int(req, "nargs"); 1002153190Spjd if (nargs != 2) { 1003148456Spjd gctl_error(req, "Invalid number of arguments."); 1004148456Spjd return; 1005148456Spjd } 1006153190Spjd file = gctl_get_ascii(req, "arg0"); 1007153190Spjd prov = gctl_get_ascii(req, "arg1"); 1008148456Spjd 1009148456Spjd provfd = filefd = -1; 1010148456Spjd sector = NULL; 1011148456Spjd secsize = 0; 1012148456Spjd 1013148456Spjd filefd = open(file, O_RDONLY); 1014148456Spjd if (filefd == -1) { 1015148456Spjd gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1016148456Spjd goto out; 1017148456Spjd } 1018148456Spjd provfd = open(prov, O_WRONLY); 1019148456Spjd if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1020148456Spjd char devprov[MAXPATHLEN]; 1021148456Spjd 1022148456Spjd snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1023148456Spjd provfd = open(devprov, O_WRONLY); 1024148456Spjd } 1025148456Spjd if (provfd == -1) { 1026148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1027148456Spjd return; 1028148456Spjd } 1029148456Spjd 1030148456Spjd mediasize = g_get_mediasize(prov); 1031148456Spjd secsize = g_get_sectorsize(prov); 1032148456Spjd if (mediasize == 0 || secsize == 0) { 1033148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1034148456Spjd strerror(errno)); 1035148456Spjd return; 1036148456Spjd } 1037148456Spjd 1038148456Spjd sector = malloc(secsize); 1039148456Spjd if (sector == NULL) { 1040148456Spjd gctl_error(req, "Cannot allocate memory."); 1041148456Spjd return; 1042148456Spjd } 1043148456Spjd 1044148456Spjd /* Read metadata from the backup file. */ 1045148456Spjd if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1046148456Spjd gctl_error(req, "Cannot read from %s: %s.", file, 1047148456Spjd strerror(errno)); 1048148456Spjd goto out; 1049148456Spjd } 1050148456Spjd /* Check if this file contains geli metadata. */ 1051148456Spjd if (eli_metadata_decode(sector, &md) != 0) { 1052148456Spjd gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1053148456Spjd goto out; 1054148456Spjd } 1055148456Spjd /* Read metadata from the provider. */ 1056148456Spjd if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1057148456Spjd (ssize_t)secsize) { 1058148456Spjd gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1059148456Spjd goto out; 1060148456Spjd } 1061148456Spjdout: 1062148456Spjd if (provfd > 0) 1063148456Spjd close(provfd); 1064148456Spjd if (filefd > 0) 1065148456Spjd close(filefd); 1066148456Spjd if (sector != NULL) { 1067148456Spjd bzero(sector, secsize); 1068148456Spjd free(sector); 1069148456Spjd } 1070148456Spjd} 1071148456Spjd 1072148456Spjdstatic void 1073148456Spjdeli_clear(struct gctl_req *req) 1074148456Spjd{ 1075148456Spjd const char *name; 1076153190Spjd int error, i, nargs; 1077148456Spjd 1078153190Spjd nargs = gctl_get_int(req, "nargs"); 1079153190Spjd if (nargs < 1) { 1080148456Spjd gctl_error(req, "Too few arguments."); 1081148456Spjd return; 1082148456Spjd } 1083148456Spjd 1084153190Spjd for (i = 0; i < nargs; i++) { 1085153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1086148456Spjd error = g_metadata_clear(name, G_ELI_MAGIC); 1087148456Spjd if (error != 0) { 1088148456Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1089148456Spjd name, strerror(error)); 1090148456Spjd gctl_error(req, "Not fully done."); 1091148456Spjd continue; 1092148456Spjd } 1093148456Spjd if (verbose) 1094155175Spjd printf("Metadata cleared on %s.\n", name); 1095148456Spjd } 1096148456Spjd} 1097148456Spjd 1098148456Spjdstatic void 1099148456Spjdeli_dump(struct gctl_req *req) 1100148456Spjd{ 1101148456Spjd struct g_eli_metadata md, tmpmd; 1102148456Spjd const char *name; 1103153190Spjd int error, i, nargs; 1104148456Spjd 1105153190Spjd nargs = gctl_get_int(req, "nargs"); 1106153190Spjd if (nargs < 1) { 1107148456Spjd gctl_error(req, "Too few arguments."); 1108148456Spjd return; 1109148456Spjd } 1110148456Spjd 1111153190Spjd for (i = 0; i < nargs; i++) { 1112153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1113148456Spjd error = g_metadata_read(name, (unsigned char *)&tmpmd, 1114148456Spjd sizeof(tmpmd), G_ELI_MAGIC); 1115148456Spjd if (error != 0) { 1116148456Spjd fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1117148456Spjd name, strerror(error)); 1118148456Spjd gctl_error(req, "Not fully done."); 1119148456Spjd continue; 1120148456Spjd } 1121148456Spjd if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1122148456Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1123148456Spjd name); 1124148456Spjd gctl_error(req, "Not fully done."); 1125148456Spjd continue; 1126148456Spjd } 1127148456Spjd printf("Metadata on %s:\n", name); 1128148456Spjd eli_metadata_dump(&md); 1129148456Spjd printf("\n"); 1130148456Spjd } 1131148456Spjd} 1132