TCRYPT: support keyfiles
[platform/upstream/cryptsetup.git] / src / cryptsetup.c
index dde6aec..5387915 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <limits.h>
-#include <popt.h>
-
 #include "cryptsetup.h"
 
-static int opt_verbose = 0;
-static int opt_debug = 0;
 static const char *opt_cipher = NULL;
 static const char *opt_hash = NULL;
 static int opt_verify_passphrase = 0;
+
 static const char *opt_key_file = NULL;
+static int opt_keyfiles_count = 0;
+static const char *opt_keyfiles[MAX_KEYFILES];
+
 static const char *opt_master_key_file = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
@@ -58,7 +45,6 @@ static uint64_t opt_skip = 0;
 static int opt_skip_valid = 0;
 static int opt_readonly = 0;
 static int opt_iteration_time = 1000;
-static int opt_batch_mode = 0;
 static int opt_version_mode = 0;
 static int opt_timeout = 0;
 static int opt_tries = 3;
@@ -68,14 +54,18 @@ static int opt_urandom = 0;
 static int opt_dump_master_key = 0;
 static int opt_shared = 0;
 static int opt_allow_discards = 0;
+static int opt_test_passphrase = 0;
+static int opt_hidden = 0;
 
 static const char **action_argv;
 static int action_argc;
+static const char *null_action_argv[] = {NULL, NULL};
 
 static int action_create(int arg);
 static int action_remove(int arg);
 static int action_resize(int arg);
 static int action_status(int arg);
+static int action_benchmark(int arg);
 static int action_luksFormat(int arg);
 static int action_luksOpen(int arg);
 static int action_luksAddKey(int arg);
@@ -91,6 +81,7 @@ static int action_luksBackup(int arg);
 static int action_luksRestore(int arg);
 static int action_loopaesOpen(int arg);
 static int action_luksRepair(int arg);
