| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 | 
							- /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
 
- /*
 
-  * Copyright (c) 2016 Red Hat, Inc.
 
-  * Author: Nathaniel McCallum <npmccallum@redhat.com>
 
-  *
 
-  * This program is free software: you can redistribute it and/or modify it
 
-  * under the terms of the GNU Lesser General Public License as published by
 
-  * the Free Software Foundation, either version 2.1 of the License, or
 
-  * (at your option) any later version.
 
-  *
 
-  * This program is distributed in the hope that it will be useful,
 
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
-  * GNU Lesser General Public License for more details.
 
-  *
 
-  * You should have received a copy of the GNU Lesser General Public License
 
-  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-  */
 
- #include "luksmeta.h"
 
- #include <errno.h>
 
- #include <getopt.h>
 
- #include <stdbool.h>
 
- #include <stdio.h>
 
- #include <stdlib.h>
 
- #include <string.h>
 
- #include <sysexits.h>
 
- #define UUID_TMPL \
 
-     "%02hhx%02hhx%02hhx%02hhx-" \
 
-     "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-" \
 
-     "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
- #define UUID_ARGS(u) \
 
-     u[0x0], u[0x1], u[0x2], u[0x3], u[0x4], u[0x5], u[0x6], u[0x7], \
 
-     u[0x8], u[0x9], u[0xa], u[0xb], u[0xc], u[0xd], u[0xe], u[0xf]
 
- struct options {
 
-     const char *device;
 
-     luksmeta_uuid_t uuid;
 
-     bool have_uuid;
 
-     bool force;
 
-     bool nuke;
 
-     int slot;
 
- };
 
- #define LUKSMETA_LIBCRYPTSETUP_LOG_LEVEL CRYPT_LOG_ERROR
 
- static void
 
- luksmeta_libcryptsetup_log(int level, const char *msg, void *usrptr)
 
- {
 
-     if (level != LUKSMETA_LIBCRYPTSETUP_LOG_LEVEL) {
 
-        return;
 
-     }
 
-     fprintf(stderr, "%s", msg);
 
- }
 
- static int
 
- cmd_test(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     return luksmeta_test(cd) == 0 ? EX_OK : EX_OSFILE;
 
- }
 
- static int
 
- cmd_nuke(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     int r = 0;
 
-     if (!opts->force) {
 
-         int c = 'X';
 
-         fprintf(stderr,
 
-                 "You are about to erase all data in the LUKSMeta storage area.\n"
 
-                 "A backup is advised before erasure is performed.\n\n");
 
-         while (!strchr("YyNn", c)) {
 
-             fprintf(stderr, "Do you wish to nuke %s? [yn] ",
 
-                     crypt_get_device_name(cd));
 
-             c = getc(stdin);
 
-         }
 
-         if (strchr("Nn", c))
 
-             return EX_NOPERM;
 
-     }
 
-     r = luksmeta_nuke(cd);
 
-     switch (r) {
 
-     case 0:
 
-         return EX_OK;
 
-     default:
 
-         fprintf(stderr, "Error while erasing device (%s): %s\n",
 
-                 opts->device, strerror(-r));
 
-         return EX_OSERR;
 
-     }
 
- }
 
- static int
 
- cmd_init(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     int r = 0;
 
-     if (!opts->force) {
 
-         int c = 'X';
 
-         fprintf(stderr,
 
-             "You are about to initialize a LUKS device for metadata storage.\n"
 
-             "Attempting to initialize it may result in data loss if data was\n"
 
-             "already written into the LUKS header gap in a different format.\n"
 
-             "A backup is advised before initialization is performed.\n\n");
 
-         while (!strchr("YyNn", c)) {
 
-             fprintf(stderr, "Do you wish to initialize %s? [yn] ",
 
-                     crypt_get_device_name(cd));
 
-             c = getc(stdin);
 
-         }
 
-         if (strchr("Nn", c))
 
-             return EX_NOPERM;
 
-     }
 
-     if (opts->nuke) {
 
-         struct options o = { .force = true, .device = opts->device };
 
-         r = cmd_nuke(&o, cd);
 
-         if (r != EX_OK)
 
-             return r;
 
-     }
 
-     r = luksmeta_init(cd);
 
-     switch (r) {
 
-     case 0: /* fallthrough */
 
-     case -EALREADY:
 
-         return EX_OK;
 
-     case -ENOSPC:
 
-         fprintf(stderr, "Insufficient space in the LUKS header (%s)\n",
 
-                 opts->device);
 
-         return EX_CANTCREAT;
 
-     default:
 
-         fprintf(stderr, "Error while initializing device (%s): %s\n",
 
-                 opts->device, strerror(-r));
 
-         return EX_OSERR;
 
-     }
 
-     return EX_OK;
 
- }
 
- static const char *
 
- status(struct crypt_device *cd, int keyslot)
 
- {
 
-     switch (crypt_keyslot_status(cd, keyslot)) {
 
-     case CRYPT_SLOT_INVALID: return "invalid";
 
-     case CRYPT_SLOT_INACTIVE: return "inactive";
 
-     case CRYPT_SLOT_ACTIVE: return "active";
 
-     case CRYPT_SLOT_ACTIVE_LAST: return "active";
 
-     default: return "unknown";
 
-     }
 
- }
 
- static int
 
- cmd_show(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     luksmeta_uuid_t uuid = {};
 
-     for (int i = 0, r = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
 
-         if (opts->slot >= 0 && i != opts->slot)
 
-             continue;
 
-         r = luksmeta_load(cd, i, uuid, NULL, 0);
 
-         switch (r) {
 
-         case -EBADSLT:
 
-             fprintf(stderr, "Invalid slot (%d)\n", opts->slot);
 
-             return EX_USAGE;
 
-         case -ENOENT:
 
-             fprintf(stderr, "Device is not initialized (%s)\n",
 
-                     opts->device);
 
-             return EX_OSFILE;
 
-         case -EINVAL:
 
-             fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n",
 
-                     opts->device);
 
-             return EX_OSFILE;
 
-         case -ENODATA:
 
-             if (opts->slot < 0)
 
-                 fprintf(stdout, "%d %8s %s\n", i, status(cd, i), "empty");
 
-             break;
 
-         default:
 
-             if (r < 0) {
 
-                 fprintf(stderr, "%d %8s %s\n",
 
-                         i, status(cd, i), "unknown error");
 
-             } else {
 
-                 if (opts->slot < 0)
 
-                     fprintf(stdout, "%d %8s ", i, status(cd, i));
 
-                 fprintf(stdout, UUID_TMPL "\n", UUID_ARGS(uuid));
 
-             }
 
-             break;
 
-         }
 
-     }
 
-     return EX_OK;
 
- }
 
- static int
 
- cmd_save(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     uint8_t *in = NULL;
 
-     size_t inl = 0;
 
-     int r = 0;
 
-     if (!opts->have_uuid) {
 
-         fprintf(stderr, "UUID required\n");
 
-         return EX_USAGE;
 
-     }
 
-     while (!feof(stdin)) {
 
-         uint8_t *tmp = NULL;
 
-         tmp = realloc(in, inl + 4096);
 
-         if (!tmp) {
 
-             fprintf(stderr, "Out of memory\n");
 
-             free(in);
 
-             return EX_OSERR;
 
-         }
 
-         in = tmp;
 
-         r = fread(&in[inl], 1, 4096, stdin);
 
-         inl += r;
 
-         if (r < 4096 && (ferror(stdin) || inl == 0)) {
 
-             fprintf(stderr, "Error reading from standard input\n");
 
-             free(in);
 
-             return EX_NOINPUT;
 
-         }
 
-     }
 
-     if (!in) {
 
-         fprintf(stderr, "No data on standard input\n");
 
-         return EX_NOINPUT;
 
-     }
 
-     r = luksmeta_save(cd, opts->slot, opts->uuid, in, inl);
 
-     memset(in, 0, inl);
 
-     free(in);
 
-     switch (r) {
 
-     case -ENOENT:
 
-         fprintf(stderr, "Device is not initialized (%s)\n", opts->device);
 
-         return EX_OSFILE;
 
-     case -EINVAL:
 
-         fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device);
 
-         return EX_OSFILE;
 
-     case -EBADSLT:
 
-         fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot);
 
-         return EX_USAGE;
 
-     case -EKEYREJECTED:
 
-         fprintf(stderr, "The specified UUID is reserved (" UUID_TMPL ")\n",
 
-                 UUID_ARGS(opts->uuid));
 
-         return EX_USAGE;
 
-     case -EALREADY:
 
-         fprintf(stderr, "Will not overwrite existing slot (%d)\n", opts->slot);
 
-         return EX_UNAVAILABLE;
 
-     case -ENOSPC:
 
-         fprintf(stderr, "Insufficient space in the LUKS header (%s)\n",
 
-                 opts->device);
 
-         return EX_CANTCREAT;
 
-     default:
 
-         if (r < 0)
 
-             fprintf(stderr, "An unknown error occurred\n");
 
-         else if (opts->slot < 0)
 
-             fprintf(stdout, "%d\n", r);
 
-         return r < 0 ? EX_OSERR : EX_OK;
 
-     }
 
- }
 
- static int
 
- cmd_load(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     luksmeta_uuid_t uuid = {};
 
-     int r = 0;
 
-     if (opts->slot < 0) {
 
-         fprintf(stderr, "Slot required\n");
 
-         return EX_USAGE;
 
-     }
 
-     r = luksmeta_load(cd, opts->slot, uuid, NULL, 0);
 
-     if (r >= 0) {
 
-         uint8_t *out = NULL;
 
-         if (opts->have_uuid && memcmp(opts->uuid, uuid, sizeof(uuid)) != 0) {
 
-             fprintf(stderr,
 
-                     "The given UUID does not match the slot UUID:\n"
 
-                     "UUID: " UUID_TMPL "\n"
 
-                     "SLOT: " UUID_TMPL "\n",
 
-                     UUID_ARGS(opts->uuid),
 
-                     UUID_ARGS(uuid));
 
-             return EX_DATAERR;
 
-         }
 
-         out = malloc(r);
 
-         if (!out) {
 
-             fprintf(stderr, "Out of memory!\n");
 
-             return EX_OSERR;
 
-         }
 
-         r = luksmeta_load(cd, opts->slot, uuid, out, r);
 
-         if (r >= 0) {
 
-             fwrite(out, 1, r, stdout);
 
-             memset(out, 0, r);
 
-         }
 
-         free(out);
 
-     }
 
-     switch (r) {
 
-     case -ENOENT:
 
-         fprintf(stderr, "Device is not initialized (%s)\n", opts->device);
 
-         return EX_OSFILE;
 
-     case -EINVAL:
 
-         fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device);
 
-         return EX_OSFILE;
 
-     case -EBADSLT:
 
-         fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot);
 
-         return EX_USAGE;
 
-     case -ENODATA:
 
-         fprintf(stderr, "The specified slot is empty (%d)\n", opts->slot);
 
-         return EX_UNAVAILABLE;
 
-     default:
 
-         if (r < 0)
 
-             fprintf(stderr, "An unknown error occurred\n");
 
-         return r < 0 ? EX_OSERR : EX_OK;
 
-     }
 
- }
 
- static int
 
- cmd_wipe(const struct options *opts, struct crypt_device *cd)
 
- {
 
-     luksmeta_uuid_t uuid = {};
 
-     int r = 0;
 
-     if (opts->slot < 0) {
 
-         fprintf(stderr, "Slot required\n");
 
-         return EX_USAGE;
 
-     }
 
-     if (!opts->force) {
 
-         int c = 'X';
 
-         fprintf(stderr,
 
-             "You are about to wipe a slot. This operation is unrecoverable.\n"
 
-             "A backup is advised before proceeding.\n\n");
 
-         while (!strchr("YyNn", c)) {
 
-             fprintf(stderr, "Do you wish to erase slot %d on %s? [yn] ",
 
-                     opts->slot, crypt_get_device_name(cd));
 
-             c = getc(stdin);
 
-         }
 
-         if (strchr("Nn", c))
 
-             return EX_NOPERM;
 
-     }
 
-     r = luksmeta_wipe(cd, opts->slot, opts->have_uuid ? opts->uuid : NULL);
 
-     switch (r) {
 
-     case -EALREADY:
 
-         return EX_OK;
 
-     case -ENOENT:
 
-         fprintf(stderr, "Device is not initialized (%s)\n", opts->device);
 
-         return EX_OSFILE;
 
-     case -EINVAL:
 
-         fprintf(stderr, "LUKSMeta data appears corrupt (%s)\n", opts->device);
 
-         return EX_OSFILE;
 
-     case -EBADSLT:
 
-         fprintf(stderr, "The specified slot is invalid (%d)\n", opts->slot);
 
-         return EX_USAGE;
 
-     case -EKEYREJECTED:
 
-         r = luksmeta_load(cd, opts->slot, uuid, NULL, 0);
 
-         if (r >= 0) {
 
-             fprintf(stderr,
 
-                     "The given UUID does not match the slot UUID:\n"
 
-                     "UUID: " UUID_TMPL "\n"
 
-                     "SLOT: " UUID_TMPL "\n",
 
-                     UUID_ARGS(opts->uuid),
 
-                     UUID_ARGS(uuid));
 
-         } else {
 
-             fprintf(stderr,
 
-                     "The given UUID does not match the slot UUID:\n"
 
-                     "UUID: " UUID_TMPL "\n"
 
-                     "SLOT: UNKNOWN\n",
 
-                     UUID_ARGS(opts->uuid));
 
-         }
 
-         return EX_DATAERR;
 
-     default:
 
-         if (r < 0)
 
-             fprintf(stderr, "An unknown error occurred\n");
 
-         return r < 0 ? EX_OSERR : EX_OK;
 
-     }
 
- }
 
- static const char *sopts = "hfnd:u:s:";
 
