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$"); 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); 75226723Spjdstatic void eli_version(struct gctl_req *req); 76148456Spjdstatic void eli_clear(struct gctl_req *req); 77148456Spjdstatic void eli_dump(struct gctl_req *req); 78148456Spjd 79182452Spjdstatic int eli_backup_create(struct gctl_req *req, const char *prov, 80182452Spjd const char *file); 81182452Spjd 82148456Spjd/* 83148456Spjd * Available commands: 84148456Spjd * 85226733Spjd * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-V version] prov 86148456Spjd * label - alias for 'init' 87213172Spjd * attach [-dprv] [-j passfile] [-k keyfile] prov 88148456Spjd * detach [-fl] prov ... 89148456Spjd * stop - alias for 'detach' 90181639Spjd * onetime [-d] [-a aalgo] [-e ealgo] [-l keylen] prov 91162353Spjd * configure [-bB] prov ... 92213172Spjd * setkey [-pPv] [-n keyno] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov 93148456Spjd * delkey [-afv] [-n keyno] prov 94214118Spjd * suspend [-v] -a | prov ... 95214118Spjd * resume [-pv] [-j passfile] [-k keyfile] prov 96148456Spjd * kill [-av] [prov ...] 97148456Spjd * backup [-v] prov file 98212934Sbrian * restore [-fv] file prov 99212934Sbrian * resize [-v] -s oldsize prov 100226723Spjd * version [prov ...] 101148456Spjd * clear [-v] prov ... 102148456Spjd * dump [-v] prov ... 103148456Spjd */ 104148456Spjdstruct g_command class_commands[] = { 105148456Spjd { "init", G_FLAG_VERBOSE, eli_main, 106148456Spjd { 107212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 108162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 109212547Spjd { 'B', "backupfile", "", G_TYPE_STRING }, 110226733Spjd { 'e', "ealgo", "", G_TYPE_STRING }, 111212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 112213172Spjd { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 113213172Spjd { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 114212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 115162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 116212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 117226733Spjd { 'V', "mdversion", "-1", G_TYPE_NUMBER }, 118148456Spjd G_OPT_SENTINEL 119148456Spjd }, 120226733Spjd "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-J newpassfile] [-K newkeyfile] [-s sectorsize] [-V version] prov" 121148456Spjd }, 122148456Spjd { "label", G_FLAG_VERBOSE, eli_main, 123148456Spjd { 124212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 125162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 126212547Spjd { 'B', "backupfile", "", G_TYPE_STRING }, 127226733Spjd { 'e', "ealgo", "", G_TYPE_STRING }, 128212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 129213172Spjd { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 130213172Spjd { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 131212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 132162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 133212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 134226733Spjd { 'V', "mdversion", "-1", G_TYPE_NUMBER }, 135148456Spjd G_OPT_SENTINEL 136148456Spjd }, 137212554Spjd "- an alias for 'init'" 138148456Spjd }, 139148456Spjd { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 140148456Spjd { 141162868Spjd { 'd', "detach", NULL, G_TYPE_BOOL }, 142213172Spjd { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 143213172Spjd { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 144162868Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 145162868Spjd { 'r', "readonly", NULL, G_TYPE_BOOL }, 146148456Spjd G_OPT_SENTINEL 147148456Spjd }, 148213172Spjd "[-dprv] [-j passfile] [-k keyfile] prov" 149148456Spjd }, 150148456Spjd { "detach", 0, NULL, 151148456Spjd { 152162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 153162868Spjd { 'l', "last", NULL, G_TYPE_BOOL }, 154148456Spjd G_OPT_SENTINEL 155148456Spjd }, 156212554Spjd "[-fl] prov ..." 157148456Spjd }, 158148456Spjd { "stop", 0, NULL, 159148456Spjd { 160162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 161162868Spjd { 'l', "last", NULL, G_TYPE_BOOL }, 162148456Spjd G_OPT_SENTINEL 163148456Spjd }, 164212554Spjd "- an alias for 'detach'" 165148456Spjd }, 166148456Spjd { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 167148456Spjd { 168212547Spjd { 'a', "aalgo", "", G_TYPE_STRING }, 169162868Spjd { 'd', "detach", NULL, G_TYPE_BOOL }, 170212547Spjd { 'e', "ealgo", GELI_ENC_ALGO, G_TYPE_STRING }, 171212554Spjd { 'l', "keylen", "0", G_TYPE_NUMBER }, 172212554Spjd { 's', "sectorsize", "0", G_TYPE_NUMBER }, 173148456Spjd G_OPT_SENTINEL 174148456Spjd }, 175212554Spjd "[-d] [-a aalgo] [-e ealgo] [-l keylen] [-s sectorsize] prov" 176148456Spjd }, 177162353Spjd { "configure", G_FLAG_VERBOSE, eli_main, 178162353Spjd { 179162868Spjd { 'b', "boot", NULL, G_TYPE_BOOL }, 180162868Spjd { 'B', "noboot", NULL, G_TYPE_BOOL }, 181162353Spjd G_OPT_SENTINEL 182162353Spjd }, 183212554Spjd "[-bB] prov ..." 184162353Spjd }, 185148456Spjd { "setkey", G_FLAG_VERBOSE, eli_main, 186148456Spjd { 187212554Spjd { 'i', "iterations", "-1", G_TYPE_NUMBER }, 188213172Spjd { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 189213172Spjd { 'J', "newpassfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 190213172Spjd { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 191213172Spjd { 'K', "newkeyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 192212554Spjd { 'n', "keyno", "-1", G_TYPE_NUMBER }, 193162868Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 194162868Spjd { 'P', "nonewpassphrase", NULL, G_TYPE_BOOL }, 195148456Spjd G_OPT_SENTINEL 196148456Spjd }, 197213172Spjd "[-pPv] [-n keyno] [-i iterations] [-j passfile] [-J newpassfile] [-k keyfile] [-K newkeyfile] prov" 198148456Spjd }, 199148456Spjd { "delkey", G_FLAG_VERBOSE, eli_main, 200148456Spjd { 201162868Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 202162868Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 203212554Spjd { 'n', "keyno", "-1", G_TYPE_NUMBER }, 204148456Spjd G_OPT_SENTINEL 205148456Spjd }, 206212554Spjd "[-afv] [-n keyno] prov" 207148456Spjd }, 208214118Spjd { "suspend", G_FLAG_VERBOSE, NULL, 209214118Spjd { 210214118Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 211214118Spjd G_OPT_SENTINEL 212214118Spjd }, 213214118Spjd "[-v] -a | prov ..." 214214118Spjd }, 215214118Spjd { "resume", G_FLAG_VERBOSE, eli_main, 216214118Spjd { 217214118Spjd { 'j', "passfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 218214118Spjd { 'k', "keyfile", G_VAL_OPTIONAL, G_TYPE_STRING | G_TYPE_MULTI }, 219214118Spjd { 'p', "nopassphrase", NULL, G_TYPE_BOOL }, 220214118Spjd G_OPT_SENTINEL 221214118Spjd }, 222214118Spjd "[-pv] [-j passfile] [-k keyfile] prov" 223214118Spjd }, 224148456Spjd { "kill", G_FLAG_VERBOSE, eli_main, 225148456Spjd { 226162868Spjd { 'a', "all", NULL, G_TYPE_BOOL }, 227148456Spjd G_OPT_SENTINEL 228148456Spjd }, 229212554Spjd "[-av] [prov ...]" 230148456Spjd }, 231212554Spjd { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 232148456Spjd "[-v] prov file" 233148456Spjd }, 234212934Sbrian { "restore", G_FLAG_VERBOSE, eli_main, 235212934Sbrian { 236212934Sbrian { 'f', "force", NULL, G_TYPE_BOOL }, 237212934Sbrian G_OPT_SENTINEL 238212934Sbrian }, 239212934Sbrian "[-fv] file prov" 240148456Spjd }, 241212934Sbrian { "resize", G_FLAG_VERBOSE, eli_main, 242212934Sbrian { 243212934Sbrian { 's', "oldsize", NULL, G_TYPE_NUMBER }, 244212934Sbrian G_OPT_SENTINEL 245212934Sbrian }, 246212934Sbrian "[-v] -s oldsize prov" 247212934Sbrian }, 248226723Spjd { "version", G_FLAG_LOADKLD, eli_main, G_NULL_OPTS, 249226723Spjd "[prov ...]" 250226723Spjd }, 251212554Spjd { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 252148456Spjd "[-v] prov ..." 253148456Spjd }, 254212554Spjd { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 255148456Spjd "[-v] prov ..." 256148456Spjd }, 257148456Spjd G_CMD_SENTINEL 258148456Spjd}; 259148456Spjd 260148456Spjdstatic int verbose = 0; 261148456Spjd 262248475Spjd#define BUFSIZE 1024 263248475Spjd 264148456Spjdstatic int 265148456Spjdeli_protect(struct gctl_req *req) 266148456Spjd{ 267148456Spjd struct rlimit rl; 268148456Spjd 269148456Spjd /* Disable core dumps. */ 270148456Spjd rl.rlim_cur = 0; 271148456Spjd rl.rlim_max = 0; 272148456Spjd if (setrlimit(RLIMIT_CORE, &rl) == -1) { 273148456Spjd gctl_error(req, "Cannot disable core dumps: %s.", 274148456Spjd strerror(errno)); 275148456Spjd return (-1); 276148456Spjd } 277148456Spjd /* Disable swapping. */ 278148456Spjd if (mlockall(MCL_FUTURE) == -1) { 279148456Spjd gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 280148456Spjd return (-1); 281148456Spjd } 282148456Spjd return (0); 283148456Spjd} 284148456Spjd 285148456Spjdstatic void 286213172Spjdeli_main(struct gctl_req *req, unsigned int flags) 287148456Spjd{ 288148456Spjd const char *name; 289148456Spjd 290148456Spjd if (eli_protect(req) == -1) 291148456Spjd return; 292148456Spjd 293148456Spjd if ((flags & G_FLAG_VERBOSE) != 0) 294148456Spjd verbose = 1; 295148456Spjd 296153190Spjd name = gctl_get_ascii(req, "verb"); 297148456Spjd if (name == NULL) { 298148456Spjd gctl_error(req, "No '%s' argument.", "verb"); 299148456Spjd return; 300148456Spjd } 301148456Spjd if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 302148456Spjd eli_init(req); 303148456Spjd else if (strcmp(name, "attach") == 0) 304148456Spjd eli_attach(req); 305162353Spjd else if (strcmp(name, "configure") == 0) 306162353Spjd eli_configure(req); 307148456Spjd else if (strcmp(name, "setkey") == 0) 308148456Spjd eli_setkey(req); 309148456Spjd else if (strcmp(name, "delkey") == 0) 310148456Spjd eli_delkey(req); 311214118Spjd else if (strcmp(name, "resume") == 0) 312214118Spjd eli_resume(req); 313148456Spjd else if (strcmp(name, "kill") == 0) 314148456Spjd eli_kill(req); 315148456Spjd else if (strcmp(name, "backup") == 0) 316148456Spjd eli_backup(req); 317148456Spjd else if (strcmp(name, "restore") == 0) 318148456Spjd eli_restore(req); 319212934Sbrian else if (strcmp(name, "resize") == 0) 320212934Sbrian eli_resize(req); 321226723Spjd else if (strcmp(name, "version") == 0) 322226723Spjd eli_version(req); 323148456Spjd else if (strcmp(name, "dump") == 0) 324148456Spjd eli_dump(req); 325148456Spjd else if (strcmp(name, "clear") == 0) 326148456Spjd eli_clear(req); 327148456Spjd else 328148456Spjd gctl_error(req, "Unknown command: %s.", name); 329148456Spjd} 330148456Spjd 331226717Spjdstatic bool 332148456Spjdeli_is_attached(const char *prov) 333148456Spjd{ 334148456Spjd char name[MAXPATHLEN]; 335148456Spjd 336148456Spjd /* 337148456Spjd * Not the best way to do it, but the easiest. 338148456Spjd * We try to open provider and check if it is a GEOM provider 339148456Spjd * by asking about its sectorsize. 340148456Spjd */ 341148456Spjd snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 342226717Spjd return (g_get_sectorsize(name) > 0); 343148456Spjd} 344148456Spjd 345213172Spjdstatic int 346213172Spjdeli_genkey_files(struct gctl_req *req, bool new, const char *type, 347213172Spjd struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize) 348148456Spjd{ 349248475Spjd char *p, buf[BUFSIZE], argname[16]; 350213172Spjd const char *file; 351213172Spjd int error, fd, i; 352213172Spjd ssize_t done; 353148456Spjd 354213172Spjd assert((strcmp(type, "keyfile") == 0 && ctxp != NULL && 355213172Spjd passbuf == NULL && passbufsize == 0) || 356213172Spjd (strcmp(type, "passfile") == 0 && ctxp == NULL && 357213172Spjd passbuf != NULL && passbufsize > 0)); 358213172Spjd assert(strcmp(type, "keyfile") == 0 || passbuf[0] == '\0'); 359148456Spjd 360213172Spjd for (i = 0; ; i++) { 361213172Spjd snprintf(argname, sizeof(argname), "%s%s%d", 362213172Spjd new ? "new" : "", type, i); 363148456Spjd 364213172Spjd /* No more {key,pass}files? */ 365213172Spjd if (!gctl_has_param(req, argname)) 366213172Spjd return (i); 367148456Spjd 368215704Sbrucec file = gctl_get_ascii(req, "%s", argname); 369213172Spjd assert(file != NULL); 370213172Spjd 371213172Spjd if (strcmp(file, "-") == 0) 372148456Spjd fd = STDIN_FILENO; 373148456Spjd else { 374213172Spjd fd = open(file, O_RDONLY); 375148456Spjd if (fd == -1) { 376213172Spjd gctl_error(req, "Cannot open %s %s: %s.", 377213172Spjd type, file, strerror(errno)); 378213172Spjd return (-1); 379148456Spjd } 380148456Spjd } 381213172Spjd if (strcmp(type, "keyfile") == 0) { 382213172Spjd while ((done = read(fd, buf, sizeof(buf))) > 0) 383213172Spjd g_eli_crypto_hmac_update(ctxp, buf, done); 384213172Spjd } else /* if (strcmp(type, "passfile") == 0) */ { 385246621Spjd assert(strcmp(type, "passfile") == 0); 386246621Spjd 387213172Spjd while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) { 388213172Spjd buf[done] = '\0'; 389213172Spjd p = strchr(buf, '\n'); 390213172Spjd if (p != NULL) { 391213172Spjd *p = '\0'; 392213172Spjd done = p - buf; 393213172Spjd } 394213172Spjd if (strlcat(passbuf, buf, passbufsize) >= 395213172Spjd passbufsize) { 396213172Spjd gctl_error(req, 397213172Spjd "Passphrase in %s too long.", file); 398213172Spjd bzero(buf, sizeof(buf)); 399213172Spjd return (-1); 400213172Spjd } 401213172Spjd if (p != NULL) 402213172Spjd break; 403213172Spjd } 404213172Spjd } 405148456Spjd error = errno; 406213172Spjd if (strcmp(file, "-") != 0) 407148456Spjd close(fd); 408148456Spjd bzero(buf, sizeof(buf)); 409148456Spjd if (done == -1) { 410213172Spjd gctl_error(req, "Cannot read %s %s: %s.", 411213172Spjd type, file, strerror(error)); 412213172Spjd return (-1); 413148456Spjd } 414148456Spjd } 415213172Spjd /* NOTREACHED */ 416213172Spjd} 417148456Spjd 418213172Spjdstatic int 419213172Spjdeli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf, 420213172Spjd size_t passbufsize) 421213172Spjd{ 422213172Spjd char *p; 423148456Spjd 424213172Spjd for (;;) { 425213172Spjd p = readpassphrase( 426213172Spjd new ? "Enter new passphrase:" : "Enter passphrase:", 427213172Spjd passbuf, passbufsize, RPP_ECHO_OFF | RPP_REQUIRE_TTY); 428213172Spjd if (p == NULL) { 429213172Spjd bzero(passbuf, passbufsize); 430213172Spjd gctl_error(req, "Cannot read passphrase: %s.", 431213172Spjd strerror(errno)); 432213172Spjd return (-1); 433149047Spjd } 434213172Spjd 435213172Spjd if (new) { 436248475Spjd char tmpbuf[BUFSIZE]; 437213172Spjd 438213172Spjd p = readpassphrase("Reenter new passphrase: ", 439213172Spjd tmpbuf, sizeof(tmpbuf), 440213172Spjd RPP_ECHO_OFF | RPP_REQUIRE_TTY); 441148456Spjd if (p == NULL) { 442213172Spjd bzero(passbuf, passbufsize); 443213172Spjd gctl_error(req, 444213172Spjd "Cannot read passphrase: %s.", 445148456Spjd strerror(errno)); 446213172Spjd return (-1); 447148456Spjd } 448213172Spjd 449213172Spjd if (strcmp(passbuf, tmpbuf) != 0) { 450213172Spjd bzero(passbuf, passbufsize); 451213172Spjd fprintf(stderr, "They didn't match.\n"); 452213172Spjd continue; 453148456Spjd } 454213172Spjd bzero(tmpbuf, sizeof(tmpbuf)); 455148456Spjd } 456213172Spjd return (0); 457213172Spjd } 458213172Spjd /* NOTREACHED */ 459213172Spjd} 460213172Spjd 461213172Spjdstatic int 462213172Spjdeli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new, 463213172Spjd struct hmac_ctx *ctxp) 464213172Spjd{ 465248475Spjd char passbuf[BUFSIZE]; 466213172Spjd bool nopassphrase; 467213172Spjd int nfiles; 468213172Spjd 469213172Spjd nopassphrase = 470213172Spjd gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 471213172Spjd if (nopassphrase) { 472213172Spjd if (gctl_has_param(req, new ? "newpassfile0" : "passfile0")) { 473213172Spjd gctl_error(req, 474213172Spjd "Options -%c and -%c are mutually exclusive.", 475213172Spjd new ? 'J' : 'j', new ? 'P' : 'p'); 476213172Spjd return (-1); 477148456Spjd } 478213172Spjd return (0); 479213172Spjd } 480148456Spjd 481213172Spjd if (!new && md->md_iterations == -1) { 482213172Spjd gctl_error(req, "Missing -p flag."); 483213172Spjd return (-1); 484213172Spjd } 485213172Spjd passbuf[0] = '\0'; 486213172Spjd nfiles = eli_genkey_files(req, new, "passfile", NULL, passbuf, 487213172Spjd sizeof(passbuf)); 488213172Spjd if (nfiles == -1) 489213172Spjd return (-1); 490213172Spjd else if (nfiles == 0) { 491213172Spjd if (eli_genkey_passphrase_prompt(req, new, passbuf, 492213172Spjd sizeof(passbuf)) == -1) { 493213172Spjd return (-1); 494148456Spjd } 495148456Spjd } 496213172Spjd /* 497213172Spjd * Field md_iterations equal to -1 means "choose some sane 498213172Spjd * value for me". 499213172Spjd */ 500213172Spjd if (md->md_iterations == -1) { 501213172Spjd assert(new); 502213172Spjd if (verbose) 503213172Spjd printf("Calculating number of iterations...\n"); 504213172Spjd md->md_iterations = pkcs5v2_calculate(2000000); 505213172Spjd assert(md->md_iterations > 0); 506213172Spjd if (verbose) { 507213172Spjd printf("Done, using %d iterations.\n", 508213172Spjd md->md_iterations); 509213172Spjd } 510213172Spjd } 511213172Spjd /* 512213172Spjd * If md_iterations is equal to 0, user doesn't want PKCS#5v2. 513213172Spjd */ 514213172Spjd if (md->md_iterations == 0) { 515213172Spjd g_eli_crypto_hmac_update(ctxp, md->md_salt, 516213172Spjd sizeof(md->md_salt)); 517213172Spjd g_eli_crypto_hmac_update(ctxp, passbuf, strlen(passbuf)); 518213172Spjd } else /* if (md->md_iterations > 0) */ { 519213172Spjd unsigned char dkey[G_ELI_USERKEYLEN]; 520213172Spjd 521213172Spjd pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 522213172Spjd sizeof(md->md_salt), passbuf, md->md_iterations); 523213172Spjd g_eli_crypto_hmac_update(ctxp, dkey, sizeof(dkey)); 524213172Spjd bzero(dkey, sizeof(dkey)); 525213172Spjd } 526213172Spjd bzero(passbuf, sizeof(passbuf)); 527213172Spjd 528213172Spjd return (0); 529213172Spjd} 530213172Spjd 531213172Spjdstatic unsigned char * 532213172Spjdeli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 533213172Spjd bool new) 534213172Spjd{ 535213172Spjd struct hmac_ctx ctx; 536213172Spjd bool nopassphrase; 537213172Spjd int nfiles; 538213172Spjd 539213172Spjd nopassphrase = 540213172Spjd gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 541213172Spjd 542213172Spjd g_eli_crypto_hmac_init(&ctx, NULL, 0); 543213172Spjd 544213172Spjd nfiles = eli_genkey_files(req, new, "keyfile", &ctx, NULL, 0); 545213172Spjd if (nfiles == -1) 546213172Spjd return (NULL); 547213172Spjd else if (nfiles == 0 && nopassphrase) { 548213172Spjd gctl_error(req, "No key components given."); 549213172Spjd return (NULL); 550213172Spjd } 551213172Spjd 552213172Spjd if (eli_genkey_passphrase(req, md, new, &ctx) == -1) 553213172Spjd return (NULL); 554213172Spjd 555148456Spjd g_eli_crypto_hmac_final(&ctx, key, 0); 556213172Spjd 557148456Spjd return (key); 558148456Spjd} 559148456Spjd 560148456Spjdstatic int 561148456Spjdeli_metadata_read(struct gctl_req *req, const char *prov, 562148456Spjd struct g_eli_metadata *md) 563148456Spjd{ 564148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 565148456Spjd int error; 566148456Spjd 567148456Spjd if (g_get_sectorsize(prov) == 0) { 568148456Spjd int fd; 569148456Spjd 570148456Spjd /* This is a file probably. */ 571148456Spjd fd = open(prov, O_RDONLY); 572148456Spjd if (fd == -1) { 573148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 574148456Spjd strerror(errno)); 575148456Spjd return (-1); 576148456Spjd } 577148456Spjd if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 578148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 579148456Spjd prov, strerror(errno)); 580148456Spjd close(fd); 581148456Spjd return (-1); 582148456Spjd } 583148456Spjd close(fd); 584148456Spjd } else { 585148456Spjd /* This is a GEOM provider. */ 586148456Spjd error = g_metadata_read(prov, sector, sizeof(sector), 587148456Spjd G_ELI_MAGIC); 588148456Spjd if (error != 0) { 589148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", 590148456Spjd prov, strerror(error)); 591148456Spjd return (-1); 592148456Spjd } 593148456Spjd } 594226722Spjd error = eli_metadata_decode(sector, md); 595226722Spjd switch (error) { 596226722Spjd case 0: 597226722Spjd break; 598226722Spjd case EOPNOTSUPP: 599226722Spjd gctl_error(req, 600226722Spjd "Provider's %s metadata version %u is too new.\n" 601226722Spjd "geli: The highest supported version is %u.", 602226722Spjd prov, (unsigned int)md->md_version, G_ELI_VERSION); 603148456Spjd return (-1); 604226722Spjd case EINVAL: 605226722Spjd gctl_error(req, "Inconsistent provider's %s metadata.", prov); 606226722Spjd return (-1); 607226722Spjd default: 608226722Spjd gctl_error(req, 609226722Spjd "Unexpected error while decoding provider's %s metadata: %s.", 610226722Spjd prov, strerror(error)); 611226722Spjd return (-1); 612148456Spjd } 613148456Spjd return (0); 614148456Spjd} 615148456Spjd 616148456Spjdstatic int 617148456Spjdeli_metadata_store(struct gctl_req *req, const char *prov, 618148456Spjd struct g_eli_metadata *md) 619148456Spjd{ 620148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 621148456Spjd int error; 622148456Spjd 623148456Spjd eli_metadata_encode(md, sector); 624148456Spjd if (g_get_sectorsize(prov) == 0) { 625148456Spjd int fd; 626148456Spjd 627148456Spjd /* This is a file probably. */ 628148456Spjd fd = open(prov, O_WRONLY | O_TRUNC); 629148456Spjd if (fd == -1) { 630148456Spjd gctl_error(req, "Cannot open %s: %s.", prov, 631148456Spjd strerror(errno)); 632148456Spjd bzero(sector, sizeof(sector)); 633148456Spjd return (-1); 634148456Spjd } 635148456Spjd if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 636148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 637148456Spjd prov, strerror(errno)); 638148456Spjd bzero(sector, sizeof(sector)); 639148456Spjd close(fd); 640148456Spjd return (-1); 641148456Spjd } 642148456Spjd close(fd); 643148456Spjd } else { 644148456Spjd /* This is a GEOM provider. */ 645148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 646148456Spjd if (error != 0) { 647148456Spjd gctl_error(req, "Cannot write metadata to %s: %s.", 648148456Spjd prov, strerror(errno)); 649148456Spjd bzero(sector, sizeof(sector)); 650148456Spjd return (-1); 651148456Spjd } 652148456Spjd } 653148456Spjd bzero(sector, sizeof(sector)); 654148456Spjd return (0); 655148456Spjd} 656148456Spjd 657148456Spjdstatic void 658148456Spjdeli_init(struct gctl_req *req) 659148456Spjd{ 660148456Spjd struct g_eli_metadata md; 661148456Spjd unsigned char sector[sizeof(struct g_eli_metadata)]; 662148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 663182452Spjd char backfile[MAXPATHLEN]; 664148456Spjd const char *str, *prov; 665226733Spjd unsigned int secsize, version; 666148456Spjd off_t mediasize; 667153190Spjd intmax_t val; 668155536Spjd int error, nargs; 669148456Spjd 670153190Spjd nargs = gctl_get_int(req, "nargs"); 671153190Spjd if (nargs != 1) { 672158214Spjd gctl_error(req, "Invalid number of arguments."); 673148456Spjd return; 674148456Spjd } 675153190Spjd prov = gctl_get_ascii(req, "arg0"); 676148456Spjd mediasize = g_get_mediasize(prov); 677148456Spjd secsize = g_get_sectorsize(prov); 678148456Spjd if (mediasize == 0 || secsize == 0) { 679148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 680148456Spjd strerror(errno)); 681148456Spjd return; 682148456Spjd } 683148456Spjd 684148456Spjd bzero(&md, sizeof(md)); 685148456Spjd strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 686226733Spjd val = gctl_get_intmax(req, "mdversion"); 687226733Spjd if (val == -1) { 688226733Spjd version = G_ELI_VERSION; 689226733Spjd } else if (val < 0 || val > G_ELI_VERSION) { 690226733Spjd gctl_error(req, 691226733Spjd "Invalid version specified should be between %u and %u.", 692226733Spjd G_ELI_VERSION_00, G_ELI_VERSION); 693226733Spjd return; 694226733Spjd } else { 695226733Spjd version = val; 696226733Spjd } 697226733Spjd md.md_version = version; 698148456Spjd md.md_flags = 0; 699155536Spjd if (gctl_get_int(req, "boot")) 700148456Spjd md.md_flags |= G_ELI_FLAG_BOOT; 701159361Spjd md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1; 702159308Spjd str = gctl_get_ascii(req, "aalgo"); 703212547Spjd if (*str != '\0') { 704226733Spjd if (version < G_ELI_VERSION_01) { 705226733Spjd gctl_error(req, 706226733Spjd "Data authentication is supported starting from version %u.", 707226733Spjd G_ELI_VERSION_01); 708226733Spjd return; 709226733Spjd } 710159308Spjd md.md_aalgo = g_eli_str2aalgo(str); 711159361Spjd if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && 712159361Spjd md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { 713159361Spjd md.md_flags |= G_ELI_FLAG_AUTH; 714159361Spjd } else { 715159361Spjd /* 716159361Spjd * For backward compatibility, check if the -a option 717159361Spjd * was used to provide encryption algorithm. 718159361Spjd */ 719159361Spjd md.md_ealgo = g_eli_str2ealgo(str); 720159361Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 721159361Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 722159361Spjd gctl_error(req, 723159361Spjd "Invalid authentication algorithm."); 724159361Spjd return; 725159361Spjd } else { 726159361Spjd fprintf(stderr, "warning: The -e option, not " 727159361Spjd "the -a option is now used to specify " 728159361Spjd "encryption algorithm to use.\n"); 729159361Spjd } 730159308Spjd } 731159308Spjd } 732159308Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 733159308Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 734159361Spjd str = gctl_get_ascii(req, "ealgo"); 735226733Spjd if (*str == '\0') { 736226733Spjd if (version < G_ELI_VERSION_05) 737226733Spjd str = "aes-cbc"; 738226733Spjd else 739226733Spjd str = GELI_ENC_ALGO; 740226733Spjd } 741159361Spjd md.md_ealgo = g_eli_str2ealgo(str); 742159361Spjd if (md.md_ealgo < CRYPTO_ALGORITHM_MIN || 743159361Spjd md.md_ealgo > CRYPTO_ALGORITHM_MAX) { 744159361Spjd gctl_error(req, "Invalid encryption algorithm."); 745159361Spjd return; 746159361Spjd } 747226733Spjd if (md.md_ealgo == CRYPTO_CAMELLIA_CBC && 748226733Spjd version < G_ELI_VERSION_04) { 749226733Spjd gctl_error(req, 750226733Spjd "Camellia-CBC algorithm is supported starting from version %u.", 751226733Spjd G_ELI_VERSION_04); 752226733Spjd return; 753226733Spjd } 754226733Spjd if (md.md_ealgo == CRYPTO_AES_XTS && 755226733Spjd version < G_ELI_VERSION_05) { 756226733Spjd gctl_error(req, 757226733Spjd "AES-XTS algorithm is supported starting from version %u.", 758226733Spjd G_ELI_VERSION_05); 759226733Spjd return; 760226733Spjd } 761148456Spjd } 762153190Spjd val = gctl_get_intmax(req, "keylen"); 763153190Spjd md.md_keylen = val; 764159308Spjd md.md_keylen = g_eli_keylen(md.md_ealgo, md.md_keylen); 765148456Spjd if (md.md_keylen == 0) { 766148456Spjd gctl_error(req, "Invalid key length."); 767148456Spjd return; 768148456Spjd } 769148456Spjd md.md_provsize = mediasize; 770148456Spjd 771153190Spjd val = gctl_get_intmax(req, "iterations"); 772155536Spjd if (val != -1) { 773155536Spjd int nonewpassphrase; 774155536Spjd 775155536Spjd /* 776155536Spjd * Don't allow to set iterations when there will be no 777155536Spjd * passphrase. 778155536Spjd */ 779155536Spjd nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 780155536Spjd if (nonewpassphrase) { 781155536Spjd gctl_error(req, 782155536Spjd "Options -i and -P are mutually exclusive."); 783155536Spjd return; 784155536Spjd } 785155536Spjd } 786153190Spjd md.md_iterations = val; 787148456Spjd 788153190Spjd val = gctl_get_intmax(req, "sectorsize"); 789153190Spjd if (val == 0) 790148456Spjd md.md_sectorsize = secsize; 791148456Spjd else { 792153190Spjd if (val < 0 || (val % secsize) != 0) { 793148456Spjd gctl_error(req, "Invalid sector size."); 794148456Spjd return; 795148456Spjd } 796167229Spjd if (val > sysconf(_SC_PAGE_SIZE)) { 797214404Spjd fprintf(stderr, 798214404Spjd "warning: Using sectorsize bigger than the page size!\n"); 799167229Spjd } 800153190Spjd md.md_sectorsize = val; 801148456Spjd } 802148456Spjd 803148456Spjd md.md_keys = 0x01; 804246620Spjd arc4random_buf(md.md_salt, sizeof(md.md_salt)); 805246620Spjd arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys)); 806148456Spjd 807148456Spjd /* Generate user key. */ 808213172Spjd if (eli_genkey(req, &md, key, true) == NULL) { 809148456Spjd bzero(key, sizeof(key)); 810148456Spjd bzero(&md, sizeof(md)); 811148456Spjd return; 812148456Spjd } 813148456Spjd 814148456Spjd /* Encrypt the first and the only Master Key. */ 815159308Spjd error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, md.md_mkeys); 816148456Spjd bzero(key, sizeof(key)); 817148456Spjd if (error != 0) { 818148456Spjd bzero(&md, sizeof(md)); 819148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 820148456Spjd strerror(error)); 821148456Spjd return; 822148456Spjd } 823148456Spjd 824148456Spjd eli_metadata_encode(&md, sector); 825148456Spjd bzero(&md, sizeof(md)); 826148456Spjd error = g_metadata_store(prov, sector, sizeof(sector)); 827148456Spjd bzero(sector, sizeof(sector)); 828148456Spjd if (error != 0) { 829148456Spjd gctl_error(req, "Cannot store metadata on %s: %s.", prov, 830148456Spjd strerror(error)); 831148456Spjd return; 832148456Spjd } 833148456Spjd if (verbose) 834148456Spjd printf("Metadata value stored on %s.\n", prov); 835182452Spjd /* Backup metadata to a file. */ 836182452Spjd str = gctl_get_ascii(req, "backupfile"); 837182452Spjd if (str[0] != '\0') { 838182452Spjd /* Backupfile given be the user, just copy it. */ 839182452Spjd strlcpy(backfile, str, sizeof(backfile)); 840182452Spjd } else { 841182452Spjd /* Generate file name automatically. */ 842182452Spjd const char *p = prov; 843182452Spjd unsigned int i; 844182452Spjd 845213662Sae if (strncmp(p, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 846213662Sae p += sizeof(_PATH_DEV) - 1; 847182452Spjd snprintf(backfile, sizeof(backfile), "%s%s.eli", 848182452Spjd GELI_BACKUP_DIR, p); 849182452Spjd /* Replace all / with _. */ 850182452Spjd for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { 851182452Spjd if (backfile[i] == '/') 852182452Spjd backfile[i] = '_'; 853182452Spjd } 854182452Spjd } 855182452Spjd if (strcmp(backfile, "none") != 0 && 856182452Spjd eli_backup_create(req, prov, backfile) == 0) { 857182452Spjd printf("\nMetadata backup can be found in %s and\n", backfile); 858182452Spjd printf("can be restored with the following command:\n"); 859182452Spjd printf("\n\t# geli restore %s %s\n\n", backfile, prov); 860182452Spjd } 861148456Spjd} 862148456Spjd 863148456Spjdstatic void 864148456Spjdeli_attach(struct gctl_req *req) 865148456Spjd{ 866148456Spjd struct g_eli_metadata md; 867148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 868148456Spjd const char *prov; 869212934Sbrian off_t mediasize; 870153190Spjd int nargs; 871148456Spjd 872153190Spjd nargs = gctl_get_int(req, "nargs"); 873153190Spjd if (nargs != 1) { 874158214Spjd gctl_error(req, "Invalid number of arguments."); 875148456Spjd return; 876148456Spjd } 877153190Spjd prov = gctl_get_ascii(req, "arg0"); 878148456Spjd 879148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 880148456Spjd return; 881148456Spjd 882212934Sbrian mediasize = g_get_mediasize(prov); 883212934Sbrian if (md.md_provsize != (uint64_t)mediasize) { 884212934Sbrian gctl_error(req, "Provider size mismatch."); 885212934Sbrian return; 886212934Sbrian } 887212934Sbrian 888213172Spjd if (eli_genkey(req, &md, key, false) == NULL) { 889148456Spjd bzero(key, sizeof(key)); 890148456Spjd return; 891148456Spjd } 892148456Spjd 893148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 894148456Spjd if (gctl_issue(req) == NULL) { 895148456Spjd if (verbose) 896166892Spjd printf("Attached to %s.\n", prov); 897148456Spjd } 898148456Spjd bzero(key, sizeof(key)); 899148456Spjd} 900148456Spjd 901148456Spjdstatic void 902213172Spjdeli_configure_detached(struct gctl_req *req, const char *prov, bool boot) 903162353Spjd{ 904162353Spjd struct g_eli_metadata md; 905162353Spjd 906162353Spjd if (eli_metadata_read(req, prov, &md) == -1) 907162353Spjd return; 908162353Spjd 909162353Spjd if (boot && (md.md_flags & G_ELI_FLAG_BOOT)) { 910162353Spjd if (verbose) 911162353Spjd printf("BOOT flag already configured for %s.\n", prov); 912162353Spjd } else if (!boot && !(md.md_flags & G_ELI_FLAG_BOOT)) { 913162353Spjd if (verbose) 914162353Spjd printf("BOOT flag not configured for %s.\n", prov); 915162353Spjd } else { 916162353Spjd if (boot) 917162353Spjd md.md_flags |= G_ELI_FLAG_BOOT; 918162353Spjd else 919162353Spjd md.md_flags &= ~G_ELI_FLAG_BOOT; 920162353Spjd eli_metadata_store(req, prov, &md); 921162353Spjd } 922162353Spjd bzero(&md, sizeof(md)); 923162353Spjd} 924162353Spjd 925162353Spjdstatic void 926162353Spjdeli_configure(struct gctl_req *req) 927162353Spjd{ 928162353Spjd const char *prov; 929213172Spjd bool boot, noboot; 930213172Spjd int i, nargs; 931162353Spjd 932162353Spjd nargs = gctl_get_int(req, "nargs"); 933162353Spjd if (nargs == 0) { 934162353Spjd gctl_error(req, "Too few arguments."); 935162353Spjd return; 936162353Spjd } 937162353Spjd 938162353Spjd boot = gctl_get_int(req, "boot"); 939162353Spjd noboot = gctl_get_int(req, "noboot"); 940162353Spjd 941162353Spjd if (boot && noboot) { 942162353Spjd gctl_error(req, "Options -b and -B are mutually exclusive."); 943162353Spjd return; 944162353Spjd } 945162353Spjd if (!boot && !noboot) { 946162353Spjd gctl_error(req, "No option given."); 947162353Spjd return; 948162353Spjd } 949162353Spjd 950162353Spjd /* First attached providers. */ 951162353Spjd gctl_issue(req); 952162353Spjd /* Now the rest. */ 953162353Spjd for (i = 0; i < nargs; i++) { 954162353Spjd prov = gctl_get_ascii(req, "arg%d", i); 955162353Spjd if (!eli_is_attached(prov)) 956162353Spjd eli_configure_detached(req, prov, boot); 957162353Spjd } 958162353Spjd} 959162353Spjd 960162353Spjdstatic void 961155101Spjdeli_setkey_attached(struct gctl_req *req, struct g_eli_metadata *md) 962148456Spjd{ 963148456Spjd unsigned char key[G_ELI_USERKEYLEN]; 964166216Spjd intmax_t val, old = 0; 965166216Spjd int error; 966148456Spjd 967153190Spjd val = gctl_get_intmax(req, "iterations"); 968149304Spjd /* Check if iterations number should be changed. */ 969153190Spjd if (val != -1) 970153190Spjd md->md_iterations = val; 971166216Spjd else 972166216Spjd old = md->md_iterations; 973148456Spjd 974148456Spjd /* Generate key for Master Key encryption. */ 975213172Spjd if (eli_genkey(req, md, key, true) == NULL) { 976148456Spjd bzero(key, sizeof(key)); 977148456Spjd return; 978148456Spjd } 979166216Spjd /* 980166216Spjd * If number of iterations has changed, but wasn't given as a 981166216Spjd * command-line argument, update the request. 982166216Spjd */ 983166216Spjd if (val == -1 && md->md_iterations != old) { 984166216Spjd error = gctl_change_param(req, "iterations", sizeof(intmax_t), 985166216Spjd &md->md_iterations); 986166216Spjd assert(error == 0); 987166216Spjd } 988148456Spjd 989148456Spjd gctl_ro_param(req, "key", sizeof(key), key); 990148456Spjd gctl_issue(req); 991148456Spjd bzero(key, sizeof(key)); 992148456Spjd} 993148456Spjd 994148456Spjdstatic void 995149304Spjdeli_setkey_detached(struct gctl_req *req, const char *prov, 996149304Spjd struct g_eli_metadata *md) 997148456Spjd{ 998148456Spjd unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 999148456Spjd unsigned char *mkeydst; 1000213172Spjd unsigned int nkey; 1001153190Spjd intmax_t val; 1002148456Spjd int error; 1003148456Spjd 1004149928Spjd if (md->md_keys == 0) { 1005149928Spjd gctl_error(req, "No valid keys on %s.", prov); 1006149928Spjd return; 1007149928Spjd } 1008149928Spjd 1009148456Spjd /* Generate key for Master Key decryption. */ 1010213172Spjd if (eli_genkey(req, md, key, false) == NULL) { 1011148456Spjd bzero(key, sizeof(key)); 1012148456Spjd return; 1013148456Spjd } 1014148456Spjd 1015148456Spjd /* Decrypt Master Key. */ 1016149304Spjd error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 1017148456Spjd bzero(key, sizeof(key)); 1018148456Spjd if (error != 0) { 1019149304Spjd bzero(md, sizeof(*md)); 1020148456Spjd if (error == -1) 1021148456Spjd gctl_error(req, "Wrong key for %s.", prov); 1022148456Spjd else /* if (error > 0) */ { 1023148456Spjd gctl_error(req, "Cannot decrypt Master Key: %s.", 1024148456Spjd strerror(error)); 1025148456Spjd } 1026148456Spjd return; 1027148456Spjd } 1028148456Spjd if (verbose) 1029148456Spjd printf("Decrypted Master Key %u.\n", nkey); 1030148456Spjd 1031153190Spjd val = gctl_get_intmax(req, "keyno"); 1032153190Spjd if (val != -1) 1033153190Spjd nkey = val; 1034148456Spjd#if 0 1035148456Spjd else 1036148456Spjd ; /* Use the key number which was found during decryption. */ 1037148456Spjd#endif 1038148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 1039148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 1040148456Spjd return; 1041148456Spjd } 1042148456Spjd 1043153190Spjd val = gctl_get_intmax(req, "iterations"); 1044149304Spjd /* Check if iterations number should and can be changed. */ 1045153190Spjd if (val != -1) { 1046149304Spjd if (bitcount32(md->md_keys) != 1) { 1047149304Spjd gctl_error(req, "To be able to use '-i' option, only " 1048149304Spjd "one key can be defined."); 1049149304Spjd return; 1050149304Spjd } 1051149304Spjd if (md->md_keys != (1 << nkey)) { 1052149304Spjd gctl_error(req, "Only already defined key can be " 1053149304Spjd "changed when '-i' option is used."); 1054149304Spjd return; 1055149304Spjd } 1056153190Spjd md->md_iterations = val; 1057149304Spjd } 1058148456Spjd 1059149304Spjd mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 1060149304Spjd md->md_keys |= (1 << nkey); 1061149304Spjd 1062148456Spjd bcopy(mkey, mkeydst, sizeof(mkey)); 1063148456Spjd bzero(mkey, sizeof(mkey)); 1064148456Spjd 1065148456Spjd /* Generate key for Master Key encryption. */ 1066213172Spjd if (eli_genkey(req, md, key, true) == NULL) { 1067148456Spjd bzero(key, sizeof(key)); 1068149304Spjd bzero(md, sizeof(*md)); 1069148456Spjd return; 1070148456Spjd } 1071148456Spjd 1072148456Spjd /* Encrypt the Master-Key with the new key. */ 1073159308Spjd error = g_eli_mkey_encrypt(md->md_ealgo, key, md->md_keylen, mkeydst); 1074148456Spjd bzero(key, sizeof(key)); 1075148456Spjd if (error != 0) { 1076149304Spjd bzero(md, sizeof(*md)); 1077148456Spjd gctl_error(req, "Cannot encrypt Master Key: %s.", 1078148456Spjd strerror(error)); 1079148456Spjd return; 1080148456Spjd } 1081148456Spjd 1082148456Spjd /* Store metadata with fresh key. */ 1083149304Spjd eli_metadata_store(req, prov, md); 1084149304Spjd bzero(md, sizeof(*md)); 1085148456Spjd} 1086148456Spjd 1087148456Spjdstatic void 1088148456Spjdeli_setkey(struct gctl_req *req) 1089148456Spjd{ 1090149304Spjd struct g_eli_metadata md; 1091148456Spjd const char *prov; 1092153190Spjd int nargs; 1093148456Spjd 1094153190Spjd nargs = gctl_get_int(req, "nargs"); 1095153190Spjd if (nargs != 1) { 1096158214Spjd gctl_error(req, "Invalid number of arguments."); 1097148456Spjd return; 1098148456Spjd } 1099153190Spjd prov = gctl_get_ascii(req, "arg0"); 1100148456Spjd 1101149304Spjd if (eli_metadata_read(req, prov, &md) == -1) 1102149304Spjd return; 1103149304Spjd 1104148456Spjd if (eli_is_attached(prov)) 1105155101Spjd eli_setkey_attached(req, &md); 1106148456Spjd else 1107149304Spjd eli_setkey_detached(req, prov, &md); 1108182452Spjd 1109182452Spjd if (req->error == NULL || req->error[0] == '\0') { 1110182452Spjd printf("Note, that the master key encrypted with old keys " 1111182452Spjd "and/or passphrase may still exists in a metadata backup " 1112182452Spjd "file.\n"); 1113182452Spjd } 1114148456Spjd} 1115148456Spjd 1116148456Spjdstatic void 1117148456Spjdeli_delkey_attached(struct gctl_req *req, const char *prov __unused) 1118148456Spjd{ 1119148456Spjd 1120148456Spjd gctl_issue(req); 1121148456Spjd} 1122148456Spjd 1123148456Spjdstatic void 1124148456Spjdeli_delkey_detached(struct gctl_req *req, const char *prov) 1125148456Spjd{ 1126148456Spjd struct g_eli_metadata md; 1127148456Spjd unsigned char *mkeydst; 1128213172Spjd unsigned int nkey; 1129153190Spjd intmax_t val; 1130213172Spjd bool all, force; 1131148456Spjd 1132148456Spjd if (eli_metadata_read(req, prov, &md) == -1) 1133148456Spjd return; 1134148456Spjd 1135153190Spjd all = gctl_get_int(req, "all"); 1136153190Spjd if (all) 1137246620Spjd arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys)); 1138148456Spjd else { 1139153190Spjd force = gctl_get_int(req, "force"); 1140153190Spjd val = gctl_get_intmax(req, "keyno"); 1141153190Spjd if (val == -1) { 1142148456Spjd gctl_error(req, "Key number has to be specified."); 1143148456Spjd return; 1144148456Spjd } 1145153190Spjd nkey = val; 1146148456Spjd if (nkey >= G_ELI_MAXMKEYS) { 1147148456Spjd gctl_error(req, "Invalid '%s' argument.", "keyno"); 1148148456Spjd return; 1149148456Spjd } 1150153190Spjd if (!(md.md_keys & (1 << nkey)) && !force) { 1151148456Spjd gctl_error(req, "Master Key %u is not set.", nkey); 1152148456Spjd return; 1153148456Spjd } 1154148456Spjd md.md_keys &= ~(1 << nkey); 1155153190Spjd if (md.md_keys == 0 && !force) { 1156148456Spjd gctl_error(req, "This is the last Master Key. Use '-f' " 1157148456Spjd "option if you really want to remove it."); 1158148456Spjd return; 1159148456Spjd } 1160148456Spjd mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 1161246620Spjd arc4random_buf(mkeydst, G_ELI_MKEYLEN); 1162148456Spjd } 1163148456Spjd 1164148456Spjd eli_metadata_store(req, prov, &md); 1165148456Spjd bzero(&md, sizeof(md)); 1166148456Spjd} 1167148456Spjd 1168148456Spjdstatic void 1169148456Spjdeli_delkey(struct gctl_req *req) 1170148456Spjd{ 1171148456Spjd const char *prov; 1172153190Spjd int nargs; 1173148456Spjd 1174153190Spjd nargs = gctl_get_int(req, "nargs"); 1175153190Spjd if (nargs != 1) { 1176158214Spjd gctl_error(req, "Invalid number of arguments."); 1177148456Spjd return; 1178148456Spjd } 1179153190Spjd prov = gctl_get_ascii(req, "arg0"); 1180148456Spjd 1181148456Spjd if (eli_is_attached(prov)) 1182148456Spjd eli_delkey_attached(req, prov); 1183148456Spjd else 1184148456Spjd eli_delkey_detached(req, prov); 1185148456Spjd} 1186148456Spjd 1187214118Spjdstatic void 1188214118Spjdeli_resume(struct gctl_req *req) 1189214118Spjd{ 1190214118Spjd struct g_eli_metadata md; 1191214118Spjd unsigned char key[G_ELI_USERKEYLEN]; 1192214118Spjd const char *prov; 1193214118Spjd off_t mediasize; 1194214118Spjd int nargs; 1195214118Spjd 1196214118Spjd nargs = gctl_get_int(req, "nargs"); 1197214118Spjd if (nargs != 1) { 1198214118Spjd gctl_error(req, "Invalid number of arguments."); 1199214118Spjd return; 1200214118Spjd } 1201214118Spjd prov = gctl_get_ascii(req, "arg0"); 1202214118Spjd 1203214118Spjd if (eli_metadata_read(req, prov, &md) == -1) 1204214118Spjd return; 1205214118Spjd 1206214118Spjd mediasize = g_get_mediasize(prov); 1207214118Spjd if (md.md_provsize != (uint64_t)mediasize) { 1208214118Spjd gctl_error(req, "Provider size mismatch."); 1209214118Spjd return; 1210214118Spjd } 1211214118Spjd 1212214118Spjd if (eli_genkey(req, &md, key, false) == NULL) { 1213214118Spjd bzero(key, sizeof(key)); 1214214118Spjd return; 1215214118Spjd } 1216214118Spjd 1217214118Spjd gctl_ro_param(req, "key", sizeof(key), key); 1218214118Spjd if (gctl_issue(req) == NULL) { 1219214118Spjd if (verbose) 1220214118Spjd printf("Resumed %s.\n", prov); 1221214118Spjd } 1222214118Spjd bzero(key, sizeof(key)); 1223214118Spjd} 1224214118Spjd 1225213060Spjdstatic int 1226213060Spjdeli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset) 1227213060Spjd{ 1228213060Spjd unsigned int overwrites; 1229213060Spjd unsigned char *sector; 1230213060Spjd ssize_t size; 1231213060Spjd int error; 1232213060Spjd 1233213060Spjd size = sizeof(overwrites); 1234213060Spjd if (sysctlbyname("kern.geom.eli.overwrites", &overwrites, &size, 1235213060Spjd NULL, 0) == -1 || overwrites == 0) { 1236213060Spjd overwrites = G_ELI_OVERWRITES; 1237213060Spjd } 1238213060Spjd 1239213060Spjd size = g_sectorsize(fd); 1240213060Spjd if (size <= 0) { 1241213060Spjd gctl_error(req, "Cannot obtain provider sector size %s: %s.", 1242213060Spjd prov, strerror(errno)); 1243213060Spjd return (-1); 1244213060Spjd } 1245213060Spjd sector = malloc(size); 1246213060Spjd if (sector == NULL) { 1247213060Spjd gctl_error(req, "Cannot allocate %zd bytes of memory.", size); 1248213060Spjd return (-1); 1249213060Spjd } 1250213060Spjd 1251213060Spjd error = 0; 1252213060Spjd do { 1253246620Spjd arc4random_buf(sector, size); 1254213060Spjd if (pwrite(fd, sector, size, offset) != size) { 1255213060Spjd if (error == 0) 1256213060Spjd error = errno; 1257213060Spjd } 1258213060Spjd (void)g_flush(fd); 1259213060Spjd } while (--overwrites > 0); 1260246622Spjd free(sector); 1261213060Spjd if (error != 0) { 1262213060Spjd gctl_error(req, "Cannot trash metadata on provider %s: %s.", 1263213060Spjd prov, strerror(error)); 1264213060Spjd return (-1); 1265213060Spjd } 1266213060Spjd return (0); 1267213060Spjd} 1268213060Spjd 1269148456Spjdstatic void 1270148456Spjdeli_kill_detached(struct gctl_req *req, const char *prov) 1271148456Spjd{ 1272213060Spjd off_t offset; 1273213060Spjd int fd; 1274148456Spjd 1275148456Spjd /* 1276148456Spjd * NOTE: Maybe we should verify if this is geli provider first, 1277148456Spjd * but 'kill' command is quite critical so better don't waste 1278148456Spjd * the time. 1279148456Spjd */ 1280148456Spjd#if 0 1281148456Spjd error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 1282148456Spjd G_ELI_MAGIC); 1283148456Spjd if (error != 0) { 1284148456Spjd gctl_error(req, "Cannot read metadata from %s: %s.", prov, 1285148456Spjd strerror(error)); 1286148456Spjd return; 1287148456Spjd } 1288148456Spjd#endif 1289148456Spjd 1290213060Spjd fd = g_open(prov, 1); 1291213060Spjd if (fd == -1) { 1292213060Spjd gctl_error(req, "Cannot open provider %s: %s.", prov, 1293213060Spjd strerror(errno)); 1294213060Spjd return; 1295148456Spjd } 1296213060Spjd offset = g_mediasize(fd) - g_sectorsize(fd); 1297213060Spjd if (offset <= 0) { 1298213060Spjd gctl_error(req, 1299213060Spjd "Cannot obtain media size or sector size for provider %s: %s.", 1300213060Spjd prov, strerror(errno)); 1301213060Spjd (void)g_close(fd); 1302213060Spjd return; 1303213060Spjd } 1304213060Spjd (void)eli_trash_metadata(req, prov, fd, offset); 1305213060Spjd (void)g_close(fd); 1306148456Spjd} 1307148456Spjd 1308148456Spjdstatic void 1309148456Spjdeli_kill(struct gctl_req *req) 1310148456Spjd{ 1311148456Spjd const char *prov; 1312153190Spjd int i, nargs, all; 1313148456Spjd 1314153190Spjd nargs = gctl_get_int(req, "nargs"); 1315153190Spjd all = gctl_get_int(req, "all"); 1316153190Spjd if (!all && nargs == 0) { 1317148456Spjd gctl_error(req, "Too few arguments."); 1318148456Spjd return; 1319148456Spjd } 1320148456Spjd /* 1321148456Spjd * How '-a' option combine with a list of providers: 1322148456Spjd * Delete Master Keys from all attached providers: 1323148456Spjd * geli kill -a 1324169312Spjd * Delete Master Keys from all attached providers and from 1325148456Spjd * detached da0 and da1: 1326148456Spjd * geli kill -a da0 da1 1327148456Spjd * Delete Master Keys from (attached or detached) da0 and da1: 1328148456Spjd * geli kill da0 da1 1329148456Spjd */ 1330148456Spjd 1331169312Spjd /* First detached providers. */ 1332153190Spjd for (i = 0; i < nargs; i++) { 1333153190Spjd prov = gctl_get_ascii(req, "arg%d", i); 1334148456Spjd if (!eli_is_attached(prov)) 1335148456Spjd eli_kill_detached(req, prov); 1336148456Spjd } 1337162347Spjd /* Now attached providers. */ 1338162347Spjd gctl_issue(req); 1339148456Spjd} 1340148456Spjd 1341182452Spjdstatic int 1342182452Spjdeli_backup_create(struct gctl_req *req, const char *prov, const char *file) 1343148456Spjd{ 1344148456Spjd unsigned char *sector; 1345213059Spjd ssize_t secsize; 1346226716Spjd int error, filefd, ret; 1347148456Spjd 1348182452Spjd ret = -1; 1349226716Spjd filefd = -1; 1350148456Spjd sector = NULL; 1351148456Spjd secsize = 0; 1352148456Spjd 1353226716Spjd secsize = g_get_sectorsize(prov); 1354226716Spjd if (secsize == 0) { 1355148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1356148456Spjd strerror(errno)); 1357169193Spjd goto out; 1358148456Spjd } 1359148456Spjd sector = malloc(secsize); 1360148456Spjd if (sector == NULL) { 1361148456Spjd gctl_error(req, "Cannot allocate memory."); 1362169193Spjd goto out; 1363148456Spjd } 1364148456Spjd /* Read metadata from the provider. */ 1365226716Spjd error = g_metadata_read(prov, sector, secsize, G_ELI_MAGIC); 1366226716Spjd if (error != 0) { 1367226716Spjd gctl_error(req, "Unable to read metadata from %s: %s.", prov, 1368226716Spjd strerror(error)); 1369148456Spjd goto out; 1370148456Spjd } 1371226716Spjd 1372226716Spjd filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 1373226716Spjd if (filefd == -1) { 1374226716Spjd gctl_error(req, "Unable to open %s: %s.", file, 1375226716Spjd strerror(errno)); 1376148456Spjd goto out; 1377148456Spjd } 1378148456Spjd /* Write metadata to the destination file. */ 1379213059Spjd if (write(filefd, sector, secsize) != secsize) { 1380226716Spjd gctl_error(req, "Unable to write to %s: %s.", file, 1381148456Spjd strerror(errno)); 1382226716Spjd (void)close(filefd); 1383226716Spjd (void)unlink(file); 1384148456Spjd goto out; 1385148456Spjd } 1386213059Spjd (void)fsync(filefd); 1387226716Spjd (void)close(filefd); 1388182452Spjd /* Success. */ 1389182452Spjd ret = 0; 1390148456Spjdout: 1391148456Spjd if (sector != NULL) { 1392148456Spjd bzero(sector, secsize); 1393148456Spjd free(sector); 1394148456Spjd } 1395182452Spjd return (ret); 1396148456Spjd} 1397148456Spjd 1398148456Spjdstatic void 1399182452Spjdeli_backup(struct gctl_req *req) 1400182452Spjd{ 1401182452Spjd const char *file, *prov; 1402182452Spjd int nargs; 1403182452Spjd 1404182452Spjd nargs = gctl_get_int(req, "nargs"); 1405182452Spjd if (nargs != 2) { 1406182452Spjd gctl_error(req, "Invalid number of arguments."); 1407182452Spjd return; 1408182452Spjd } 1409182452Spjd prov = gctl_get_ascii(req, "arg0"); 1410182452Spjd file = gctl_get_ascii(req, "arg1"); 1411182452Spjd 1412182452Spjd eli_backup_create(req, prov, file); 1413182452Spjd} 1414182452Spjd 1415182452Spjdstatic void 1416148456Spjdeli_restore(struct gctl_req *req) 1417148456Spjd{ 1418148456Spjd struct g_eli_metadata md; 1419148456Spjd const char *file, *prov; 1420148456Spjd off_t mediasize; 1421226716Spjd int nargs; 1422148456Spjd 1423153190Spjd nargs = gctl_get_int(req, "nargs"); 1424153190Spjd if (nargs != 2) { 1425148456Spjd gctl_error(req, "Invalid number of arguments."); 1426148456Spjd return; 1427148456Spjd } 1428153190Spjd file = gctl_get_ascii(req, "arg0"); 1429153190Spjd prov = gctl_get_ascii(req, "arg1"); 1430148456Spjd 1431226716Spjd /* Read metadata from the backup file. */ 1432226716Spjd if (eli_metadata_read(req, file, &md) == -1) 1433226716Spjd return; 1434226716Spjd /* Obtain provider's mediasize. */ 1435226716Spjd mediasize = g_get_mediasize(prov); 1436226716Spjd if (mediasize == 0) { 1437148456Spjd gctl_error(req, "Cannot get informations about %s: %s.", prov, 1438148456Spjd strerror(errno)); 1439226716Spjd return; 1440148456Spjd } 1441212934Sbrian /* Check if the provider size has changed since we did the backup. */ 1442212934Sbrian if (md.md_provsize != (uint64_t)mediasize) { 1443212934Sbrian if (gctl_get_int(req, "force")) { 1444212934Sbrian md.md_provsize = mediasize; 1445212934Sbrian } else { 1446212934Sbrian gctl_error(req, "Provider size mismatch: " 1447212934Sbrian "wrong backup file?"); 1448226716Spjd return; 1449212934Sbrian } 1450212934Sbrian } 1451226716Spjd /* Write metadata to the provider. */ 1452226716Spjd (void)eli_metadata_store(req, prov, &md); 1453148456Spjd} 1454148456Spjd 1455148456Spjdstatic void 1456212934Sbrianeli_resize(struct gctl_req *req) 1457212934Sbrian{ 1458212934Sbrian struct g_eli_metadata md; 1459212934Sbrian const char *prov; 1460212934Sbrian unsigned char *sector; 1461213056Spjd ssize_t secsize; 1462212934Sbrian off_t mediasize, oldsize; 1463226722Spjd int error, nargs, provfd; 1464212934Sbrian 1465212934Sbrian nargs = gctl_get_int(req, "nargs"); 1466212934Sbrian if (nargs != 1) { 1467212934Sbrian gctl_error(req, "Invalid number of arguments."); 1468212934Sbrian return; 1469212934Sbrian } 1470212934Sbrian prov = gctl_get_ascii(req, "arg0"); 1471212934Sbrian 1472212934Sbrian provfd = -1; 1473212934Sbrian sector = NULL; 1474212934Sbrian secsize = 0; 1475212934Sbrian 1476213056Spjd provfd = g_open(prov, 1); 1477212934Sbrian if (provfd == -1) { 1478212934Sbrian gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1479212934Sbrian goto out; 1480212934Sbrian } 1481212934Sbrian 1482213056Spjd mediasize = g_mediasize(provfd); 1483213056Spjd secsize = g_sectorsize(provfd); 1484213056Spjd if (mediasize == -1 || secsize == -1) { 1485212934Sbrian gctl_error(req, "Cannot get information about %s: %s.", prov, 1486212934Sbrian strerror(errno)); 1487212934Sbrian goto out; 1488212934Sbrian } 1489212934Sbrian 1490212934Sbrian sector = malloc(secsize); 1491212934Sbrian if (sector == NULL) { 1492212934Sbrian gctl_error(req, "Cannot allocate memory."); 1493212934Sbrian goto out; 1494212934Sbrian } 1495212934Sbrian 1496212934Sbrian oldsize = gctl_get_intmax(req, "oldsize"); 1497212934Sbrian if (oldsize < 0 || oldsize > mediasize) { 1498212934Sbrian gctl_error(req, "Invalid oldsize: Out of range."); 1499212934Sbrian goto out; 1500212934Sbrian } 1501213058Spjd if (oldsize == mediasize) { 1502213058Spjd gctl_error(req, "Size hasn't changed."); 1503213058Spjd goto out; 1504213058Spjd } 1505212934Sbrian 1506212934Sbrian /* Read metadata from the 'oldsize' offset. */ 1507213056Spjd if (pread(provfd, sector, secsize, oldsize - secsize) != secsize) { 1508212934Sbrian gctl_error(req, "Cannot read old metadata: %s.", 1509212934Sbrian strerror(errno)); 1510212934Sbrian goto out; 1511212934Sbrian } 1512212934Sbrian 1513212934Sbrian /* Check if this sector contains geli metadata. */ 1514226722Spjd error = eli_metadata_decode(sector, &md); 1515226722Spjd switch (error) { 1516226722Spjd case 0: 1517226722Spjd break; 1518226722Spjd case EOPNOTSUPP: 1519226722Spjd gctl_error(req, 1520226722Spjd "Provider's %s metadata version %u is too new.\n" 1521226722Spjd "geli: The highest supported version is %u.", 1522226722Spjd prov, (unsigned int)md.md_version, G_ELI_VERSION); 1523212934Sbrian goto out; 1524226722Spjd case EINVAL: 1525226722Spjd gctl_error(req, "Inconsistent provider's %s metadata.", prov); 1526226722Spjd goto out; 1527226722Spjd default: 1528226722Spjd gctl_error(req, 1529226722Spjd "Unexpected error while decoding provider's %s metadata: %s.", 1530226722Spjd prov, strerror(error)); 1531226722Spjd goto out; 1532212934Sbrian } 1533212934Sbrian 1534212934Sbrian /* 1535212934Sbrian * If the old metadata doesn't have a correct provider size, refuse 1536212934Sbrian * to resize. 1537212934Sbrian */ 1538212934Sbrian if (md.md_provsize != (uint64_t)oldsize) { 1539212934Sbrian gctl_error(req, "Provider size mismatch at oldsize."); 1540212934Sbrian goto out; 1541212934Sbrian } 1542212934Sbrian 1543212934Sbrian /* 1544212934Sbrian * Update the old metadata with the current provider size and write 1545212934Sbrian * it back to the correct place on the provider. 1546212934Sbrian */ 1547212934Sbrian md.md_provsize = mediasize; 1548226720Spjd /* Write metadata to the provider. */ 1549226720Spjd (void)eli_metadata_store(req, prov, &md); 1550212934Sbrian /* Now trash the old metadata. */ 1551226720Spjd (void)eli_trash_metadata(req, prov, provfd, oldsize - secsize); 1552212934Sbrianout: 1553226720Spjd if (provfd != -1) 1554213056Spjd (void)g_close(provfd); 1555212934Sbrian if (sector != NULL) { 1556212934Sbrian bzero(sector, secsize); 1557212934Sbrian free(sector); 1558212934Sbrian } 1559212934Sbrian} 1560212934Sbrian 1561212934Sbrianstatic void 1562226723Spjdeli_version(struct gctl_req *req) 1563226723Spjd{ 1564226723Spjd struct g_eli_metadata md; 1565226723Spjd const char *name; 1566226723Spjd unsigned int version; 1567226723Spjd int error, i, nargs; 1568226723Spjd 1569226723Spjd nargs = gctl_get_int(req, "nargs"); 1570226723Spjd 1571226723Spjd if (nargs == 0) { 1572226723Spjd unsigned int kernver; 1573226723Spjd ssize_t size; 1574226723Spjd 1575226723Spjd size = sizeof(kernver); 1576226723Spjd if (sysctlbyname("kern.geom.eli.version", &kernver, &size, 1577226723Spjd NULL, 0) == -1) { 1578226723Spjd warn("Unable to obtain GELI kernel version"); 1579226723Spjd } else { 1580226723Spjd printf("kernel: %u\n", kernver); 1581226723Spjd } 1582226723Spjd printf("userland: %u\n", G_ELI_VERSION); 1583226723Spjd return; 1584226723Spjd } 1585226723Spjd 1586226723Spjd for (i = 0; i < nargs; i++) { 1587226723Spjd name = gctl_get_ascii(req, "arg%d", i); 1588226723Spjd error = g_metadata_read(name, (unsigned char *)&md, 1589226723Spjd sizeof(md), G_ELI_MAGIC); 1590226723Spjd if (error != 0) { 1591226723Spjd warn("%s: Unable to read metadata: %s.", name, 1592226723Spjd strerror(error)); 1593226723Spjd gctl_error(req, "Not fully done."); 1594226723Spjd continue; 1595226723Spjd } 1596226723Spjd version = le32dec(&md.md_version); 1597226723Spjd printf("%s: %u\n", name, version); 1598226723Spjd } 1599226723Spjd} 1600226723Spjd 1601226723Spjdstatic void 1602148456Spjdeli_clear(struct gctl_req *req) 1603148456Spjd{ 1604148456Spjd const char *name; 1605153190Spjd int error, i, nargs; 1606148456Spjd 1607153190Spjd nargs = gctl_get_int(req, "nargs"); 1608153190Spjd if (nargs < 1) { 1609148456Spjd gctl_error(req, "Too few arguments."); 1610148456Spjd return; 1611148456Spjd } 1612148456Spjd 1613153190Spjd for (i = 0; i < nargs; i++) { 1614153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1615148456Spjd error = g_metadata_clear(name, G_ELI_MAGIC); 1616148456Spjd if (error != 0) { 1617148456Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1618148456Spjd name, strerror(error)); 1619148456Spjd gctl_error(req, "Not fully done."); 1620148456Spjd continue; 1621148456Spjd } 1622148456Spjd if (verbose) 1623155175Spjd printf("Metadata cleared on %s.\n", name); 1624148456Spjd } 1625148456Spjd} 1626148456Spjd 1627148456Spjdstatic void 1628148456Spjdeli_dump(struct gctl_req *req) 1629148456Spjd{ 1630226719Spjd struct g_eli_metadata md; 1631148456Spjd const char *name; 1632226719Spjd int i, nargs; 1633148456Spjd 1634153190Spjd nargs = gctl_get_int(req, "nargs"); 1635153190Spjd if (nargs < 1) { 1636148456Spjd gctl_error(req, "Too few arguments."); 1637148456Spjd return; 1638148456Spjd } 1639148456Spjd 1640153190Spjd for (i = 0; i < nargs; i++) { 1641153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1642226719Spjd if (eli_metadata_read(NULL, name, &md) == -1) { 1643148456Spjd gctl_error(req, "Not fully done."); 1644148456Spjd continue; 1645148456Spjd } 1646148456Spjd printf("Metadata on %s:\n", name); 1647148456Spjd eli_metadata_dump(&md); 1648148456Spjd printf("\n"); 1649148456Spjd } 1650148456Spjd} 1651