Fix luksFormat to properly use key file with --master-key-file switch.
[platform/upstream/cryptsetup.git] / src / cryptsetup.c
index ac6f3aa..3a4a2c9 100644 (file)
@@ -24,7 +24,10 @@ static int opt_verify_passphrase = 0;
 static char *opt_key_file = NULL;
 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;
@@ -308,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)
@@ -333,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)
@@ -352,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);
@@ -384,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,
-                                NULL, 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_verify_passphrase && !opt_batch_mode,
-                             cd);
-
-               if(!password) {
-                       r = -EINVAL;
-                       goto out;
-               }
-
-               r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
-                                NULL, 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);
@@ -452,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],
@@ -529,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);
@@ -554,12 +540,30 @@ static int action_isLuks(int arg)
 
 static int action_luksUUID(int arg)
 {
-       struct crypt_options options = {
-               .device = action_argv[0],
-               .icb = &cmd_icb,
-       };
+       struct crypt_device *cd = NULL;
+       const char *existing_uuid = NULL;
+       int r;
+
+       if ((r = crypt_init(&cd, action_argv[0])))
+               goto out;
+
+       crypt_set_log_callback(cd, _log, NULL);
+       crypt_set_confirm_callback(cd, _yesDialog, NULL);
+
+       if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
+               goto out;
+
+       if (opt_uuid)
+               r = crypt_set_uuid(cd, opt_uuid);
+       else {
+               existing_uuid = crypt_get_uuid(cd);
+               log_std("%s\n", existing_uuid ?: "");
+               r = existing_uuid ? 0 : 1;
+       }
+out:
+       crypt_free(cd);
+       return r;
 
-       return crypt_luksUUID(&options);
 }
 
 static int action_luksDump(int arg)
@@ -598,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);
@@ -741,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") },
@@ -759,6 +765,7 @@ int main(int argc, char **argv)
                { "header-backup-file",'\0', POPT_ARG_STRING, &opt_header_backup_file,  0, N_("File with LUKS header and keyslots backup."), NULL },
                { "use-random",        '\0', POPT_ARG_NONE, &opt_random,                0, N_("Use /dev/random for generating volume key."), NULL },
                { "use-urandom",       '\0', POPT_ARG_NONE, &opt_urandom,               0, N_("Use /dev/urandom for generating volume key."), NULL },
+               { "uuid",              '\0',  POPT_ARG_STRING, &opt_uuid,               0, N_("UUID for device to use."), NULL },
                POPT_TABLEEND
        };
        poptContext popt_context;
@@ -810,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"),
@@ -822,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));
@@ -839,6 +855,14 @@ int main(int argc, char **argv)
                usage(popt_context, 1, _("Option --use-[u]random is allowed only for luksFormat."),
                      poptGetInvocationName(popt_context));
 
+       if (opt_uuid && strcmp(aname, "luksFormat") && strcmp(aname, "luksUUID"))
+               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 */