Fix luksFormat to properly use key file with --master-key-file switch.
[platform/upstream/cryptsetup.git] / src / cryptsetup.c
index e86b626..3a4a2c9 100644 (file)
@@ -26,6 +26,8 @@ static char *opt_master_key_file = NULL;
 static char *opt_header_backup_file = NULL;
 static char *opt_uuid = NULL;
 static unsigned int opt_key_size = 0;
+static unsigned int opt_keyfile_size = 0;
+static unsigned int opt_new_keyfile_size = 0;
 static int opt_key_slot = CRYPT_ANY_SLOT;
 static uint64_t opt_size = 0;
 static uint64_t opt_offset = 0;
@@ -309,16 +311,19 @@ static int _read_mk(const char *file, char **key, int keysize)
        fd = open(file, O_RDONLY);
        if (fd == -1) {
                log_err("Cannot read keyfile %s.\n", file);
-               return -EINVAL;
+               goto fail;
        }
        if ((read(fd, *key, keysize) != keysize)) {
                log_err("Cannot read %d bytes from keyfile %s.\n", keysize, file);
                close(fd);
-               crypt_safe_free(*key);
-               return -EINVAL;
+               goto fail;
        }
        close(fd);
        return 0;
+fail:
+       crypt_safe_free(*key);
+       *key = NULL;
+       return -EINVAL;
 }
 
 static int action_luksFormat(int arg)
@@ -334,13 +339,6 @@ static int action_luksFormat(int arg)
                .data_alignment = opt_align_payload,
        };
 
-       /* Avoid overwriting possibly wrong part of device than user requested by rejecting these options */
-       if (opt_offset || opt_skip) {
-               log_err("Options --offset and --skip are not supported for luksFormat.\n");
-               r = -EINVAL;
-               goto out;;
-       }
-
        if (action_argc > 1) {
                key_file = action_argv[1];
                if (opt_key_file)
@@ -353,13 +351,10 @@ static int action_luksFormat(int arg)
                r = -ENOMEM;
                goto out;
        }
-       r = yesDialog(msg);
+       r = yesDialog(msg) ? 0 : -EINVAL;
        free(msg);
-
-       if (!r) {
-               r = -EINVAL;
+       if (r < 0)
                goto out;
-       }
 
        r = crypt_parse_name_and_mode(opt_cipher ?: DEFAULT_CIPHER(LUKS1),
                                      cipher, cipher_mode);
@@ -385,39 +380,30 @@ static int action_luksFormat(int arg)
        else if (opt_urandom)
                crypt_set_rng_type(cd, CRYPT_RNG_URANDOM);
 
+       r = -EINVAL;
+       crypt_get_key(_("Enter LUKS passphrase: "),
+                     &password, &passwordLen,
+                     opt_keyfile_size, key_file,
+                     opt_timeout,
+                     opt_batch_mode ? 0 : 1, /* always verify */
+                     cd);
+       if(!password)
+               goto out;
+
        if (opt_master_key_file) {
                r = _read_mk(opt_master_key_file, &key, keysize);
                if (r < 0)
                        goto out;
+       }
 
-               r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
-                                opt_uuid, key, keysize, &params);
-               if (r < 0)
-                       goto out;
-
-               r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
-                                                   key, keysize, NULL, 0);
-       } else {
-               crypt_get_key(_("Enter LUKS passphrase: "),
-                             &password, &passwordLen, 0,
-                             key_file, opt_timeout,
-                             opt_batch_mode ? 0 : 1, /* always verify */
-                             cd);
-
-               if(!password) {
-                       r = -EINVAL;
-                       goto out;
-               }
-
-               r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
-                                opt_uuid, NULL, keysize, &params);
-               if (r < 0)
-                       goto out;
+       r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
+                        opt_uuid, key, keysize, &params);
+       if (r < 0)
+               goto out;
 
-               /* Add keyslot using internally stored volume key generated during format */
-               r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
-                                                   NULL, 0, password, passwordLen);
-       }
+       r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
+                                           key, keysize,
+                                           password, passwordLen);
 out:
        crypt_free(cd);
        crypt_safe_free(key);