+static int action_tcryptOpen(int arg);
 
 static struct action_type {
        const char *type;
@@ -105,6 +96,7 @@ static struct action_type {
        { "remove",     action_remove,          0, 1, 1, N_("<name>"), N_("remove device") },
        { "resize",     action_resize,          0, 1, 1, N_("<name>"), N_("resize active device") },
        { "status",     action_status,          0, 1, 0, N_("<name>"), N_("show device status") },
+       { "benchmark",  action_benchmark,       0, 0, 0, N_("<name>"), N_("benchmark cipher") },
        { "repair",     action_luksRepair,      0, 1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
        { "luksFormat", action_luksFormat,      0, 1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
        { "luksOpen",   action_luksOpen,        0, 2, 1, N_("<device> <name> "), N_("open LUKS device as mapping <name>") },
@@ -122,87 +114,10 @@ static struct action_type {
        { "luksHeaderRestore",action_luksRestore,0,1, 1, N_("<device>"), N_("Restore LUKS device header and keyslots") },
        { "loopaesOpen",action_loopaesOpen,     0, 2, 1, N_("<device> <name> "), N_("open loop-AES device as mapping <name>") },
        { "loopaesClose",action_remove,         0, 1, 1, N_("<name>"), N_("remove loop-AES mapping") },
+       { "tcryptOpen", action_tcryptOpen,      0, 2, 1, N_("<device> <name> "), N_("open TCRYPT device as mapping <name>") },
        { NULL, NULL, 0, 0, 0, NULL, NULL }
 };
 
-__attribute__((format(printf, 5, 6)))
-static void clogger(struct crypt_device *cd, int level, const char *file,
-                  int line, const char *format, ...)
-{
-       va_list argp;
-       char *target = NULL;
-
-       va_start(argp, format);
-
-       if (vasprintf(&target, format, argp) > 0) {
-               if (level >= 0) {
-                       crypt_log(cd, level, target);
-#ifdef CRYPT_DEBUG
-               } else if (opt_debug)
-                       printf("# %s:%d %s\n", file ?: "?", line, target);
-#else
-               } else if (opt_debug)
-                       printf("# %s\n", target);
-#endif
-       }
-
-       va_end(argp);
-       free(target);
-}
-
-static int _yesDialog(const char *msg, void *usrptr __attribute__((unused)))
-{
-       char *answer = NULL;
-       size_t size = 0;
-       int r = 1;
-
-       if(isatty(STDIN_FILENO) && !opt_batch_mode) {
-               log_std("\nWARNING!\n========\n");
-               log_std("%s\n\nAre you sure? (Type uppercase yes): ", msg);
-               if(getline(&answer, &size, stdin) == -1) {
-                       perror("getline");
-                       free(answer);
-                       return 0;
-               }
-               if(strcmp(answer, "YES\n"))
-                       r = 0;
-               free(answer);
-       }
-
-       return r;
-}
-
-static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
-{
-       switch(level) {
-
-       case CRYPT_LOG_NORMAL:
-               fputs(msg, stdout);
-               break;
-       case CRYPT_LOG_VERBOSE:
-               if (opt_verbose)
-                       fputs(msg, stdout);
-               break;
-       case CRYPT_LOG_ERROR:
-               fputs(msg, stderr);
-               break;
-       case CRYPT_LOG_DEBUG:
-               if (opt_debug)
-                       printf("# %s\n", msg);
-               break;
-       default:
-               fprintf(stderr, "Internal error on logging class for msg: %s", msg);
-               break;
-       }
-}
-
-static void _quiet_log(int level, const char *msg, void *usrptr)
-{
-       if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
-               level = CRYPT_LOG_VERBOSE;
-       _log(level, msg, usrptr);
-}
-
 static int _verify_passphrase(int def)
 {
        /* Batch mode switch off verify - if not overrided by -y */
@@ -221,60 +136,6 @@ static int _verify_passphrase(int def)
        return def;
 }
 
-static void show_status(int errcode)
-{
-       char error[256], *error_;
-
-       if(!opt_verbose)
-               return;
-
-       if(!errcode) {
-               log_std(_("Command successful.\n"));
-               return;
-       }
-
-       crypt_get_error(error, sizeof(error));
-
-       if (!error[0]) {
-               error_ = strerror_r(-errcode, error, sizeof(error));
-               if (error_ != error) {
-                       strncpy(error, error_, sizeof(error));
-                       error[sizeof(error) - 1] = '\0';
-               }
-       }
-
-       log_err(_("Command failed with code %i"), -errcode);
-       if (*error)
-               log_err(": %s\n", error);
-       else
-               log_err(".\n");
-}
-
-static const char *uuid_or_device(const char *spec)
-{
-       static char device[PATH_MAX];
-       char s, *ptr;
-       int i = 0, uuid_len = 5;
-
-       /* Check if it is correct UUID=<LUKS_UUID> format */
-       if (spec && !strncmp(spec, "UUID=", uuid_len)) {
-               strcpy(device, "/dev/disk/by-uuid/");
-               ptr = &device[strlen(device)];
-               i = uuid_len;
-               while ((s = spec[i++]) && i < PATH_MAX) {
-                       if (!isxdigit(s) && s != '-')
-                               return spec; /* Bail it out */
-                       if (isalpha(s))
-                               s = tolower(s);
-                       *ptr++ = s;
-               }
-               *ptr = '\0';
-               return device;
-       }
-
-       return spec;
-}
-
 static int action_create(int arg __attribute__((unused)))
 {
        struct crypt_device *cd = NULL;
@@ -398,6 +259,47 @@ out:
        return r;
 }
 
+static int action_tcryptOpen(int arg __attribute__((unused)))
+{
+       struct crypt_device *cd = NULL;
+       struct crypt_params_tcrypt params = {
+               .keyfiles = opt_keyfiles,
+               .keyfiles_count = opt_keyfiles_count,
+       };
+       const char *activated_name;
+       uint32_t flags = 0;
+       int r;
+
+       activated_name = opt_test_passphrase ? NULL : action_argv[1];
+
+       if ((r = crypt_init(&cd, action_argv[0])))
+               goto out;
+
+       /* TCRYPT header is encrypted, get passphrase now */
+       r = crypt_get_key(_("Enter passphrase: "),
+                         CONST_CAST(char**)&params.passphrase,
+                         &params.passphrase_size, 0, 0, NULL, opt_timeout,
+                         _verify_passphrase(0), cd);
+       if (r < 0)
+               goto out;
+
+       if (opt_hidden)
+               params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
+
+       r = crypt_load(cd, CRYPT_TCRYPT, &params);
+       if (r < 0)
+               goto out;
+
+       if (opt_readonly)
+               flags |= CRYPT_ACTIVATE_READONLY;
+
+       r = crypt_activate_by_volume_key(cd, activated_name, NULL, 0, flags);
+out:
+       crypt_free(cd);
+       crypt_safe_free(CONST_CAST(char*)params.passphrase);
+       return r;
+}
+
 static int action_remove(int arg __attribute__((unused)))
 {
        struct crypt_device *cd = NULL;
@@ -489,6 +391,84 @@ static int action_status(int arg __attribute__((unused)))
        }
 out:
        crypt_free(cd);
+       if (r == -ENOTSUP)
+               r = 0;
+       return r;
+}
+
+static int action_benchmark(int arg __attribute__((unused)))
+{
+       static struct {
+               char *cipher;
+               char *mode;
+               size_t key_size;
+               size_t iv_size;
+       } bciphers[] = {
+               { "aes",     "cbc", 16, 16 },
+               { "serpent", "cbc", 16, 16 },
+               { "twofish", "cbc", 16, 16 },
+               { "aes",     "cbc", 32, 16 },
+               { "serpent", "cbc", 32, 16 },
+               { "twofish", "cbc", 32, 16 },
+               { "aes",     "xts", 32, 16 },
+               { "serpent", "xts", 32, 16 },
+               { "twofish", "xts", 32, 16 },
+               { "aes",     "xts", 64, 16 },
+               { "serpent", "xts", 64, 16 },
+               { "twofish", "xts", 64, 16 },
+               {  NULL, NULL, 0, 0 }
+       };
+       char *header = "# Tests are approximate using memory only (no storage IO).\n"
+                       "# Algorithm | Key | Encryption | Decryption\n";
+       char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
+       double enc_mbr = 0, dec_mbr = 0;
+       int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
+       int iv_size = 16;
+       int buffer_size = 1024 * 1024;
+       char *c;
+       int i, r;
+
+       if (opt_cipher) {
+               r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
+               if (r < 0) {
+                       log_err(_("No known cipher specification pattern detected.\n"));
+                       return r;
+               }
+               if ((c  = strchr(cipher_mode, '-')))
+                       *c = '\0';
+
+               /* FIXME: not really clever :) */
+               if (strstr(cipher, "des"))
+                       iv_size = 8;
+
+               r = crypt_benchmark(NULL, cipher, cipher_mode,
+                                   key_size / 8, iv_size, buffer_size,
+                                   &enc_mbr, &dec_mbr);
+               if (!r) {
+                       log_std("%s", header);
+                       strncat(cipher, "-", MAX_CIPHER_LEN);
+                       strncat(cipher, cipher_mode, MAX_CIPHER_LEN);
+                       log_std("%11s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
+                               cipher, key_size, enc_mbr, dec_mbr);
+               } else
+                       log_err(_("Cannot benchmark %s.\n"), cipher);
+       } else {
+               log_std("%s", header);
+               for (i = 0; bciphers[i].cipher; i++) {
+                       r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
+                                           bciphers[i].key_size, bciphers[i].iv_size,
+                                           buffer_size, &enc_mbr, &dec_mbr);
+                       snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
+                                bciphers[i].cipher, bciphers[i].mode);
+                       if (!r)
+                               log_std("%11s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
+                                       cipher, bciphers[i].key_size*8, enc_mbr, dec_mbr);
+                       else
+                               log_std("%11s  %4db %12s %12s\n", cipher,
+                                       bciphers[i].key_size*8, _("N/A"), _("N/A"));
+               }
+       }
+
        return r;
 }
 
@@ -527,15 +507,15 @@ static int action_luksRepair(int arg __attribute__((unused)))
                goto out;
 
        /* Currently only LUKS1 allows repair */
-       crypt_set_log_callback(cd, _quiet_log, NULL);
+       crypt_set_log_callback(cd, quiet_log, NULL);
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
-       crypt_set_log_callback(cd, _log, NULL);
+       crypt_set_log_callback(cd, tool_log, NULL);
        if (r == 0) {
                log_verbose( _("No known problems detected for LUKS header.\n"));
                goto out;
        }
 
-       r = _yesDialog(_("Really try to repair LUKS device header?"),
+       r = yesDialog(_("Really try to repair LUKS device header?"),
                       NULL) ? 0 : -EINVAL;
        if (r == 0)
                r = crypt_repair(cd, CRYPT_LUKS1, NULL);
@@ -566,7 +546,7 @@ static int action_luksFormat(int arg __attribute__((unused)))
                r = -ENOMEM;
                goto out;
        }
-       r = _yesDialog(msg, NULL) ? 0 : -EINVAL;
+       r = yesDialog(msg, NULL) ? 0 : -EINVAL;
        free(msg);
        if (r < 0)
                goto out;
@@ -626,7 +606,7 @@ out:
 static int action_luksOpen(int arg __attribute__((unused)))
 {
        struct crypt_device *cd = NULL;
-       const char *data_device, *header_device;
+       const char *data_device, *header_device, *activated_name;
        char *key = NULL;
        uint32_t flags = 0;
        int r, keysize;
@@ -639,6 +619,8 @@ static int action_luksOpen(int arg __attribute__((unused)))
                data_device = NULL;
        }
 
+       activated_name = opt_test_passphrase ? NULL : action_argv[1];
+
        if ((r = crypt_init(&cd, header_device)))
                goto out;
 
@@ -673,15 +655,15 @@ static int action_luksOpen(int arg __attribute__((unused)))
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
                        goto out;
-               r = crypt_activate_by_volume_key(cd, action_argv[1],
+               r = crypt_activate_by_volume_key(cd, activated_name,
                                                 key, keysize, flags);
        } else if (opt_key_file) {
                crypt_set_password_retry(cd, 1);
-               r = crypt_activate_by_keyfile_offset(cd, action_argv[1],
+               r = crypt_activate_by_keyfile_offset(cd, activated_name,
                        opt_key_slot, opt_key_file, opt_keyfile_size,
                        opt_keyfile_offset, flags);
        } else
-               r = crypt_activate_by_passphrase(cd, action_argv[1],
+               r = crypt_activate_by_passphrase(cd, activated_name,
                        opt_key_slot, NULL, 0, flags);
 out:
        crypt_safe_free(key);
@@ -700,7 +682,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
        int i, r;
 
        ki = crypt_keyslot_status(cd, key_slot);
-       if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !_yesDialog(msg_last, NULL))
+       if (ki == CRYPT_SLOT_ACTIVE_LAST && msg_last && !yesDialog(msg_last, NULL))
                return -EPERM;
 
        r = crypt_get_key(msg_pass, &password, &passwordLen,
@@ -727,7 +709,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
                }
        }
 
-       if (r < 0)
+       if (r == -EPERM)
                log_err(_("No key available with this passphrase.\n"));
 out:
        crypt_safe_free(password);