- static const struct option lopts[] = {
 
-     { "help",                      .val = 'h' },
 
-     { "nuke",   no_argument,       .val = 'n' },
 
-     { "force",  no_argument,       .val = 'f' },
 
-     { "device", required_argument, .val = 'd' },
 
-     { "uuid",   required_argument, .val = 'u' },
 
-     { "slot",   required_argument, .val = 's' },
 
-     {}
 
- };
 
- static const struct {
 
-     int (*func)(const struct options *opts, struct crypt_device *cd);
 
-     const char *name;
 
- } commands[] = {
 
-     { cmd_test, "test", },
 
-     { cmd_nuke, "nuke", },
 
-     { cmd_init, "init", },
 
-     { cmd_show, "show", },
 
-     { cmd_save, "save", },
 
-     { cmd_load, "load", },
 
-     { cmd_wipe, "wipe", },
 
-     {}
 
- };
 
- int
 
- main(int argc, char *argv[])
 
- {
 
-     struct options o = { .slot = CRYPT_ANY_SLOT };
 
-     for (int c; (c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1; ) {
 
-         switch (c) {
 
-         case 'h': goto usage;
 
-         case 'd': o.device = optarg; break;
 
-         case 'n': o.nuke = true; break;
 
-         case 'f': o.force = true; break;
 
-         case 'u':
 
-             if (sscanf(optarg, UUID_TMPL, UUID_ARGS(&o.uuid)) != 16) {
 
-                 fprintf(stderr, "Invalid UUID (%s)\n", optarg);
 
-                 return EX_USAGE;
 
-             }
 
-             o.have_uuid = true;
 
-             break;
 
-         case 's':
 
-             if (sscanf(optarg, "%d", &o.slot) != 1 || o.slot < 0 ||
 
-                 o.slot >= crypt_keyslot_max(CRYPT_LUKS1)) {
 
-                 fprintf(stderr, "Invalid slot (%s)\n", optarg);
 
-                 return EX_USAGE;
 
-             }
 
-             break;
 
-         }
 
-     }
 
-     if (argc > 1 && !o.device) {
 
-         fprintf(stderr, "Device must be specified\n\n");
 
-         goto usage;
 
-     }
 
-     if (optind != argc - 1)
 
-         goto usage;
 
-     for (size_t i = 0; argc > 1 && commands[i].name; i++) {
 
-         struct crypt_device *cd = NULL;
 
-         const char *type = NULL;
 
-         int r = 0;
 
-         if (strcmp(argv[optind], commands[i].name) != 0)
 
-             continue;
 
-         r = crypt_init(&cd, o.device);
 
-         if (r != 0) {
 
-             fprintf(stderr, "Unable to open device (%s): %s\n",
 
-                     o.device, strerror(-r));
 
-             return EX_IOERR;
 
-         }
 
-         crypt_set_log_callback(cd, luksmeta_libcryptsetup_log, NULL);
 
-         r = crypt_load(cd, NULL, NULL);
 
-         if (r != 0) {
 
-             fprintf(stderr, "Unable to read LUKSv1 header (%s): %s\n",
 
-                     o.device, strerror(-r));
 
-             crypt_free(cd);
 
-             return EX_IOERR;
 
-         }
 
-         type = crypt_get_type(cd);
 
-         if (type == NULL) {
 
-             fprintf(stderr, "Unable to determine device type for %s\n",
 
-                     o.device);
 
-             crypt_free(cd);
 
-             return EX_OSFILE;
 
-         }
 
-         if (strcmp(type, CRYPT_LUKS1) != 0) {
 
-             fprintf(stderr, "%s (%s) is not a LUKSv1 device\n", o.device, type);
 
-             crypt_free(cd);
 
-             return EX_OSFILE;
 
-         }
 
-         r = commands[i].func(&o, cd);
 
-         crypt_free(cd);
 
-         return r;
 
-     }
 
-     fprintf(stderr, "Invalid command\n\n");
 
- usage:
 
-     fprintf(stderr,
 
-             "Usage: luksmeta test -d DEVICE\n"
 
-             "   or: luksmeta nuke -d DEVICE [-f]\n"
 
-             "   or: luksmeta init -d DEVICE [-f] [-n]\n"
 
-             "   or: luksmeta show -d DEVICE [-s SLOT]\n"
 
-             "   or: luksmeta save -d DEVICE [-s SLOT]  -u UUID  < DATA\n"
 
-             "   or: luksmeta load -d DEVICE  -s SLOT  [-u UUID] > DATA\n"
 
-             "   or: luksmeta wipe -d DEVICE  -s SLOT  [-u UUID] [-f]\n");
 
-     return EX_USAGE;
 
- }
 
 
  |