@@ -453,9 +439,8 @@ static int action_luksOpen(int arg)
 
        if (opt_key_file) {
                crypt_set_password_retry(cd, 1);
-               /* limit bytes read from keyfile using opt_key_size*/
                r = crypt_activate_by_keyfile(cd, action_argv[1],
-                       CRYPT_ANY_SLOT, opt_key_file, opt_key_size / 8,
+                       CRYPT_ANY_SLOT, opt_key_file, opt_keyfile_size,
                        flags);
        } else
                r = crypt_activate_by_passphrase(cd, action_argv[1],
@@ -530,8 +515,8 @@ static int action_luksAddKey(int arg)
                                                    key, keysize, NULL, 0);
        } else if (opt_key_file || opt_new_key_file) {
                r = crypt_keyslot_add_by_keyfile(cd, opt_key_slot,
-                                                opt_key_file, 0,
-                                                opt_new_key_file, 0);
+                                                opt_key_file, opt_keyfile_size,
+                                                opt_new_key_file, opt_new_keyfile_size);
        } else {
                r = crypt_keyslot_add_by_passphrase(cd, opt_key_slot,
                                                    NULL, 0, NULL, 0);
@@ -617,7 +602,7 @@ static int action_luksResume(int arg)
 
        if (opt_key_file)
                r = crypt_resume_by_keyfile(cd, action_argv[0], CRYPT_ANY_SLOT,
-                                           opt_key_file, opt_key_size / 8);
+                                           opt_key_file, opt_keyfile_size);
        else
                r = crypt_resume_by_passphrase(cd, action_argv[0], CRYPT_ANY_SLOT,
                                               NULL, 0);
@@ -760,9 +745,11 @@ int main(int argc, 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 (can be /dev/random)"), NULL },
+               { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            0, 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 },
                { "key-size",          's',  POPT_ARG_INT, &opt_key_size,               0, N_("The size of the encryption key"), N_("BITS") },
+               { "keyfile-size",      'l',  POPT_ARG_INT, &opt_keyfile_size,           0, N_("Limits the read from keyfile"), N_("bytes") },
+               { "new-keyfile-size", '\0',  POPT_ARG_INT, &opt_new_keyfile_size,       0, N_("Limits the read from newly added keyfile"), N_("bytes") },
                { "key-slot",          'S',  POPT_ARG_INT, &opt_key_slot,               0, N_("Slot number for new key (default is first free)"), NULL },
                { "size",              'b',  POPT_ARG_STRING, &popt_tmp,                1, N_("The size of the device"), N_("SECTORS") },
                { "offset",            'o',  POPT_ARG_STRING, &popt_tmp,                2, N_("The start offset in the backend device"), N_("SECTORS") },
@@ -830,6 +817,25 @@ int main(int argc, char **argv)
                exit(0);
        }
 
+       if (!(aname = (char *)poptGetArg(popt_context)))
+               usage(popt_context, 1, _("Argument <action> missing."),
+                     poptGetInvocationName(popt_context));
+       for(action = action_types; action->type; action++)
+               if (strcmp(action->type, aname) == 0)
+                       break;
+       if (!action->type)
+               usage(popt_context, 1, _("Unknown action."),
+                     poptGetInvocationName(popt_context));
+
+       if (opt_key_size &&
+          strcmp(aname, "luksFormat") &&
+          strcmp(aname, "create")) {
+               usage(popt_context, 1,
+                     _("Option --key-size is allowed only for luksFormat and create.\n"
+                       "To limit read from keyfile use --keyfile-size=(bytes)."),
+                     poptGetInvocationName(popt_context));
+       }
+
        if (opt_key_size % 8)
                usage(popt_context, 1,
                      _("Key size must be a multiple of 8 bits"),
@@ -842,16 +848,6 @@ int main(int argc, char **argv)
                      poptGetInvocationName(popt_context));
        }
 
-       if (!(aname = (char *)poptGetArg(popt_context)))
-               usage(popt_context, 1, _("Argument <action> missing."),
-                     poptGetInvocationName(popt_context));
-       for(action = action_types; action->type; action++)
-               if (strcmp(action->type, aname) == 0)
-                       break;
-       if (!action->type)
-               usage(popt_context, 1, _("Unknown action."),
-                     poptGetInvocationName(popt_context));
-
        if (opt_random && opt_urandom)
                usage(popt_context, 1, _("Only one of --use-[u]random options is allowed."),
                      poptGetInvocationName(popt_context));
@@ -863,6 +859,10 @@ int main(int argc, char **argv)
                usage(popt_context, 1, _("Option --uuid is allowed only for luksFormat and luksUUID."),
                      poptGetInvocationName(popt_context));
 
+       if ((opt_offset || opt_skip) && strcmp(aname, "create"))
+               usage(popt_context, 1, _("Options --offset and --skip are supported only for create command.\n"),
+                     poptGetInvocationName(popt_context));
+
        action_argc = 0;
        action_argv = poptGetArgs(popt_context);
        /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */