geom_eli.c revision 226716
1148456Spjd/*- 2213073Spjd * Copyright (c) 2004-2010 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 226716 2011-10-25 07:31:13Z pjd $"); 29148456Spjd 30226715Spjd#include <sys/param.h> 31226715Spjd#include <sys/mman.h> 32213060Spjd#include <sys/sysctl.h> 33226715Spjd#include <sys/resource.h> 34226715Spjd#include <opencrypto/cryptodev.h> 35213060Spjd 36226715Spjd#include <assert.h> 37226715Spjd#include <err.h> 38226715Spjd#include <errno.h> 39226715Spjd#include <fcntl.h> 40226715Spjd#include <libgeom.h> 41226715Spjd#include <paths.h> 42226715Spjd#include <readpassphrase.h> 43213172Spjd#include <stdbool.h> 44226715Spjd#include <stdint.h> 45148456Spjd#include <stdio.h> 46148456Spjd#include <stdlib.h> 47148456Spjd#include <string.h> 48148456Spjd#include <strings.h> 49226715Spjd#include <unistd.h> 50148456Spjd 51148456Spjd#include <geom/eli/g_eli.h> 52148456Spjd#include <geom/eli/pkcs5v2.h> 53148456Spjd 54148456Spjd#include "core/geom.h" 55148456Spjd#include "misc/subr.h" 56148456Spjd 57148456Spjd 58148456Spjduint32_t lib_version = G_LIB_VERSION; 59148456Spjduint32_t version = G_ELI_VERSION; 60148456Spjd 61182452Spjd#define GELI_BACKUP_DIR "/var/backups/" 62212547Spjd#define GELI_ENC_ALGO "aes" 63182452Spjd 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); 67162353Spjdstatic void eli_configure(struct gctl_req *req); 68148456Spjdstatic void eli_setkey(struct gctl_req *req); 69148456Spjdstatic void eli_delkey(struct gctl_req *req); 70214118Spjdstatic void eli_resume(struct gctl_req *req); 71148456Spjdstatic void eli_kill(struct gctl_req *req); 72148456Spjdstatic void eli_backup(struct gctl_req *req); 73148456Spjdstatic void eli_restore(struct gctl_req *req); 74212934Sbrianstatic void eli_resize(struct gctl_req *req); 75148456Spjdstatic void eli_clear(struct gctl_req *req); 76148456Spjdstatic void eli_dump(struct gctl_req *req); 77148456Spjd 78182452Spjdstatic int eli_backup_create(struct gctl_req *req, const char *prov, 79182452Spjd const char *file); 80182452Spjd 81148456Spjd/* 82148456Spjd * Available commands: 83148456Spjd * 84213172Spjd * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] prov 85148456Spjd * label - alias for 'init' 86213172Spjd * attach [-dprv] [-j passfile] [-k keyfile] prov 87148456Spjd * detach [-fl] prov ... 88148456Spjd * stop - alias for 'detach' 89181639Spjd * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov 90162353Spjd * configure [-bB] prov ... 91213172Spjd * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov 92148456Spjd * delkey [-afv] [-n keyno] prov 93214118Spjd * suspend [-v] -a | prov ... 94214118Spjd * resume [-pv] [-j passfile] [-k keyfile] prov 95148456Spjd * kill [-av] [prov ...] 96148456Spjd * backup [-v] prov file 97212934Sbrian * restore [-fv] file prov 98212934Sbrian * resize [-v] -s oldsize prov 99148456Spjd * clear [-v] prov ... 100148456Spjd * dump [-v] prov ... 101148456Spjd */ 102148456Spjdstruct g_command class_commands[] = { 103148456Spjd { "init", G_FLAG_VERBOSE, eli_main, 104148456Spjd { 105212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 106162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 107212547Spjd { 'B', "backupfile", "", G_TYPE_STRING }, 108212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 109212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 110213172Spjd { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 111213172Spjd { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 112212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 113162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 114212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 115148456Spjd G_OPT_SENTINEL 116148456Spjd }, 117213172Spjd "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] prov" 118148456Spjd }, 119148456Spjd { "label", G_FLAG_VERBOSE, eli_main, 120148456Spjd { 121212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 122162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 123212547Spjd { 'B', "backupfile", "", G_TYPE_STRING }, 124212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 125212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 126213172Spjd { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 127213172Spjd { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 128212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 129162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 130212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 131148456Spjd G_OPT_SENTINEL 132148456Spjd }, 133212554Spjd "- an alias for 'init'" 134148456Spjd }, 135148456Spjd { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 136148456Spjd { 137162868Spjd { 'd', "detach", NULL, G_TYPE_BOOL }, 138213172Spjd { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 139213172Spjd { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 140162868Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 141162868Spjd { 'r', "readonly", NULL, G_TYPE_BOOL }, 142148456Spjd G_OPT_SENTINEL 143148456Spjd }, 144213172Spjd "[-dprv] [-j passfile] [-k keyfile] prov" 145148456Spjd }, 146148456Spjd { "detach", 0, NULL, 147148456Spjd { 148162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 149162868Spjd { 'l', "last", NULL, G_TYPE_BOOL }, 150148456Spjd G_OPT_SENTINEL 151148456Spjd }, 152212554Spjd "[-fl] prov ..." 153148456Spjd }, 154148456Spjd { "stop", 0, NULL, 155148456Spjd { 156162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 157162868Spjd { 'l', "last", NULL, G_TYPE_BOOL }, 158148456Spjd G_OPT_SENTINEL 159148456Spjd }, 160212554Spjd "- an alias for 'detach'" 161148456Spjd }, 162148456Spjd { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 163148456Spjd { 164212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 165162868Spjd { 'd', "detach", NULL, G_TYPE_BOOL }, 166212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 167212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 168212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 169148456Spjd G_OPT_SENTINEL 170148456Spjd }, 171212554Spjd "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov" 172148456Spjd }, 173162353Spjd { "configure", G_FLAG_VERBOSE, eli_main, 174162353Spjd { 175162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 176162868Spjd { 'B', "noboot", NULL, G_TYPE_BOOL }, 177162353Spjd G_OPT_SENTINEL 178162353Spjd }, 179212554Spjd "[-bB] prov ..." 180162353Spjd }, 181148456Spjd { "setkey", G_FLAG_VERBOSE, eli_main, 182148456Spjd { 183212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 184213172Spjd { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 185213172Spjd { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 186213172Spjd { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 187213172Spjd { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 188212554Spjd { 'n', "keyno", "-1", G_TYPE_NUMBER }, 189162868Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 190162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 191148456Spjd G_OPT_SENTINEL 192148456Spjd }, 193213172Spjd "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov" 194148456Spjd }, 195148456Spjd { "delkey", G_FLAG_VERBOSE, eli_main, 196148456Spjd { 197162868Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 198162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 199212554Spjd { 'n', "keyno", "-1", G_TYPE_NUMBER }, 200148456Spjd G_OPT_SENTINEL 201148456Spjd }, 202212554Spjd "[-afv] [-n keyno] prov" 203148456Spjd }, 204214118Spjd { "suspend", G_FLAG_VERBOSE, NULL, 205214118Spjd { 206214118Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 207214118Spjd G_OPT_SENTINEL 208214118Spjd }, 209214118Spjd "[-v] -a | prov ..." 210214118Spjd }, 211214118Spjd { "resume", G_FLAG_VERBOSE, eli_main, 212214118Spjd { 213214118Spjd { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 214214118Spjd { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 215214118Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 216214118Spjd G_OPT_SENTINEL 217214118Spjd }, 218214118Spjd "[-pv] [-j passfile] [-k keyfile] prov" 219214118Spjd }, 220148456Spjd { "kill", G_FLAG_VERBOSE, eli_main, 221148456Spjd { 222162868Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 223148456Spjd G_OPT_SENTINEL 224148456Spjd }, 225212554Spjd "[-av] [prov ...]" 226148456Spjd }, 227212554Spjd { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 228148456Spjd "[-v] prov file" 229148456Spjd }, 230212934Sbrian { "restore", G_FLAG_VERBOSE, eli_main, 231212934Sbrian { 232212934Sbrian { 'f', "force", NULL, G_TYPE_BOOL }, 233212934Sbrian G_OPT_SENTINEL 234212934Sbrian }, 235212934Sbrian "[-fv] file prov" 236148456Spjd }, 237212934Sbrian { "resize", G_FLAG_VERBOSE, eli_main, 238212934Sbrian { 239212934Sbrian { 's', "oldsize", NULL, G_TYPE_NUMBER }, 240212934Sbrian G_OPT_SENTINEL 241212934Sbrian }, 242212934Sbrian "[-v] -s oldsize prov" 243212934Sbrian }, 244212554Spjd { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 245148456Spjd "[-v] prov ..." 246148456Spjd }, 247212554Spjd { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 248148456Spjd "[-v] prov ..." 249148456Spjd }, 250148456Spjd G_CMD_SENTINEL 251148456Spjd}; 252148456Spjd 253148456Spjdstatic int verbose = 0; 254148456Spjd 255148456Spjdstatic int 256148456Spjdeli_protect(struct gctl_req *req) 257148456Spjd{ 258148456Spjd struct rlimit rl; 259148456Spjd 260148456Spjd /* Disable core dumps. */ 261148456Spjd rl.rlim_cur = 0; 262148456Spjd rl.rlim_max = 0; 263148456Spjd if (setrlimit(RLIMIT_CORE, &rl) == -1) { 264148456Spjd gctl_error(req, "Cannot disable core dumps: %s.", 265148456Spjd strerror(errno)); 266148456Spjd return (-1); 267148456Spjd } 268148456Spjd /* Disable swapping. */ 269148456Spjd if (mlockall(MCL_FUTURE) == -1) { 270148456Spjd gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 271148456Spjd return (-1); 272148456Spjd } 273148456Spjd return (0); 274148456Spjd} 275148456Spjd 276148456Spjdstatic void 277213172Spjdeli_main(struct gctl_req *req, unsigned int flags) 278148456Spjd{ 279148456Spjd const char *name; 280148456Spjd 281148456Spjd if (eli_protect(req) == -1) 282148456Spjd return; 283148456Spjd 284148456Spjd if ((flags & G_FLAG_VERBOSE) != 0) 285148456Spjd verbose = 1; 286148456Spjd 287153190Spjd name = gctl_get_ascii(req, "verb"); 288148456Spjd if (name == NULL) { 289148456Spjd gctl_error(req, "No '%s' argument.", "verb"); 290148456Spjd return; 291148456Spjd } 292148456Spjd if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 293148456Spjd eli_init(req); 294148456Spjd else if (strcmp(name, "attach") == 0) 295148456Spjd eli_attach(req); 296162353Spjd else if (strcmp(name, "configure") == 0) 297162353Spjd eli_configure(req); 298148456Spjd else if (strcmp(name, "setkey") == 0) 299148456Spjd eli_setkey(req); 300148456Spjd else if (strcmp(name, "delkey") == 0) 301148456Spjd eli_delkey(req); 302214118Spjd else if (strcmp(name, "resume") == 0) 303214118Spjd eli_resume(req); 304148456Spjd else if (strcmp(name, "kill") == 0) 305148456Spjd eli_kill(req); 306148456Spjd else if (strcmp(name, "backup") == 0) 307148456Spjd eli_backup(req); 308148456Spjd else if (strcmp(name, "restore") == 0) 309148456Spjd eli_restore(req); 310212934Sbrian else if (strcmp(name, "resize") == 0) 311212934Sbrian eli_resize(req); 312148456Spjd else if (strcmp(name, "dump") == 0) 313148456Spjd eli_dump(req); 314148456Spjd else if (strcmp(name, "clear") == 0) 315148456Spjd eli_clear(req); 316148456Spjd else 317148456Spjd gctl_error(req, "Unknown command: %s.", name); 318148456Spjd} 319148456Spjd 320148456Spjdstatic void 321148456Spjdarc4rand(unsigned char *buf, size_t size) 322148456Spjd{ 323148456Spjd uint32_t *buf4; 324148456Spjd size_t size4; 325213172Spjd unsigned int i; 326148456Spjd 327148456Spjd buf4 = (uint32_t *)buf; 328148456Spjd size4 = size / 4; 329148456Spjd 330148456Spjd for (i = 0; i < size4; i++) 331148456Spjd buf4[i] = arc4random(); 332148456Spjd for (i *= 4; i < size; i++) 333148456Spjd buf[i] = arc4random() % 0xff; 334148456Spjd} 335148456Spjd 336148456Spjdstatic int 337148456Spjdeli_is_attached(const char *prov) 338148456Spjd{ 339148456Spjd char name[MAXPATHLEN]; 340148456Spjd unsigned secsize; 341148456Spjd 342148456Spjd /* 343148456Spjd * Not the best way to do it, but the easiest. 344148456Spjd * We try to open provider and check if it is a GEOM provider 345148456Spjd * by asking about its sectorsize. 346148456Spjd */ 347148456Spjd snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 348148456Spjd secsize = g_get_sectorsize(name); 349148456Spjd if (secsize > 0) 350148456Spjd return (1); 351148456Spjd return (0); 352148456Spjd} 353148456Spjd 354213172Spjdstatic int 355213172Spjdeli_genkey_files(struct gctl_req *req, bool new, const char *type, 356213172Spjd struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize) 357148456Spjd{ 358213172Spjd char *p, buf[MAXPHYS], argname[16]; 359213172Spjd const char *file; 360213172Spjd int error, fd, i; 361213172Spjd ssize_t done; 362148456Spjd 363213172Spjd assert((strcmp(type, "keyfile") == 0 && ctxp != NULL && 364213172Spjd passbuf == NULL && passbufsize == 0) || 365213172Spjd (strcmp(type, "passfile") == 0 && ctxp == NULL && 366213172Spjd passbuf != NULL && passbufsize > 0)); 367213172Spjd assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0'); 368148456Spjd 369213172Spjd for (i = 0; ; i++) { 370213172Spjd snprintf(argname, sizeof(argname), "%s%s%d", 371213172Spjd new ? "new" : "", type, i); 372148456Spjd 373213172Spjd /* No more {key,pass}files? */ 374213172Spjd if (!gctl_has_param(req, argname)) 375213172Spjd return (i); 376148456Spjd 377215704Sbrucec file = gctl_get_ascii(req, "%s", argname); 378213172Spjd assert(file != NULL); 379213172Spjd 380213172Spjd if (strcmp(file, "-") == 0) 381148456Spjd fd = STDIN_FILENO; 382148456Spjd else { 383213172Spjd fd = open(file, O_RDONLY); 384148456Spjd if (fd == -1) { 385213172Spjd gctl_error(req, "Cannot open %s %s: %s.", 386213172Spjd type, file, strerror(errno)); 387213172Spjd return (-1); 388148456Spjd } 389148456Spjd } 390213172Spjd if (strcmp(type, "keyfile") == 0) { 391213172Spjd while ((done = read(fd, buf, sizeof(buf))) > 0) 392213172Spjd g_eli_crypto_hmac_update(ctxp, buf, done); 393213172Spjd } else /* if (strcmp(type, "passfile") == 0) */ { 394213172Spjd while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) { 395213172Spjd buf[done] = '\0'; 396213172Spjd p = strchr(buf, '\n'); 397213172Spjd if (p != NULL) { 398213172Spjd *p = '\0'; 399213172Spjd done = p - buf; 400213172Spjd } 401213172Spjd if (strlcat(passbuf, buf, passbufsize) >= 402213172Spjd passbufsize) { 403213172Spjd gctl_error(req, 404213172Spjd "Passphrase in %s too long.", file); 405213172Spjd bzero(buf, sizeof(buf)); 406213172Spjd return (-1); 407213172Spjd } 408213172Spjd if (p != NULL) 409213172Spjd break; 410213172Spjd } 411213172Spjd } 412148456Spjd error = errno; 413213172Spjd if (strcmp(file, "-") != 0) 414148456Spjd close(fd); 415148456Spjd bzero(buf, sizeof(buf)); 416148456Spjd if (done == -1) { 417213172Spjd gctl_error(req, "Cannot read %s %s: %s.", 418213172Spjd type, file, strerror(error)); 419213172Spjd return (-1); 420148456Spjd } 421148456Spjd } 422213172Spjd /* NOTREACHED */ 423213172Spjd} 424148456Spjd 425213172Spjdstatic int 426213172Spjdeli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf, 427213172Spjd size_t passbufsize) 428213172Spjd{ 429213172Spjd char *p; 430148456Spjd 431213172Spjd for (;;) { 432213172Spjd p = readpassphrase( 433213172Spjd new ? "Enter new passphrase:" : "Enter passphrase:", 434213172Spjd passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY); 435213172Spjd if (p == NULL) { 436213172Spjd bzero(passbuf, passbufsize); 437213172Spjd gctl_error(req, "Cannot read passphrase: %s.", 438213172Spjd strerror(errno)); 439213172Spjd return (-1); 440149047Spjd } 441213172Spjd 442213172Spjd if (new) { 443213172Spjd char tmpbuf[BUFSIZ]; 444213172Spjd 445213172Spjd p = readpassphrase("Reenter new passphrase: ", 446213172Spjd tmpbuf, sizeof(tmpbuf), 447213172Spjd RPP_ECHO_OFF | RPP_REQUIRE_TTY); 448148456Spjd if (p == NULL) { 449213172Spjd bzero(passbuf, passbufsize); 450213172Spjd gctl_error(req, 451213172Spjd "Cannot read passphrase: %s.", 452148456Spjd strerror(errno)); 453213172Spjd return (-1); 454148456Spjd } 455213172Spjd 456213172Spjd if (strcmp(passbuf, tmpbuf) != 0) { 457213172Spjd bzero(passbuf, passbufsize); 458213172Spjd fprintf(stderr, "They didn't match.\n"); 459213172Spjd continue; 460148456Spjd } 461213172Spjd bzero(tmpbuf, sizeof(tmpbuf)); 462148456Spjd } 463213172Spjd return (0); 464213172Spjd } 465213172Spjd /* NOTREACHED */ 466213172Spjd} 467213172Spjd 468213172Spjdstatic int 469213172Spjdeli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new, 470213172Spjd struct hmac_ctx *ctxp) 471213172Spjd{ 472213172Spjd char passbuf[MAXPHYS]; 473213172Spjd bool nopassphrase; 474213172Spjd int nfiles; 475213172Spjd 476213172Spjd nopassphrase = 477213172Spjd gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 478213172Spjd if (nopassphrase) { 479213172Spjd if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) { 480213172Spjd gctl_error(req, 481213172Spjd "Options -%c and -%c are mutually exclusive.", 482213172Spjd new ? 'J' : 'j', new ? 'P' : 'p'); 483213172Spjd return (-1); 484148456Spjd } 485213172Spjd return (0); 486213172Spjd } 487148456Spjd 488213172Spjd if (!new && md->md_iterations == -1) { 489213172Spjd gctl_error(req, "Missing -p flag."); 490213172Spjd return (-1); 491213172Spjd } 492213172Spjd passbuf[0] = '\0'; 493213172Spjd nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf, 494213172Spjd sizeof(passbuf)); 495213172Spjd if (nfiles == -1) 496213172Spjd return (-1); 497213172Spjd else if (nfiles == 0) { 498213172Spjd if (eli_genkey_passphrase_prompt(req, new, passbuf, 499213172Spjd sizeof(passbuf)) == -1) { 500213172Spjd return (-1); 501148456Spjd } 502148456Spjd } 503213172Spjd /* 504213172Spjd * Field md_iterations equal to -1 means "choose some sane 505213172Spjd * value for me". 506213172Spjd */ 507213172Spjd if (md->md_iterations == -1) { 508213172Spjd assert(new); 509213172Spjd if (verbose) 510213172Spjd printf("Calculating number of iterations...\n"); 511213172Spjd md->md_iterations = pkcs5v2_calculate(2000000); 512213172Spjd assert(md->md_iterations > 0); 513213172Spjd if (verbose) { 514213172Spjd printf("Done, using %d iterations.\n", 515213172Spjd md->md_iterations); 516213172Spjd } 517213172Spjd } 518213172Spjd /* 519213172Spjd * If md_iterations is equal to 0, user doesn't want PKCS#5v2. 520213172Spjd */ 521213172Spjd if (md->md_iterations == 0) { 522213172Spjd g_eli_crypto_hmac_update(ctxp, md->md_salt, 523213172Spjd sizeof(md->md_salt)); 524213172Spjd g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf)); 525213172Spjd } else /* if (md->md_iterations > 0) */ { 526213172Spjd unsigned char dkey[G_ELI_USERKEYLEN]; 527213172Spjd 528213172Spjd pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 529213172Spjd sizeof(md->md_salt), passbuf, md->md_iterations); 530213172Spjd g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey)); 531213172Spjd bzero(dkey, sizeof(dkey)); 532213172Spjd } 533213172Spjd bzero(passbuf, sizeof(passbuf)); 534213172Spjd 535213172Spjd return (0); 536213172Spjd} 537213172Spjd 538213172Spjdstatic unsigned char * 539213172Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 540213172Spjd bool new) 541213172Spjd{ 542213172Spjd struct hmac_ctx ctx; 543213172Spjd bool nopassphrase; 544213172Spjd int nfiles; 545213172Spjd 546213172Spjd nopassphrase = 547213172Spjd gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 548213172Spjd 549213172Spjd g_eli_crypto_hmac_init(&ctx, NULL, 0); 550213172Spjd 551213172Spjd nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0); 552213172Spjd if (nfiles == -1) 553213172Spjd return (NULL); 554213172Spjd else if (nfiles == 0 && nopassphrase) { 555213172Spjd gctl_error(req, "No key components given."); 556213172Spjd return (NULL); 557213172Spjd } 558213172Spjd 559213172Spjd if (eli_genkey_passphrase(req, md, new, &ctx) == -1) 560213172Spjd return (NULL); 561213172Spjd 562148456Spjd g_eli_crypto_hmac_final(&ctx, key, 0); 563213172Spjd 564148456Spjd return (key); 565148456Spjd} 566148456Spjd 567148456Spjdstatic int 568148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov, 569148456Spjd struct g_eli_metadata *md) 570148456Spjd{ 571148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 572148456Spjd int error; 573148456Spjd 574148456Spjd if (g_get_sectorsize(prov) == 0) { 575148456Spjd int fd; 576148456Spjd 577148456Spjd /* This is a file probably. */ 578148456Spjd fd = open(prov, O_RDONLY); 579148456Spjd if (fd == -1) { 580148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 581148456Spjd strerror(errno)); 582148456Spjd return (-1); 583148456Spjd } 584148456Spjd if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 585148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 586148456Spjd prov, strerror(errno)); 587148456Spjd close(fd); 588148456Spjd return (-1); 589148456Spjd } 590148456Spjd close(fd); 591148456Spjd } else { 592148456Spjd /* This is a GEOM provider. */ 593148456Spjd error = g_metadata_read(prov, sector, sizeof(sector), 594148456Spjd G_ELI_MAGIC); 595148456Spjd if (error != 0) { 596148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 597148456Spjd prov, strerror(error)); 598148456Spjd return (-1); 599148456Spjd } 600148456Spjd } 601148456Spjd if (eli_metadata_decode(sector, md) != 0) { 602148456Spjd gctl_error(req, "MD5 hash mismatch for %s.", prov); 603148456Spjd return (-1); 604148456Spjd } 605148456Spjd return (0); 606148456Spjd} 607148456Spjd 608148456Spjdstatic int 609148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov, 610148456Spjd struct g_eli_metadata *md) 611148456Spjd{ 612148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 613148456Spjd int error; 614148456Spjd 615148456Spjd eli_metadata_encode(md, sector); 616148456Spjd if (g_get_sectorsize(prov) == 0) { 617148456Spjd int fd; 618148456Spjd 619148456Spjd /* This is a file probably. */ 620148456Spjd fd = open(prov, O_WRONLY | O_TRUNC); 621148456Spjd if (fd == -1) { 622148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 623148456Spjd strerror(errno)); 624148456Spjd bzero(sector, sizeof(sector)); 625148456Spjd return (-1); 626148456Spjd } 627148456Spjd if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 628148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 629148456Spjd prov, strerror(errno)); 630148456Spjd bzero(sector, sizeof(sector)); 631148456Spjd close(fd); 632148456Spjd return (-1); 633148456Spjd } 634148456Spjd close(fd); 635148456Spjd } else { 636148456Spjd /* This is a GEOM provider. */ 637148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 638148456Spjd if (error != 0) { 639148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 640148456Spjd prov, strerror(errno)); 641148456Spjd bzero(sector, sizeof(sector)); 642148456Spjd return (-1); 643148456Spjd } 644148456Spjd } 645148456Spjd bzero(sector, sizeof(sector)); 646148456Spjd return (0); 647148456Spjd} 648148456Spjd 649148456Spjdstatic void 650148456Spjdeli_init(struct gctl_req *req) 651148456Spjd{ 652148456Spjd struct g_eli_metadata md; 653148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 654148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 655182452Spjd char backfile[MAXPATHLEN]; 656148456Spjd const char *str, *prov; 657148456Spjd unsigned secsize; 658148456Spjd off_t mediasize; 659153190Spjd intmax_t val; 660155536Spjd int error, nargs; 661148456Spjd 662153190Spjd nargs = gctl_get_int(req, "nargs"); 663153190Spjd if (nargs != 1) { 664158214Spjd gctl_error(req, "Invalid number of arguments."); 665148456Spjd return; 666148456Spjd } 667153190Spjd prov = gctl_get_ascii(req, "arg0"); 668148456Spjd mediasize = g_get_mediasize(prov); 669148456Spjd secsize = g_get_sectorsize(prov); 670148456Spjd if (mediasize == 0 || secsize == 0) { 671148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 672148456Spjd strerror(errno)); 673148456Spjd return; 674148456Spjd } 675148456Spjd 676148456Spjd bzero(&md, sizeof(md)); 677148456Spjd strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 678148456Spjd md.md_version = G_ELI_VERSION; 679148456Spjd md.md_flags = 0; 680155536Spjd if (gctl_get_int(req, "boot")) 681148456Spjd md.md_flags |= G_ELI_FLAG_BOOT; 682159361Spjd md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 683159308Spjd str = gctl_get_ascii(req, "aalgo"); 684212547Spjd if (*str != '\0') { 685159308Spjd md.md_aalgo = g_eli_str2aalgo(str); 686159361Spjd if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 687159361Spjd md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 688159361Spjd md.md_flags |= G_ELI_FLAG_AUTH; 689159361Spjd } else { 690159361Spjd /* 691159361Spjd * For backward compatibility, check if the -a option 692159361Spjd * was used to provide encryption algorithm. 693159361Spjd */ 694159361Spjd md.md_ealgo = g_eli_str2ealgo(str); 695159361Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 696159361Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 697159361Spjd gctl_error(req, 698159361Spjd "Invalid authentication algorithm."); 699159361Spjd return; 700159361Spjd } else { 701159361Spjd fprintf(stderr, "warning: The -e option, not " 702159361Spjd "the -a option is now used to specify " 703159361Spjd "encryption algorithm to use.\n"); 704159361Spjd } 705159308Spjd } 706159308Spjd } 707159308Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 708159308Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 709159361Spjd str = gctl_get_ascii(req, "ealgo"); 710159361Spjd md.md_ealgo = g_eli_str2ealgo(str); 711159361Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 712159361Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 713159361Spjd gctl_error(req, "Invalid encryption algorithm."); 714159361Spjd return; 715159361Spjd } 716148456Spjd } 717153190Spjd val = gctl_get_intmax(req, "keylen"); 718153190Spjd md.md_keylen = val; 719159308Spjd md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 720148456Spjd if (md.md_keylen == 0) { 721148456Spjd gctl_error(req, "Invalid key length."); 722148456Spjd return; 723148456Spjd } 724148456Spjd md.md_provsize = mediasize; 725148456Spjd 726153190Spjd val = gctl_get_intmax(req, "iterations"); 727155536Spjd if (val != -1) { 728155536Spjd int nonewpassphrase; 729155536Spjd 730155536Spjd /* 731155536Spjd * Don't allow to set iterations when there will be no 732155536Spjd * passphrase. 733155536Spjd */ 734155536Spjd nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 735155536Spjd if (nonewpassphrase) { 736155536Spjd gctl_error(req, 737155536Spjd "Options -i and -P are mutually exclusive."); 738155536Spjd return; 739155536Spjd } 740155536Spjd } 741153190Spjd md.md_iterations = val; 742148456Spjd 743153190Spjd val = gctl_get_intmax(req, "sectorsize"); 744153190Spjd if (val == 0) 745148456Spjd md.md_sectorsize = secsize; 746148456Spjd else { 747153190Spjd if (val < 0 || (val % secsize) != 0) { 748148456Spjd gctl_error(req, "Invalid sector size."); 749148456Spjd return; 750148456Spjd } 751167229Spjd if (val > sysconf(_SC_PAGE_SIZE)) { 752214404Spjd fprintf(stderr, 753214404Spjd "warning: Using sectorsize bigger than the page size!\n"); 754167229Spjd } 755153190Spjd md.md_sectorsize = val; 756148456Spjd } 757148456Spjd 758148456Spjd md.md_keys = 0x01; 759148456Spjd arc4rand(md.md_salt, sizeof(md.md_salt)); 760148456Spjd arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 761148456Spjd 762148456Spjd /* Generate user key. */ 763213172Spjd if (eli_genkey(req, &md, key, true) == NULL) { 764148456Spjd bzero(key, sizeof(key)); 765148456Spjd bzero(&md, sizeof(md)); 766148456Spjd return; 767148456Spjd } 768148456Spjd 769148456Spjd /* Encrypt the first and the only Master Key. */ 770159308Spjd error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 771148456Spjd bzero(key, sizeof(key)); 772148456Spjd if (error != 0) { 773148456Spjd bzero(&md, sizeof(md)); 774148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 775148456Spjd strerror(error)); 776148456Spjd return; 777148456Spjd } 778148456Spjd 779148456Spjd eli_metadata_encode(&md, sector); 780148456Spjd bzero(&md, sizeof(md)); 781148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 782148456Spjd bzero(sector, sizeof(sector)); 783148456Spjd if (error != 0) { 784148456Spjd gctl_error(req, "Cannot store metadata on %s: %s.", prov, 785148456Spjd strerror(error)); 786148456Spjd return; 787148456Spjd } 788148456Spjd if (verbose) 789148456Spjd printf("Metadata value stored on %s.\n", prov); 790182452Spjd /* Backup metadata to a file. */ 791182452Spjd str = gctl_get_ascii(req, "backupfile"); 792182452Spjd if (str[0] != '\0') { 793182452Spjd /* Backupfile given be the user, just copy it. */ 794182452Spjd strlcpy(backfile, str, sizeof(backfile)); 795182452Spjd } else { 796182452Spjd /* Generate file name automatically. */ 797182452Spjd const char *p = prov; 798182452Spjd unsigned int i; 799182452Spjd 800213662Sae if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 801213662Sae p += sizeof(_PATH_DEV) - 1; 802182452Spjd snprintf(backfile, sizeof(backfile), "%s%s.eli", 803182452Spjd GELI_BACKUP_DIR, p); 804182452Spjd /* Replace all / with _. */ 805182452Spjd for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { 806182452Spjd if (backfile[i] == '/') 807182452Spjd backfile[i] = '_'; 808182452Spjd } 809182452Spjd } 810182452Spjd if (strcmp(backfile, "none") != 0 && 811182452Spjd eli_backup_create(req, prov, backfile) == 0) { 812182452Spjd printf("\nMetadata backup can be found in %s and\n", backfile); 813182452Spjd printf("can be restored with the following command:\n"); 814182452Spjd printf("\n\t# geli restore %s %s\n\n", backfile, prov); 815182452Spjd } 816148456Spjd} 817148456Spjd 818148456Spjdstatic void 819148456Spjdeli_attach(struct gctl_req *req) 820148456Spjd{ 821148456Spjd struct g_eli_metadata md; 822148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 823148456Spjd const char *prov; 824212934Sbrian off_t mediasize; 825153190Spjd int nargs; 826148456Spjd 827153190Spjd nargs = gctl_get_int(req, "nargs"); 828153190Spjd if (nargs != 1) { 829158214Spjd gctl_error(req, "Invalid number of arguments."); 830148456Spjd return; 831148456Spjd } 832153190Spjd prov = gctl_get_ascii(req, "arg0"); 833148456Spjd 834148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 835148456Spjd return; 836148456Spjd 837212934Sbrian mediasize = g_get_mediasize(prov); 838212934Sbrian if (md.md_provsize != (uint64_t)mediasize) { 839212934Sbrian gctl_error(req, "Provider size mismatch."); 840212934Sbrian return; 841212934Sbrian } 842212934Sbrian 843213172Spjd if (eli_genkey(req, &md, key, false) == NULL) { 844148456Spjd bzero(key, sizeof(key)); 845148456Spjd return; 846148456Spjd } 847148456Spjd 848148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 849148456Spjd if (gctl_issue(req) == NULL) { 850148456Spjd if (verbose) 851166892Spjd printf("Attached to %s.\n", prov); 852148456Spjd } 853148456Spjd bzero(key, sizeof(key)); 854148456Spjd} 855148456Spjd 856148456Spjdstatic void 857213172Spjdeli_configure_detached(struct gctl_req *req, const char *prov, bool boot) 858162353Spjd{ 859162353Spjd struct g_eli_metadata md; 860162353Spjd 861162353Spjd if (eli_metadata_read(req, prov, &md) == -1) 862162353Spjd return; 863162353Spjd 864162353Spjd if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { 865162353Spjd if (verbose) 866162353Spjd printf("BOOT flag already configured for %s.\n", prov); 867162353Spjd } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { 868162353Spjd if (verbose) 869162353Spjd printf("BOOT flag not configured for %s.\n", prov); 870162353Spjd } else { 871162353Spjd if (boot) 872162353Spjd md.md_flags |= G_ELI_FLAG_BOOT; 873162353Spjd else 874162353Spjd md.md_flags &= ~G_ELI_FLAG_BOOT; 875162353Spjd eli_metadata_store(req, prov, &md); 876162353Spjd } 877162353Spjd bzero(&md, sizeof(md)); 878162353Spjd} 879162353Spjd 880162353Spjdstatic void 881162353Spjdeli_configure(struct gctl_req *req) 882162353Spjd{ 883162353Spjd const char *prov; 884213172Spjd bool boot, noboot; 885213172Spjd int i, nargs; 886162353Spjd 887162353Spjd nargs = gctl_get_int(req, "nargs"); 888162353Spjd if (nargs == 0) { 889162353Spjd gctl_error(req, "Too few arguments."); 890162353Spjd return; 891162353Spjd } 892162353Spjd 893162353Spjd boot = gctl_get_int(req, "boot"); 894162353Spjd noboot = gctl_get_int(req, "noboot"); 895162353Spjd 896162353Spjd if (boot && noboot) { 897162353Spjd gctl_error(req, "Options -b and -B are mutually exclusive."); 898162353Spjd return; 899162353Spjd } 900162353Spjd if (!boot && !noboot) { 901162353Spjd gctl_error(req, "No option given."); 902162353Spjd return; 903162353Spjd } 904162353Spjd 905162353Spjd /* First attached providers. */ 906162353Spjd gctl_issue(req); 907162353Spjd /* Now the rest. */ 908162353Spjd for (i = 0; i < nargs; i++) { 909162353Spjd prov = gctl_get_ascii(req, "arg%d", i); 910162353Spjd if (!eli_is_attached(prov)) 911162353Spjd eli_configure_detached(req, prov, boot); 912162353Spjd } 913162353Spjd} 914162353Spjd 915162353Spjdstatic void 916155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 917148456Spjd{ 918148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 919166216Spjd intmax_t val, old = 0; 920166216Spjd int error; 921148456Spjd 922153190Spjd val = gctl_get_intmax(req, "iterations"); 923149304Spjd /* Check if iterations number should be changed. */ 924153190Spjd if (val != -1) 925153190Spjd md->md_iterations = val; 926166216Spjd else 927166216Spjd old = md->md_iterations; 928148456Spjd 929148456Spjd /* Generate key for Master Key encryption. */ 930213172Spjd if (eli_genkey(req, md, key, true) == NULL) { 931148456Spjd bzero(key, sizeof(key)); 932148456Spjd return; 933148456Spjd } 934166216Spjd /* 935166216Spjd * If number of iterations has changed, but wasn't given as a 936166216Spjd * command-line argument, update the request. 937166216Spjd */ 938166216Spjd if (val == -1 && md->md_iterations != old) { 939166216Spjd error = gctl_change_param(req, "iterations", sizeof(intmax_t), 940166216Spjd &md->md_iterations); 941166216Spjd assert(error == 0); 942166216Spjd } 943148456Spjd 944148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 945148456Spjd gctl_issue(req); 946148456Spjd bzero(key, sizeof(key)); 947148456Spjd} 948148456Spjd 949148456Spjdstatic void 950149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov, 951149304Spjd struct g_eli_metadata *md) 952148456Spjd{ 953148456Spjd unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 954148456Spjd unsigned char *mkeydst; 955213172Spjd unsigned int nkey; 956153190Spjd intmax_t val; 957148456Spjd int error; 958148456Spjd 959149928Spjd if (md->md_keys == 0) { 960149928Spjd gctl_error(req, "No valid keys on %s.", prov); 961149928Spjd return; 962149928Spjd } 963149928Spjd 964148456Spjd /* Generate key for Master Key decryption. */ 965213172Spjd if (eli_genkey(req, md, key, false) == NULL) { 966148456Spjd bzero(key, sizeof(key)); 967148456Spjd return; 968148456Spjd } 969148456Spjd 970148456Spjd /* Decrypt Master Key. */ 971149304Spjd error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 972148456Spjd bzero(key, sizeof(key)); 973148456Spjd if (error != 0) { 974149304Spjd bzero(md, sizeof(*md)); 975148456Spjd if (error == -1) 976148456Spjd gctl_error(req, "Wrong key for %s.", prov); 977148456Spjd else /* if (error > 0) */ { 978148456Spjd gctl_error(req, "Cannot decrypt Master Key: %s.", 979148456Spjd strerror(error)); 980148456Spjd } 981148456Spjd return; 982148456Spjd } 983148456Spjd if (verbose) 984148456Spjd printf("Decrypted Master Key %u.\n", nkey); 985148456Spjd 986153190Spjd val = gctl_get_intmax(req, "keyno"); 987153190Spjd if (val != -1) 988153190Spjd nkey = val; 989148456Spjd#if 0 990148456Spjd else 991148456Spjd ; /* Use the key number which was found during decryption. */ 992148456Spjd#endif 993148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 994148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 995148456Spjd return; 996148456Spjd } 997148456Spjd 998153190Spjd val = gctl_get_intmax(req, "iterations"); 999149304Spjd /* Check if iterations number should and can be changed. */ 1000153190Spjd if (val != -1) { 1001149304Spjd if (bitcount32(md->md_keys) != 1) { 1002149304Spjd gctl_error(req, "To be able to use '-i' option, only " 1003149304Spjd "one key can be defined."); 1004149304Spjd return; 1005149304Spjd } 1006149304Spjd if (md->md_keys != (1 << nkey)) { 1007149304Spjd gctl_error(req, "Only already defined key can be " 1008149304Spjd "changed when '-i' option is used."); 1009149304Spjd return; 1010149304Spjd } 1011153190Spjd md->md_iterations = val; 1012149304Spjd } 1013148456Spjd 1014149304Spjd mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 1015149304Spjd md->md_keys |= (1 << nkey); 1016149304Spjd 1017148456Spjd bcopy(mkey, mkeydst, sizeof(mkey)); 1018148456Spjd bzero(mkey, sizeof(mkey)); 1019148456Spjd 1020148456Spjd /* Generate key for Master Key encryption. */ 1021213172Spjd if (eli_genkey(req, md, key, true) == NULL) { 1022148456Spjd bzero(key, sizeof(key)); 1023149304Spjd bzero(md, sizeof(*md)); 1024148456Spjd return; 1025148456Spjd } 1026148456Spjd 1027148456Spjd /* Encrypt the Master-Key with the new key. */ 1028159308Spjd error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 1029148456Spjd bzero(key, sizeof(key)); 1030148456Spjd if (error != 0) { 1031149304Spjd bzero(md, sizeof(*md)); 1032148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 1033148456Spjd strerror(error)); 1034148456Spjd return; 1035148456Spjd } 1036148456Spjd 1037148456Spjd /* Store metadata with fresh key. */ 1038149304Spjd eli_metadata_store(req, prov, md); 1039149304Spjd bzero(md, sizeof(*md)); 1040148456Spjd} 1041148456Spjd 1042148456Spjdstatic void 1043148456Spjdeli_setkey(struct gctl_req *req) 1044148456Spjd{ 1045149304Spjd struct g_eli_metadata md; 1046148456Spjd const char *prov; 1047153190Spjd int nargs; 1048148456Spjd 1049153190Spjd nargs = gctl_get_int(req, "nargs"); 1050153190Spjd if (nargs != 1) { 1051158214Spjd gctl_error(req, "Invalid number of arguments."); 1052148456Spjd return; 1053148456Spjd } 1054153190Spjd prov = gctl_get_ascii(req, "arg0"); 1055148456Spjd 1056149304Spjd if (eli_metadata_read(req, prov, &md) == -1) 1057149304Spjd return; 1058149304Spjd 1059148456Spjd if (eli_is_attached(prov)) 1060155101Spjd eli_setkey_attached(req, &md); 1061148456Spjd else 1062149304Spjd eli_setkey_detached(req, prov, &md); 1063182452Spjd 1064182452Spjd if (req->error == NULL || req->error[0] == '\0') { 1065182452Spjd printf("Note, that the master key encrypted with old keys " 1066182452Spjd "and/or passphrase may still exists in a metadata backup " 1067182452Spjd "file.\n"); 1068182452Spjd } 1069148456Spjd} 1070148456Spjd 1071148456Spjdstatic void 1072148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused) 1073148456Spjd{ 1074148456Spjd 1075148456Spjd gctl_issue(req); 1076148456Spjd} 1077148456Spjd 1078148456Spjdstatic void 1079148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov) 1080148456Spjd{ 1081148456Spjd struct g_eli_metadata md; 1082148456Spjd unsigned char *mkeydst; 1083213172Spjd unsigned int nkey; 1084153190Spjd intmax_t val; 1085213172Spjd bool all, force; 1086148456Spjd 1087148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 1088148456Spjd return; 1089148456Spjd 1090153190Spjd all = gctl_get_int(req, "all"); 1091153190Spjd if (all) 1092148456Spjd arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 1093148456Spjd else { 1094153190Spjd force = gctl_get_int(req, "force"); 1095153190Spjd val = gctl_get_intmax(req, "keyno"); 1096153190Spjd if (val == -1) { 1097148456Spjd gctl_error(req, "Key number has to be specified."); 1098148456Spjd return; 1099148456Spjd } 1100153190Spjd nkey = val; 1101148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 1102148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 1103148456Spjd return; 1104148456Spjd } 1105153190Spjd if (!(md.md_keys & (1 << nkey)) && !force) { 1106148456Spjd gctl_error(req, "Master Key %u is not set.", nkey); 1107148456Spjd return; 1108148456Spjd } 1109148456Spjd md.md_keys &= ~(1 << nkey); 1110153190Spjd if (md.md_keys == 0 && !force) { 1111148456Spjd gctl_error(req, "This is the last Master Key. Use '-f' " 1112148456Spjd "option if you really want to remove it."); 1113148456Spjd return; 1114148456Spjd } 1115148456Spjd mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 1116148456Spjd arc4rand(mkeydst, G_ELI_MKEYLEN); 1117148456Spjd } 1118148456Spjd 1119148456Spjd eli_metadata_store(req, prov, &md); 1120148456Spjd bzero(&md, sizeof(md)); 1121148456Spjd} 1122148456Spjd 1123148456Spjdstatic void 1124148456Spjdeli_delkey(struct gctl_req *req) 1125148456Spjd{ 1126148456Spjd const char *prov; 1127153190Spjd int nargs; 1128148456Spjd 1129153190Spjd nargs = gctl_get_int(req, "nargs"); 1130153190Spjd if (nargs != 1) { 1131158214Spjd gctl_error(req, "Invalid number of arguments."); 1132148456Spjd return; 1133148456Spjd } 1134153190Spjd prov = gctl_get_ascii(req, "arg0"); 1135148456Spjd 1136148456Spjd if (eli_is_attached(prov)) 1137148456Spjd eli_delkey_attached(req, prov); 1138148456Spjd else 1139148456Spjd eli_delkey_detached(req, prov); 1140148456Spjd} 1141148456Spjd 1142214118Spjdstatic void 1143214118Spjdeli_resume(struct gctl_req *req) 1144214118Spjd{ 1145214118Spjd struct g_eli_metadata md; 1146214118Spjd unsigned char key[G_ELI_USERKEYLEN]; 1147214118Spjd const char *prov; 1148214118Spjd off_t mediasize; 1149214118Spjd int nargs; 1150214118Spjd 1151214118Spjd nargs = gctl_get_int(req, "nargs"); 1152214118Spjd if (nargs != 1) { 1153214118Spjd gctl_error(req, "Invalid number of arguments."); 1154214118Spjd return; 1155214118Spjd } 1156214118Spjd prov = gctl_get_ascii(req, "arg0"); 1157214118Spjd 1158214118Spjd if (eli_metadata_read(req, prov, &md) == -1) 1159214118Spjd return; 1160214118Spjd 1161214118Spjd mediasize = g_get_mediasize(prov); 1162214118Spjd if (md.md_provsize != (uint64_t)mediasize) { 1163214118Spjd gctl_error(req, "Provider size mismatch."); 1164214118Spjd return; 1165214118Spjd } 1166214118Spjd 1167214118Spjd if (eli_genkey(req, &md, key, false) == NULL) { 1168214118Spjd bzero(key, sizeof(key)); 1169214118Spjd return; 1170214118Spjd } 1171214118Spjd 1172214118Spjd gctl_ro_param(req, "key", sizeof(key), key); 1173214118Spjd if (gctl_issue(req) == NULL) { 1174214118Spjd if (verbose) 1175214118Spjd printf("Resumed %s.\n", prov); 1176214118Spjd } 1177214118Spjd bzero(key, sizeof(key)); 1178214118Spjd} 1179214118Spjd 1180213060Spjdstatic int 1181213060Spjdeli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset) 1182213060Spjd{ 1183213060Spjd unsigned int overwrites; 1184213060Spjd unsigned char *sector; 1185213060Spjd ssize_t size; 1186213060Spjd int error; 1187213060Spjd 1188213060Spjd size = sizeof(overwrites); 1189213060Spjd if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size, 1190213060Spjd NULL, 0) == -1 || overwrites == 0) { 1191213060Spjd overwrites = G_ELI_OVERWRITES; 1192213060Spjd } 1193213060Spjd 1194213060Spjd size = g_sectorsize(fd); 1195213060Spjd if (size <= 0) { 1196213060Spjd gctl_error(req, "Cannot obtain provider sector size %s: %s.", 1197213060Spjd prov, strerror(errno)); 1198213060Spjd return (-1); 1199213060Spjd } 1200213060Spjd sector = malloc(size); 1201213060Spjd if (sector == NULL) { 1202213060Spjd gctl_error(req, "Cannot allocate %zd bytes of memory.", size); 1203213060Spjd return (-1); 1204213060Spjd } 1205213060Spjd 1206213060Spjd error = 0; 1207213060Spjd do { 1208213060Spjd arc4rand(sector, size); 1209213060Spjd if (pwrite(fd, sector, size, offset) != size) { 1210213060Spjd if (error == 0) 1211213060Spjd error = errno; 1212213060Spjd } 1213213060Spjd (void)g_flush(fd); 1214213060Spjd } while (--overwrites > 0); 1215213060Spjd if (error != 0) { 1216213060Spjd gctl_error(req, "Cannot trash metadata on provider %s: %s.", 1217213060Spjd prov, strerror(error)); 1218213060Spjd return (-1); 1219213060Spjd } 1220213060Spjd return (0); 1221213060Spjd} 1222213060Spjd 1223148456Spjdstatic void 1224148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov) 1225148456Spjd{ 1226213060Spjd off_t offset; 1227213060Spjd int fd; 1228148456Spjd 1229148456Spjd /* 1230148456Spjd * NOTE: Maybe we should verify if this is geli provider first, 1231148456Spjd * but 'kill' command is quite critical so better don't waste 1232148456Spjd * the time. 1233148456Spjd */ 1234148456Spjd#if 0 1235148456Spjd error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 1236148456Spjd G_ELI_MAGIC); 1237148456Spjd if (error != 0) { 1238148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", prov, 1239148456Spjd strerror(error)); 1240148456Spjd return; 1241148456Spjd } 1242148456Spjd#endif 1243148456Spjd 1244213060Spjd fd = g_open(prov, 1); 1245213060Spjd if (fd == -1) { 1246213060Spjd gctl_error(req, "Cannot open provider %s: %s.", prov, 1247213060Spjd strerror(errno)); 1248213060Spjd return; 1249148456Spjd } 1250213060Spjd offset = g_mediasize(fd) - g_sectorsize(fd); 1251213060Spjd if (offset <= 0) { 1252213060Spjd gctl_error(req, 1253213060Spjd "Cannot obtain media size or sector size for provider %s: %s.", 1254213060Spjd prov, strerror(errno)); 1255213060Spjd (void)g_close(fd); 1256213060Spjd return; 1257213060Spjd } 1258213060Spjd (void)eli_trash_metadata(req, prov, fd, offset); 1259213060Spjd (void)g_close(fd); 1260148456Spjd} 1261148456Spjd 1262148456Spjdstatic void 1263148456Spjdeli_kill(struct gctl_req *req) 1264148456Spjd{ 1265148456Spjd const char *prov; 1266153190Spjd int i, nargs, all; 1267148456Spjd 1268153190Spjd nargs = gctl_get_int(req, "nargs"); 1269153190Spjd all = gctl_get_int(req, "all"); 1270153190Spjd if (!all && nargs == 0) { 1271148456Spjd gctl_error(req, "Too few arguments."); 1272148456Spjd return; 1273148456Spjd } 1274148456Spjd /* 1275148456Spjd * How '-a' option combine with a list of providers: 1276148456Spjd * Delete Master Keys from all attached providers: 1277148456Spjd * geli kill -a 1278169312Spjd * Delete Master Keys from all attached providers and from 1279148456Spjd * detached da0 and da1: 1280148456Spjd * geli kill -a da0 da1 1281148456Spjd * Delete Master Keys from (attached or detached) da0 and da1: 1282148456Spjd * geli kill da0 da1 1283148456Spjd */ 1284148456Spjd 1285169312Spjd /* First detached providers. */ 1286153190Spjd for (i = 0; i < nargs; i++) { 1287153190Spjd prov = gctl_get_ascii(req, "arg%d", i); 1288148456Spjd if (!eli_is_attached(prov)) 1289148456Spjd eli_kill_detached(req, prov); 1290148456Spjd } 1291162347Spjd /* Now attached providers. */ 1292162347Spjd gctl_issue(req); 1293148456Spjd} 1294148456Spjd 1295182452Spjdstatic int 1296182452Spjdeli_backup_create(struct gctl_req *req, const char *prov, const char *file) 1297148456Spjd{ 1298148456Spjd unsigned char *sector; 1299213059Spjd ssize_t secsize; 1300226716Spjd int error, filefd, ret; 1301148456Spjd 1302182452Spjd ret = -1; 1303226716Spjd filefd = -1; 1304148456Spjd sector = NULL; 1305148456Spjd secsize = 0; 1306148456Spjd 1307226716Spjd secsize = g_get_sectorsize(prov); 1308226716Spjd if (secsize == 0) { 1309148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1310148456Spjd strerror(errno)); 1311169193Spjd goto out; 1312148456Spjd } 1313148456Spjd sector = malloc(secsize); 1314148456Spjd if (sector == NULL) { 1315148456Spjd gctl_error(req, "Cannot allocate memory."); 1316169193Spjd goto out; 1317148456Spjd } 1318148456Spjd /* Read metadata from the provider. */ 1319226716Spjd error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC); 1320226716Spjd if (error != 0) { 1321226716Spjd gctl_error(req, "Unable to read metadata from %s: %s.", prov, 1322226716Spjd strerror(error)); 1323148456Spjd goto out; 1324148456Spjd } 1325226716Spjd 1326226716Spjd filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1327226716Spjd if (filefd == -1) { 1328226716Spjd gctl_error(req, "Unable to open %s: %s.", file, 1329226716Spjd strerror(errno)); 1330148456Spjd goto out; 1331148456Spjd } 1332148456Spjd /* Write metadata to the destination file. */ 1333213059Spjd if (write(filefd, sector, secsize) != secsize) { 1334226716Spjd gctl_error(req, "Unable to write to %s: %s.", file, 1335148456Spjd strerror(errno)); 1336226716Spjd (void)close(filefd); 1337226716Spjd (void)unlink(file); 1338148456Spjd goto out; 1339148456Spjd } 1340213059Spjd (void)fsync(filefd); 1341226716Spjd (void)close(filefd); 1342182452Spjd /* Success. */ 1343182452Spjd ret = 0; 1344148456Spjdout: 1345148456Spjd if (sector != NULL) { 1346148456Spjd bzero(sector, secsize); 1347148456Spjd free(sector); 1348148456Spjd } 1349182452Spjd return (ret); 1350148456Spjd} 1351148456Spjd 1352148456Spjdstatic void 1353182452Spjdeli_backup(struct gctl_req *req) 1354182452Spjd{ 1355182452Spjd const char *file, *prov; 1356182452Spjd int nargs; 1357182452Spjd 1358182452Spjd nargs = gctl_get_int(req, "nargs"); 1359182452Spjd if (nargs != 2) { 1360182452Spjd gctl_error(req, "Invalid number of arguments."); 1361182452Spjd return; 1362182452Spjd } 1363182452Spjd prov = gctl_get_ascii(req, "arg0"); 1364182452Spjd file = gctl_get_ascii(req, "arg1"); 1365182452Spjd 1366182452Spjd eli_backup_create(req, prov, file); 1367182452Spjd} 1368182452Spjd 1369182452Spjdstatic void 1370148456Spjdeli_restore(struct gctl_req *req) 1371148456Spjd{ 1372148456Spjd struct g_eli_metadata md; 1373148456Spjd const char *file, *prov; 1374148456Spjd off_t mediasize; 1375226716Spjd int nargs; 1376148456Spjd 1377153190Spjd nargs = gctl_get_int(req, "nargs"); 1378153190Spjd if (nargs != 2) { 1379148456Spjd gctl_error(req, "Invalid number of arguments."); 1380148456Spjd return; 1381148456Spjd } 1382153190Spjd file = gctl_get_ascii(req, "arg0"); 1383153190Spjd prov = gctl_get_ascii(req, "arg1"); 1384148456Spjd 1385226716Spjd /* Read metadata from the backup file. */ 1386226716Spjd if (eli_metadata_read(req, file, &md) == -1) 1387226716Spjd return; 1388226716Spjd /* Obtain provider's mediasize. */ 1389226716Spjd mediasize = g_get_mediasize(prov); 1390226716Spjd if (mediasize == 0) { 1391148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1392148456Spjd strerror(errno)); 1393226716Spjd return; 1394148456Spjd } 1395212934Sbrian /* Check if the provider size has changed since we did the backup. */ 1396212934Sbrian if (md.md_provsize != (uint64_t)mediasize) { 1397212934Sbrian if (gctl_get_int(req, "force")) { 1398212934Sbrian md.md_provsize = mediasize; 1399212934Sbrian } else { 1400212934Sbrian gctl_error(req, "Provider size mismatch: " 1401212934Sbrian "wrong backup file?"); 1402226716Spjd return; 1403212934Sbrian } 1404212934Sbrian } 1405226716Spjd /* Write metadata to the provider. */ 1406226716Spjd (void)eli_metadata_store(req, prov, &md); 1407148456Spjd} 1408148456Spjd 1409148456Spjdstatic void 1410212934Sbrianeli_resize(struct gctl_req *req) 1411212934Sbrian{ 1412212934Sbrian struct g_eli_metadata md; 1413212934Sbrian const char *prov; 1414212934Sbrian unsigned char *sector; 1415213056Spjd ssize_t secsize; 1416212934Sbrian off_t mediasize, oldsize; 1417212934Sbrian int nargs, provfd; 1418212934Sbrian 1419212934Sbrian nargs = gctl_get_int(req, "nargs"); 1420212934Sbrian if (nargs != 1) { 1421212934Sbrian gctl_error(req, "Invalid number of arguments."); 1422212934Sbrian return; 1423212934Sbrian } 1424212934Sbrian prov = gctl_get_ascii(req, "arg0"); 1425212934Sbrian 1426212934Sbrian provfd = -1; 1427212934Sbrian sector = NULL; 1428212934Sbrian secsize = 0; 1429212934Sbrian 1430213056Spjd provfd = g_open(prov, 1); 1431212934Sbrian if (provfd == -1) { 1432212934Sbrian gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1433212934Sbrian goto out; 1434212934Sbrian } 1435212934Sbrian 1436213056Spjd mediasize = g_mediasize(provfd); 1437213056Spjd secsize = g_sectorsize(provfd); 1438213056Spjd if (mediasize == -1 || secsize == -1) { 1439212934Sbrian gctl_error(req, "Cannot get information about %s: %s.", prov, 1440212934Sbrian strerror(errno)); 1441212934Sbrian goto out; 1442212934Sbrian } 1443212934Sbrian 1444212934Sbrian sector = malloc(secsize); 1445212934Sbrian if (sector == NULL) { 1446212934Sbrian gctl_error(req, "Cannot allocate memory."); 1447212934Sbrian goto out; 1448212934Sbrian } 1449212934Sbrian 1450212934Sbrian oldsize = gctl_get_intmax(req, "oldsize"); 1451212934Sbrian if (oldsize < 0 || oldsize > mediasize) { 1452212934Sbrian gctl_error(req, "Invalid oldsize: Out of range."); 1453212934Sbrian goto out; 1454212934Sbrian } 1455213058Spjd if (oldsize == mediasize) { 1456213058Spjd gctl_error(req, "Size hasn't changed."); 1457213058Spjd goto out; 1458213058Spjd } 1459212934Sbrian 1460212934Sbrian /* Read metadata from the 'oldsize' offset. */ 1461213056Spjd if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) { 1462212934Sbrian gctl_error(req, "Cannot read old metadata: %s.", 1463212934Sbrian strerror(errno)); 1464212934Sbrian goto out; 1465212934Sbrian } 1466212934Sbrian 1467212934Sbrian /* Check if this sector contains geli metadata. */ 1468212934Sbrian if (eli_metadata_decode(sector, &md) != 0) { 1469212934Sbrian gctl_error(req, "MD5 hash mismatch: no metadata for oldsize."); 1470212934Sbrian goto out; 1471212934Sbrian } 1472212934Sbrian 1473212934Sbrian /* 1474212934Sbrian * If the old metadata doesn't have a correct provider size, refuse 1475212934Sbrian * to resize. 1476212934Sbrian */ 1477212934Sbrian if (md.md_provsize != (uint64_t)oldsize) { 1478212934Sbrian gctl_error(req, "Provider size mismatch at oldsize."); 1479212934Sbrian goto out; 1480212934Sbrian } 1481212934Sbrian 1482212934Sbrian /* 1483212934Sbrian * Update the old metadata with the current provider size and write 1484212934Sbrian * it back to the correct place on the provider. 1485212934Sbrian */ 1486212934Sbrian md.md_provsize = mediasize; 1487212934Sbrian eli_metadata_encode(&md, sector); 1488213056Spjd if (pwrite(provfd, sector, secsize, mediasize - secsize) != secsize) { 1489212934Sbrian gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1490212934Sbrian goto out; 1491212934Sbrian } 1492213057Spjd (void)g_flush(provfd); 1493212934Sbrian 1494212934Sbrian /* Now trash the old metadata. */ 1495213060Spjd if (eli_trash_metadata(req, prov, provfd, oldsize - secsize) == -1) 1496212934Sbrian goto out; 1497212934Sbrianout: 1498213056Spjd if (provfd >= 0) 1499213056Spjd (void)g_close(provfd); 1500212934Sbrian if (sector != NULL) { 1501212934Sbrian bzero(sector, secsize); 1502212934Sbrian free(sector); 1503212934Sbrian } 1504212934Sbrian} 1505212934Sbrian 1506212934Sbrianstatic void 1507148456Spjdeli_clear(struct gctl_req *req) 1508148456Spjd{ 1509148456Spjd const char *name; 1510153190Spjd int error, i, nargs; 1511148456Spjd 1512153190Spjd nargs = gctl_get_int(req, "nargs"); 1513153190Spjd if (nargs < 1) { 1514148456Spjd gctl_error(req, "Too few arguments."); 1515148456Spjd return; 1516148456Spjd } 1517148456Spjd 1518153190Spjd for (i = 0; i < nargs; i++) { 1519153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1520148456Spjd error = g_metadata_clear(name, G_ELI_MAGIC); 1521148456Spjd if (error != 0) { 1522148456Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1523148456Spjd name, strerror(error)); 1524148456Spjd gctl_error(req, "Not fully done."); 1525148456Spjd continue; 1526148456Spjd } 1527148456Spjd if (verbose) 1528155175Spjd printf("Metadata cleared on %s.\n", name); 1529148456Spjd } 1530148456Spjd} 1531148456Spjd 1532148456Spjdstatic void 1533148456Spjdeli_dump(struct gctl_req *req) 1534148456Spjd{ 1535148456Spjd struct g_eli_metadata md, tmpmd; 1536148456Spjd const char *name; 1537153190Spjd int error, i, nargs; 1538148456Spjd 1539153190Spjd nargs = gctl_get_int(req, "nargs"); 1540153190Spjd if (nargs < 1) { 1541148456Spjd gctl_error(req, "Too few arguments."); 1542148456Spjd return; 1543148456Spjd } 1544148456Spjd 1545153190Spjd for (i = 0; i < nargs; i++) { 1546153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1547148456Spjd error = g_metadata_read(name, (unsigned char *)&tmpmd, 1548148456Spjd sizeof(tmpmd), G_ELI_MAGIC); 1549148456Spjd if (error != 0) { 1550148456Spjd fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1551148456Spjd name, strerror(error)); 1552148456Spjd gctl_error(req, "Not fully done."); 1553148456Spjd continue; 1554148456Spjd } 1555148456Spjd if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1556148456Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1557148456Spjd name); 1558148456Spjd gctl_error(req, "Not fully done."); 1559148456Spjd continue; 1560148456Spjd } 1561148456Spjd printf("Metadata on %s:\n", name); 1562148456Spjd eli_metadata_dump(&md); 1563148456Spjd printf("\n"); 1564148456Spjd } 1565148456Spjd} 1566