@@ -742,7 +724,7 @@ static int action_luksKillSlot(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
        crypt_set_timeout(cd, opt_timeout);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -785,7 +767,7 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
        crypt_set_timeout(cd, opt_timeout);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
@@ -809,7 +791,7 @@ static int action_luksRemoveKey(int arg __attribute__((unused)))
        log_verbose(_("Key slot %d selected for deletion.\n"), opt_key_slot);
 
        if (crypt_keyslot_status(cd, opt_key_slot) == CRYPT_SLOT_ACTIVE_LAST &&
-           !_yesDialog(_("This is the last keyslot. "
+           !yesDialog(_("This is the last keyslot. "
                          "Device will become unusable after purging this key."),
                        NULL)) {
                r = -EPERM;
@@ -833,7 +815,7 @@ static int action_luksAddKey(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
@@ -972,7 +954,7 @@ static int action_isLuks(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       crypt_set_log_callback(cd, _quiet_log, NULL);
+       crypt_set_log_callback(cd, quiet_log, NULL);
        r = crypt_load(cd, CRYPT_LUKS1, NULL);
 out:
        crypt_free(cd);
@@ -988,7 +970,7 @@ static int action_luksUUID(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
@@ -1013,8 +995,8 @@ static int luksDump_with_volume_key(struct crypt_device *cd)
        unsigned i;
        int r;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
-       if (!_yesDialog(
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
+       if (!yesDialog(
            _("LUKS header dump with volume key is sensitive information\n"
              "which allows access to encrypted partition without passphrase.\n"
              "This dump should be always stored encrypted on safe place."),
@@ -1127,7 +1109,7 @@ static int action_luksBackup(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
 
        r = crypt_header_backup(cd, CRYPT_LUKS1, opt_header_backup_file);
 out:
@@ -1148,24 +1130,13 @@ static int action_luksRestore(int arg __attribute__((unused)))
        if ((r = crypt_init(&cd, action_argv[0])))
                goto out;
 
-       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+       crypt_set_confirm_callback(cd, yesDialog, NULL);
        r = crypt_header_restore(cd, CRYPT_LUKS1, opt_header_backup_file);
 out:
        crypt_free(cd);
        return r;
 }
 
-static __attribute__ ((noreturn)) void usage(poptContext popt_context,
-                                            int exitcode, const char *error,
-                                            const char *more)
-{
-       poptPrintUsage(popt_context, stderr, 0);
-       if (error)
-               log_err("%s: %s\n", more, error);
-       poptFreeContext(popt_context);
-       exit(exitcode);
-}
-
 static void help(poptContext popt_context,
                 enum poptCallbackReason reason __attribute__((unused)),
                 struct poptOption *key,
@@ -1210,19 +1181,6 @@ static void help(poptContext popt_context,
                usage(popt_context, EXIT_SUCCESS, NULL, NULL);
 }
 
-static void _dbg_version_and_cmd(int argc, const char **argv)
-{
-       int i;
-
-       log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
-       for (i = 0; i < argc; i++) {
-               if (i)
-                       log_std(" ");
-               log_std("%s", argv[i]);
-       }
-       log_std("\"\n");
-}
-
 static int run_action(struct action_type *action)
 {
        int r;
@@ -1242,22 +1200,7 @@ static int run_action(struct action_type *action)
                r = 0;
 
        show_status(r);
-
-       /* Translate exit code to simple codes */
-       switch (r) {
-       case 0:         r = EXIT_SUCCESS; break;
-       case -EEXIST:
-       case -EBUSY:    r = 5; break;
-       case -ENOTBLK:
-       case -ENODEV:   r = 4; break;
-       case -ENOMEM:   r = 3; break;
-       case -EPERM:    r = 2; break;
-       case -EINVAL:
-       case -ENOENT:
-       case -ENOSYS:
-       default:        r = EXIT_FAILURE;
-       }
-       return r;
+       return translate_errno(r);
 }
 
 int main(int argc, const char **argv)
@@ -1277,7 +1220,7 @@ int main(int argc, const char **argv)
                { "cipher",            'c',  POPT_ARG_STRING, &opt_cipher,              0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
                { "hash",              'h',  POPT_ARG_STRING, &opt_hash,                0, N_("The hash used to create the encryption key from the passphrase"), NULL },
                { "verify-passphrase", 'y',  POPT_ARG_NONE, &opt_verify_passphrase,     0, N_("Verifies the passphrase by asking for it twice"), NULL },
-               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            0, N_("Read the key from a file."), NULL },
+               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            5, N_("Read the key from a file."), NULL },
                { "master-key-file",  '\0',  POPT_ARG_STRING, &opt_master_key_file,     0, N_("Read the volume (master) key from file."), NULL },
                { "dump-master-key",  '\0',  POPT_ARG_NONE, &opt_dump_master_key,       0, N_("Dump volume (master) key instead of keyslots info."), NULL },
                { "key-size",          's',  POPT_ARG_INT, &opt_key_size,               0, N_("The size of the encryption key"), N_("BITS") },
@@ -1302,15 +1245,16 @@ int main(int argc, const char **argv)
                { "uuid",              '\0', POPT_ARG_STRING, &opt_uuid,                0, N_("UUID for device to use."), NULL },
                { "allow-discards",    '\0', POPT_ARG_NONE, &opt_allow_discards,        0, N_("Allow discards (aka TRIM) requests for device."), NULL },
                { "header",            '\0', POPT_ARG_STRING, &opt_header_device,       0, N_("Device or file with separated LUKS header."), NULL },
+               { "test-passphrase",   '\0', POPT_ARG_NONE, &opt_test_passphrase,       0, N_("Do not activate device, just check passphrase."), NULL },
+               { "hidden",            '\0', POPT_ARG_NONE, &opt_hidden,               0, N_("Use hidden header (hiden TCRYPT device) ."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
        struct action_type *action;
        const char *aname;
        int r;
-       const char *null_action_argv[] = {NULL};
 
-       crypt_set_log_callback(NULL, _log, NULL);
+       crypt_set_log_callback(NULL, tool_log, NULL);
 
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1320,12 +1264,18 @@ int main(int argc, const char **argv)
 
        popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
        poptSetOtherOptionHelp(popt_context,
-                              N_("[OPTION...] <action> <action-specific>]"));
+                              _("[OPTION...] <action> <action-specific>"));
 
        while((r = poptGetNextOpt(popt_context)) > 0) {
                unsigned long long ull_value;
                char *endp;
 
+               if (r == 5) {
+                       if (opt_keyfiles_count < MAX_KEYFILES)
+                               opt_keyfiles[opt_keyfiles_count++] = poptGetOptArg(popt_context);
+                       continue;
+               }
+
                errno = 0;
                ull_value = strtoull(popt_tmp, &endp, 0);
                if (*endp || !*popt_tmp ||
@@ -1388,30 +1338,34 @@ int main(int argc, const char **argv)
 
        /* FIXME: rewrite this from scratch */
 
-       if (opt_shared && strcmp(aname, "create")) {
+       if (opt_shared && strcmp(aname, "create"))
                usage(popt_context, EXIT_FAILURE,
                      _("Option --shared is allowed only for create operation.\n"),
                      poptGetInvocationName(popt_context));
-       }
 
        if (opt_allow_discards &&
            strcmp(aname, "luksOpen") &&
            strcmp(aname, "create") &&
-           strcmp(aname, "loopaesOpen")) {
+           strcmp(aname, "loopaesOpen"))
                usage(popt_context, EXIT_FAILURE,
                      _("Option --allow-discards is allowed only for luksOpen, loopaesOpen and create operation.\n"),
                      poptGetInvocationName(popt_context));
-       }
 
        if (opt_key_size &&
           strcmp(aname, "luksFormat") &&
           strcmp(aname, "create") &&
-          strcmp(aname, "loopaesOpen")) {
+          strcmp(aname, "loopaesOpen") &&
+          strcmp(aname, "benchmark"))
                usage(popt_context, EXIT_FAILURE,
-                     _("Option --key-size is allowed only for luksFormat, create and loopaesOpen.\n"
+                     _("Option --key-size is allowed only for luksFormat, create, loopaesOpen and benchmark.\n"
                        "To limit read from keyfile use --keyfile-size=(bytes)."),
                      poptGetInvocationName(popt_context));
-       }
+
+       if (opt_test_passphrase &&
+          strcmp(aname, "luksOpen"))
+               usage(popt_context, EXIT_FAILURE,
+                     _("Option --test-passphrase is allowed only for luksOpen.\n"),
+                     poptGetInvocationName(popt_context));
 
        if (opt_key_size % 8)
                usage(popt_context, EXIT_FAILURE,
@@ -1435,11 +1389,10 @@ int main(int argc, const char **argv)
        }
 
        if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0 ||
-           opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0) {
+           opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0)
                usage(popt_context, EXIT_FAILURE,
                      _("Negative number for option not permitted."),
                      poptGetInvocationName(popt_context));
-       }
 
        if (opt_random && opt_urandom)
                usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."),
@@ -1467,10 +1420,15 @@ int main(int argc, const char **argv)
                _("Option --offset is supported only for create and loopaesOpen commands.\n"),
                poptGetInvocationName(popt_context));
 
+       if (opt_hidden && strcmp(aname, "tcryptOpen"))
+               usage(popt_context, EXIT_FAILURE,
+               _("Option --hidden is supported only for tcryptOpen command.\n"),
+               poptGetInvocationName(popt_context));
+
        if (opt_debug) {
                opt_verbose = 1;
                crypt_set_debug_level(-1);
-               _dbg_version_and_cmd(argc, argv);
+               dbg_version_and_cmd(argc, argv);
        }
 
        r = run_action(action);