* Add --header option for detached metadata (on-disk LUKS header) device.
authorMilan Broz <gmazyland@gmail.com>
Wed, 20 Jul 2011 17:39:26 +0000 (17:39 +0000)
committerMilan Broz <gmazyland@gmail.com>
Wed, 20 Jul 2011 17:39:26 +0000 (17:39 +0000)
* Add crypt_init_by_name_and_header() and crypt_set_data_device() to API.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@575 36d66b0a-2a48-0410-832c-cd162a569da5

ChangeLog
lib/libcryptsetup.h
lib/libcryptsetup.sym
lib/setup.c
man/cryptsetup.8
src/cryptsetup.c

index 1d8241a..3b57943 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,8 @@
        * Do not allow key retrieval while suspended (key could be wiped).
        * Do not allow suspend for non-LUKS devices.
        * Support retries and timeout parameters for luksSuspend.
+       * Add --header option for detached metadata (on-disk LUKS header) device.
+       * Add crypt_init_by_name_and_header() and crypt_set_data_device() to API.
 
 2011-07-07  Milan Broz  <mbroz@redhat.com>
        * Remove old API functions (all functions using crypt_options).
index 9258826..a533b66 100644 (file)
@@ -22,14 +22,23 @@ struct crypt_device; /* crypt device handle */
 int crypt_init(struct crypt_device **cd, const char *device);
 
 /**
- * Initialise crypt device handle from provided active device name
+ * Initialise crypt device handle from provided active device name,
+ * and, optionally, from separate metadata (header) device
  * and check if provided device exists.
  *
  * Returns 0 on success or negative errno value otherwise.
  *
  * @cd - crypt device handle
  * @name - name of active crypt device
+ * @header_device - optional device containing on-disk header
+ *  (NULL if it the same as underlying device on there is no on-disk header)
+ *
+ * crypt_init_by_name is quivalent to calling
+ * crypt_init_by_name_and_header(cd, name, NULL);
  */
+int crypt_init_by_name_and_header(struct crypt_device **cd,
+                                 const char *name,
+                                 const char *header_device);
 int crypt_init_by_name(struct crypt_device **cd, const char *name);
 
 /**
@@ -113,6 +122,13 @@ void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_m
 void crypt_set_password_verify(struct crypt_device *cd, int password_verify);
 
 /**
+ * Set data device (ciphertext device) if LUKS header is separated
+ * @cd - crypt device handle
+ * @device - path to device
+ */
+int crypt_set_data_device(struct crypt_device *cd, const char *device);
+
+/**
  * Set which RNG (random number generator) is used for generating long term key
  * @cd - crypt device handle
  * @rng_type - kernel random number generator to use
index 10718b5..53ccaad 100644 (file)
@@ -2,6 +2,7 @@ CRYPTSETUP_1.0 {
        global:
                crypt_init;
                crypt_init_by_name;
+               crypt_init_by_name_and_header;
                crypt_set_log_callback;
                crypt_set_confirm_callback;
                crypt_set_password_callback;
@@ -10,6 +11,7 @@ CRYPTSETUP_1.0 {
                crypt_set_iterarion_time;
                crypt_set_password_verify;
                crypt_set_uuid;
+               crypt_set_data_device;
 
                crypt_memory_lock;
                crypt_format;
index 08eaf6f..77e771f 100644 (file)
@@ -36,6 +36,8 @@ struct crypt_device {
        char *type;
 
        char *device;
+       char *metadata_device;
+
        char *backing_file;
        int loop_fd;
        struct volume_key *volume_key;
@@ -118,6 +120,11 @@ void logger(struct crypt_device *cd, int level, const char *file,
        free(target);
 }
 
+static const char *mdata_device(struct crypt_device *cd)
+{
+       return cd->metadata_device ?: cd->device;
+}
+
 static int init_crypto(struct crypt_device *ctx)
 {
        int r;
@@ -273,7 +280,7 @@ static int key_from_terminal(struct crypt_device *cd, char *msg, char **key,
 
        *key = NULL;
        if(!msg && asprintf(&prompt, _("Enter passphrase for %s: "),
-                           cd->backing_file ?: cd->device) < 0)
+                           cd->backing_file ?: crypt_get_device_name(cd)) < 0)
                return -ENOMEM;
 
        if (!msg)
@@ -317,7 +324,7 @@ static int volume_key_by_terminal_passphrase(struct crypt_device *cd, int keyslo
                if(r < 0)
                        goto out;
 
-               r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), keyslot, passphrase_read,
                                           passphrase_size_read, &cd->hdr, vk, cd);
                if (r == -EPERM)
                        eperm = 1;
@@ -469,7 +476,42 @@ bad:
        return r;
 }
 
-int crypt_init_by_name(struct crypt_device **cd, const char *name)
+int crypt_set_data_device(struct crypt_device *cd, const char *device)
+{
+       char *data_device;
+       int r;
+
+       log_dbg("Setting ciphertext data device to %s.", device ?: "(none)");
+
+       if (!isLUKS(cd->type)) {
+               log_err(cd, _("This operation is not supported for this device type.\n"));
+               return  -EINVAL;
+       }
+
+       /* metadata device must be set */
+       if (!cd->device)
+               return -EINVAL;
+
+       r = device_ready(NULL, device, O_RDONLY);
+       if (r < 0)
+               return r;
+
+       if (!(data_device = strdup(device)))
+               return -ENOMEM;
+
+       if (!cd->metadata_device)
+               cd->metadata_device = cd->device;
+       else
+               free(cd->device);
+
+       cd->device = data_device;
+
+       return 0;
+}
+
+int crypt_init_by_name_and_header(struct crypt_device **cd,
+                                 const char *name,
+                                 const char *header_device)
 {
        crypt_status_info ci;
        struct crypt_dm_active_device dmd;
@@ -494,23 +536,46 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name)
                goto out;
 
        *cd = NULL;
-       r = crypt_init(cd, dmd.device);
-
-       /* Underlying device disappeared but mapping still active */
-       if (!dmd.device || r == -ENOTBLK)
-               log_verbose(NULL, _("Underlying device for crypt device %s disappeared.\n"),
-                           name);
-
-       /* Underlying device is not readable but crypt mapping exists */
-       if (r == -ENOTBLK) {
-               free((char*)dmd.device);
-               dmd.device = NULL;
-               r = crypt_init(cd, NULL);
+
+       if (header_device) {
+               r = crypt_init(cd, header_device);
+       } else {
+               r = crypt_init(cd, dmd.device);
+
+               /* Underlying device disappeared but mapping still active */
+               if (!dmd.device || r == -ENOTBLK)
+                       log_verbose(NULL, _("Underlying device for crypt device %s disappeared.\n"),
+                                   name);
+
+               /* Underlying device is not readable but crypt mapping exists */
+               if (r == -ENOTBLK) {
+                       free((char*)dmd.device);
+                       dmd.device = NULL;
+                       r = crypt_init(cd, NULL);
+               }
        }
 
        if (r < 0)
                goto out;
 
+       if (dmd.uuid) {
+               if (!strncmp(CRYPT_PLAIN, dmd.uuid, sizeof(CRYPT_PLAIN)-1))
+                       (*cd)->type = strdup(CRYPT_PLAIN);
+               else if (!strncmp(CRYPT_LOOPAES, dmd.uuid, sizeof(CRYPT_LOOPAES)-1))
+                       (*cd)->type = strdup(CRYPT_LOOPAES);
+               else if (!strncmp(CRYPT_LUKS1, dmd.uuid, sizeof(CRYPT_LUKS1)-1))
+                       (*cd)->type = strdup(CRYPT_LUKS1);
+               else
+                       log_dbg("Unknown UUID set, some parameters are not set.");
+       } else
+               log_dbg("Active device has no UUID set, some parameters are not set.");
+
+       if (header_device) {
+               r = crypt_set_data_device(*cd, dmd.device);
+               if (r < 0)
+                       goto out;
+       }
+
        /* Try to initialise basic parameters from active device */
 
        if (!(*cd)->backing_file && dmd.device && crypt_loop_device(dmd.device) &&
@@ -519,46 +584,45 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name)
                goto out;
        }
 
-       if (dmd.uuid) {
-               if (!strncmp(CRYPT_PLAIN, dmd.uuid, sizeof(CRYPT_PLAIN)-1)) {
-                       (*cd)->type = strdup(CRYPT_PLAIN);
-                       (*cd)->plain_uuid = strdup(dmd.uuid);
-                       (*cd)->plain_hdr.hash = NULL; /* no way to get this */
-                       (*cd)->plain_hdr.offset = dmd.offset;
-                       (*cd)->plain_hdr.skip = dmd.iv_offset;
-
-                       r = crypt_parse_name_and_mode(dmd.cipher, cipher, NULL, cipher_mode);
-                       if (!r) {
-                               (*cd)->plain_cipher = strdup(cipher);
-                               (*cd)->plain_cipher_mode = strdup(cipher_mode);
-                       }
-               } else if (!strncmp(CRYPT_LOOPAES, dmd.uuid, sizeof(CRYPT_LOOPAES)-1)) {
-                       (*cd)->type = strdup(CRYPT_LOOPAES);
-                       (*cd)->loopaes_uuid = strdup(dmd.uuid);
-                       (*cd)->loopaes_hdr.offset = dmd.offset;
-
-                       r = crypt_parse_name_and_mode(dmd.cipher, cipher,
-                                                     &key_nums, cipher_mode);
-                       if (!r) {
-                               (*cd)->loopaes_cipher = strdup(cipher);
-                               (*cd)->loopaes_cipher_mode = strdup(cipher_mode);
-                               /* version 3 uses last key for IV */
-                               if (dmd.vk->keylength % key_nums)
-                                       key_nums++;
-                               (*cd)->loopaes_key_size = dmd.vk->keylength / key_nums;
-                       }
-               } else if (!strncmp(CRYPT_LUKS1, dmd.uuid, sizeof(CRYPT_LUKS1)-1)) {
-                       if (dmd.device) {
-                               r = crypt_load(*cd, CRYPT_LUKS1, NULL);
-                               if (r < 0) {
-                                       log_dbg("LUKS device header does not match active device.");
-                                       /* initialise empty context */
-                                       r = 0;
-                               }
+       if (isPLAIN((*cd)->type)) {
+               (*cd)->type = strdup(CRYPT_PLAIN);
+               (*cd)->plain_uuid = strdup(dmd.uuid);
+               (*cd)->plain_hdr.hash = NULL; /* no way to get this */
+               (*cd)->plain_hdr.offset = dmd.offset;
+               (*cd)->plain_hdr.skip = dmd.iv_offset;
+
+               r = crypt_parse_name_and_mode(dmd.cipher, cipher, NULL, cipher_mode);
+               if (!r) {
+                       (*cd)->plain_cipher = strdup(cipher);
+                       (*cd)->plain_cipher_mode = strdup(cipher_mode);
+               }
+       } else if (isLOOPAES((*cd)->type)) {
+               (*cd)->type = strdup(CRYPT_LOOPAES);
+               (*cd)->loopaes_uuid = strdup(dmd.uuid);
+               (*cd)->loopaes_hdr.offset = dmd.offset;
+
+               r = crypt_parse_name_and_mode(dmd.cipher, cipher,
+                                             &key_nums, cipher_mode);
+               if (!r) {
+                       (*cd)->loopaes_cipher = strdup(cipher);
+                       (*cd)->loopaes_cipher_mode = strdup(cipher_mode);
+                       /* version 3 uses last key for IV */
+                       if (dmd.vk->keylength % key_nums)
+                               key_nums++;
+                       (*cd)->loopaes_key_size = dmd.vk->keylength / key_nums;
+               }
+       } else if (isLUKS((*cd)->type)) {
+               if (mdata_device(*cd)) {
+                       r = crypt_load(*cd, CRYPT_LUKS1, NULL);
+                       if (r < 0) {
+                               log_dbg("LUKS device header does not match active device.");
+                               free((*cd)->type);
+                               (*cd)->type = NULL;
+                               r = 0;
+                               goto out;
                        }
                }
-       } else
-               log_dbg("Active device has no UUID set, some parameters are not set.");
+       }
 
 out:
        if (r < 0) {
@@ -572,6 +636,11 @@ out:
        return r;
 }
 
+int crypt_init_by_name(struct crypt_device **cd, const char *name)
+{
+       return crypt_init_by_name_and_header(cd, name, NULL);
+}
+
 static int _crypt_format_plain(struct crypt_device *cd,
                               const char *cipher,
                               const char *cipher_mode,
@@ -624,7 +693,7 @@ static int _crypt_format_luks1(struct crypt_device *cd,
        unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT;
        unsigned long alignment_offset = 0;
 
-       if (!cd->device) {
+       if (!mdata_device(cd)) {
                log_err(cd, _("Can't format LUKS without device.\n"));
                return -EINVAL;
        }
@@ -638,6 +707,7 @@ static int _crypt_format_luks1(struct crypt_device *cd,
        if(!cd->volume_key)
                return -ENOMEM;
 
+       //FIXME: external metadata, ignore alignment
        if (params && params->data_alignment)
                required_alignment = params->data_alignment * SECTOR_SIZE;
        else
@@ -654,19 +724,19 @@ static int _crypt_format_luks1(struct crypt_device *cd,
                return r;
 
        /* Wipe first 8 sectors - fs magic numbers etc. */
-       r = wipe_device_header(cd->device, 8);
+       r = wipe_device_header(mdata_device(cd), 8);
        if(r < 0) {
                if (r == -EBUSY)
                        log_err(cd, _("Cannot format device %s which is still in use.\n"),
-                               cd->device);
+                               mdata_device(cd));
                else
                        log_err(cd, _("Cannot wipe header on device %s.\n"),
-                               cd->device);
+                               mdata_device(cd));
 
                return r;
        }
 
-       r = LUKS_write_phdr(cd->device, &cd->hdr, cd);
+       r = LUKS_write_phdr(mdata_device(cd), &cd->hdr, cd);
 
        return r;
 }
@@ -677,7 +747,7 @@ static int _crypt_format_loopaes(struct crypt_device *cd,
                                 size_t volume_key_size,
                                 struct crypt_params_loopaes *params)
 {
-       if (!cd->device) {
+       if (!mdata_device(cd)) {
                log_err(cd, _("Can't format LOOPAES without device.\n"));
                return -EINVAL;
        }
@@ -717,7 +787,7 @@ int crypt_format(struct crypt_device *cd,
        if (!type)
                return -EINVAL;
 
-       log_dbg("Formatting device %s as type %s.", cd->device ?: "(none)", type);
+       log_dbg("Formatting device %s as type %s.", mdata_device(cd) ?: "(none)", type);
 
        r = init_crypto(cd);
        if (r < 0)
@@ -756,9 +826,9 @@ int crypt_load(struct crypt_device *cd,
        int r;
 
        log_dbg("Trying to load %s crypt type from device %s.",
-               requested_type ?: "any", cd->device ?: "(none)");
+               requested_type ?: "any", mdata_device(cd) ?: "(none)");
 
-       if (!cd->device)
+       if (!mdata_device(cd))
                return -EINVAL;
 
        if (requested_type && !isLUKS(requested_type))
@@ -768,10 +838,11 @@ int crypt_load(struct crypt_device *cd,
        if (r < 0)
                return r;
 
-       r = LUKS_read_phdr(cd->device, &hdr, 1, cd);
+       r = LUKS_read_phdr(mdata_device(cd), &hdr, 1, cd);
 
        if (!r) {
                memcpy(&cd->hdr, &hdr, sizeof(hdr));
+               free(cd->type);
                cd->type = strdup(CRYPT_LUKS1);
                if (!cd->type)
                        r = -ENOMEM;
@@ -834,19 +905,19 @@ int crypt_set_uuid(struct crypt_device *cd, const char *uuid)
 
        if (uuid && !strncmp(uuid, cd->hdr.uuid, sizeof(cd->hdr.uuid))) {
                log_dbg("UUID is the same as requested (%s) for device %s.",
-                       uuid, cd->device);
+                       uuid, mdata_device(cd));
                return 0;
        }
 
        if (uuid)
-               log_dbg("Requested new UUID change to %s for %s.", uuid, cd->device);
+               log_dbg("Requested new UUID change to %s for %s.", uuid, mdata_device(cd));
        else
-               log_dbg("Requested new UUID refresh for %s.", cd->device);
+               log_dbg("Requested new UUID refresh for %s.", mdata_device(cd));
 
        if (!crypt_confirm(cd, _("Do you really want to change UUID of device?")))
                return -EPERM;
 
-       return LUKS_hdr_uuid_set(cd->device, &cd->hdr, uuid, cd);
+       return LUKS_hdr_uuid_set(mdata_device(cd), &cd->hdr, uuid, cd);
 }
 
 int crypt_header_backup(struct crypt_device *cd,
@@ -863,9 +934,9 @@ int crypt_header_backup(struct crypt_device *cd,
                return r;
 
        log_dbg("Requested header backup of device %s (%s) to "
-               "file %s.", cd->device, requested_type, backup_file);
+               "file %s.", mdata_device(cd), requested_type, backup_file);
 
-       return LUKS_hdr_backup(backup_file, cd->device, &cd->hdr, cd);
+       return LUKS_hdr_backup(backup_file, mdata_device(cd), &cd->hdr, cd);
 }
 
 int crypt_header_restore(struct crypt_device *cd,
@@ -883,15 +954,15 @@ int crypt_header_restore(struct crypt_device *cd,
                return r;
 
        log_dbg("Requested header restore to device %s (%s) from "
-               "file %s.", cd->device, requested_type, backup_file);
+               "file %s.", mdata_device(cd), requested_type, backup_file);
 
-       return LUKS_hdr_restore(backup_file, cd->device, &cd->hdr, cd);
+       return LUKS_hdr_restore(backup_file, mdata_device(cd), &cd->hdr, cd);
 }
 
 void crypt_free(struct crypt_device *cd)
 {
        if (cd) {
-               log_dbg("Releasing crypt device %s context.", cd->device);
+               log_dbg("Releasing crypt device %s context.", mdata_device(cd));
 
                if (cd->loop_fd != -1)
                        close(cd->loop_fd);
@@ -900,6 +971,7 @@ void crypt_free(struct crypt_device *cd)
                crypt_free_volume_key(cd->volume_key);
 
                free(cd->device);
+               free(cd->metadata_device);
                free(cd->backing_file);
                free(cd->type);
 
@@ -989,7 +1061,7 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
        }
 
        if (passphrase) {
-               r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), keyslot, passphrase,
                                           passphrase_size, &cd->hdr, &vk, cd);
        } else
                r = volume_key_by_terminal_passphrase(cd, keyslot, &vk);
@@ -1044,7 +1116,7 @@ int crypt_resume_by_keyfile(struct crypt_device *cd,
        if (r < 0)
                goto out;
 
-       r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
+       r = LUKS_open_key_with_hdr(mdata_device(cd), keyslot, passphrase_read,
                                   passphrase_size_read, &cd->hdr, &vk, cd);
        if (r < 0)
                goto out;
@@ -1096,7 +1168,7 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
                }
        } else if (passphrase) {
                /* Passphrase provided, use it to unlock existing keyslot */
-               r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, passphrase,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), CRYPT_ANY_SLOT, passphrase,
                                           passphrase_size, &cd->hdr, &vk, cd);
        } else {
                /* Passphrase not provided, ask first and use it to unlock existing keyslot */
@@ -1105,7 +1177,7 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
                if (r < 0)
                        goto out;
 
-               r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), CRYPT_ANY_SLOT, password,
                                           passwordLen, &cd->hdr, &vk, cd);
                crypt_safe_free(password);
        }
@@ -1123,7 +1195,7 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
                        goto out;
        }
 
-       r = LUKS_set_key(cd->device, keyslot, new_password, new_passwordLen,
+       r = LUKS_set_key(mdata_device(cd), keyslot, new_password, new_passwordLen,
                         &cd->hdr, vk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
        if(r < 0) goto out;
 
@@ -1180,7 +1252,7 @@ int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
                if (r < 0)
                        goto out;
 
-               r = LUKS_open_key_with_hdr(cd->device, CRYPT_ANY_SLOT, password, passwordLen,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), CRYPT_ANY_SLOT, password, passwordLen,
                                           &cd->hdr, &vk, cd);
        }
 
@@ -1197,7 +1269,7 @@ int crypt_keyslot_add_by_keyfile(struct crypt_device *cd,
        if (r < 0)
                goto out;
 
-       r = LUKS_set_key(cd->device, keyslot, new_password, new_passwordLen,
+       r = LUKS_set_key(mdata_device(cd), keyslot, new_password, new_passwordLen,
                         &cd->hdr, vk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
 out:
        crypt_safe_free(password);
@@ -1251,7 +1323,7 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
                passphrase_size = new_passwordLen;
        }
 
-       r = LUKS_set_key(cd->device, keyslot, passphrase, passphrase_size,
+       r = LUKS_set_key(mdata_device(cd), keyslot, passphrase, passphrase_size,
                         &cd->hdr, vk, cd->iteration_time, &cd->PBKDF2_per_sec, cd);
 out:
        crypt_safe_free(new_password);
@@ -1281,7 +1353,7 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot)
                return -EINVAL;
        }
 
-       return LUKS_del_key(cd->device, keyslot, &cd->hdr, cd);
+       return LUKS_del_key(mdata_device(cd), keyslot, &cd->hdr, cd);
 }
 
 // activation/deactivation of device mapping
@@ -1337,7 +1409,7 @@ int crypt_activate_by_passphrase(struct crypt_device *cd,
        } else if (isLUKS(cd->type)) {
                /* provided passphrase, do not retry */
                if (passphrase) {
-                       r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
+                       r = LUKS_open_key_with_hdr(mdata_device(cd), keyslot, passphrase,
                                                   passphrase_size, &cd->hdr, &vk, cd);
                } else
                        r = volume_key_by_terminal_passphrase(cd, keyslot, &vk);
@@ -1408,7 +1480,7 @@ int crypt_activate_by_keyfile(struct crypt_device *cd,
                          &passphrase_size_read, keyfile, keyfile_size);
                if (r < 0)
                        goto out;
-               r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase_read,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), keyslot, passphrase_read,
                                           passphrase_size_read, &cd->hdr, &vk, cd);
                if (r < 0)
                        goto out;
@@ -1567,7 +1639,7 @@ int crypt_volume_key_get(struct crypt_device *cd,
                if (r < 0)
                        log_err(cd, _("Cannot retrieve volume key for plain device.\n"));
        } else if (isLUKS(cd->type)) {
-               r = LUKS_open_key_with_hdr(cd->device, keyslot, passphrase,
+               r = LUKS_open_key_with_hdr(mdata_device(cd), keyslot, passphrase,
                                        passphrase_size, &cd->hdr, &vk, cd);
 
        } else
@@ -1695,7 +1767,7 @@ int crypt_dump(struct crypt_device *cd)
                return -EINVAL;
        }
 
-       log_std(cd, "LUKS header information for %s\n\n", cd->device);
+       log_std(cd, "LUKS header information for %s\n\n", mdata_device(cd));
        log_std(cd, "Version:       \t%d\n", cd->hdr.version);
        log_std(cd, "Cipher name:   \t%s\n", cd->hdr.cipherName);
        log_std(cd, "Cipher mode:   \t%s\n", cd->hdr.cipherMode);
@@ -1784,6 +1856,7 @@ const char *crypt_get_device_name(struct crypt_device *cd)
        return cd->device;
 }
 
+
 int crypt_get_volume_key_size(struct crypt_device *cd)
 {
        if (isPLAIN(cd->type) && cd->volume_key)
index 70a334e..9e6ca2a 100644 (file)
@@ -52,7 +52,8 @@ opens the LUKS partition <device> and sets up a mapping <name> after
 successful verification of the supplied key material
 (either via key file by \-\-key-file, or via prompting).
 
-\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly, \-\-allow-discards].
+\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly, \-\-allow-discards,
+\-\-header].
 .PP
 \fIluksClose\fR <name>
 .IP
@@ -67,13 +68,15 @@ After that operation you have to use \fIluksResume\fR to reinstate
 encryption key (and resume device) or \fIluksClose\fR to remove mapped device.
 
 \fBWARNING:\fR never try to suspend device where is the cryptsetup binary itself.
+
+\fB<options>\fR can be [\-\-header].
 .PP
 \fIluksResume\fR <name>
 .IP
 Resumes suspended device and reinstates encryption key. You will need provide passphrase
 identical to \fIluksOpen\fR command (using prompting or key file).
 
-\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size]
+\fB<options>\fR can be [\-\-key-file, \-\-keyfile-size, \-\-header]
 .PP
 \fIluksAddKey\fR <device> [<new key file>]
 .IP
@@ -374,6 +377,20 @@ if the discarded blocks can be located easily on the device later.
 Kernel version 3.1 or more recent is required.
 For older versions is the option ignored.
 .TP
+.B "\-\-header\fR"
+Set detached (separated) metadata device or file with LUKS header.
+
+This options allows separation of ciphertext device and on-disk metadata header.
+
+This option is only relevant for LUKS devices and can be used in \fIluksOpen\fR,
+\fIluksSuspend\fR, \fIluksResume\fR and \fIresize\fR commands.
+
+For other commands with separated metadata device you have to always specify
+path to metadata device (not to the ciphertext device).
+
+\fBWARNING:\fR There is no possible check that specified ciphertext device
+is correct if on-disk header is detached. Use with care.
+.TP
 .B "\-\-version"
 Show the version.
 .SH RETURN CODES
index b7e27ca..82cbca1 100644 (file)
@@ -43,6 +43,7 @@ static const char *opt_key_file = NULL;
 static const char *opt_master_key_file = NULL;
 static const char *opt_header_backup_file = NULL;
 static const char *opt_uuid = NULL;
+static const char *opt_header_device = NULL;
 static int opt_key_size = 0;
 static long opt_keyfile_size = 0;
 static long opt_new_keyfile_size = 0;
@@ -356,7 +357,7 @@ static int action_resize(int arg __attribute__((unused)))
        struct crypt_device *cd = NULL;
        int r;
 
-       r = crypt_init_by_name(&cd, action_argv[0]);
+       r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
        if (r == 0)
                r = crypt_resize(cd, action_argv[0], opt_size);
 
@@ -520,15 +521,28 @@ out:
 static int action_luksOpen(int arg __attribute__((unused)))
 {
        struct crypt_device *cd = NULL;
+       const char *data_device, *header_device;
        uint32_t flags = 0;
        int r;
 
-       if ((r = crypt_init(&cd, action_argv[0])))
+       if (opt_header_device) {
+               header_device = opt_header_device;
+               data_device = action_argv[0];
+       } else {
+               header_device = action_argv[0];
+               data_device = NULL;
+       }
+
+       if ((r = crypt_init(&cd, header_device)))
                goto out;
 
        if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
                goto out;
 
+       if (data_device &&
+           (r = crypt_set_data_device(cd, data_device)))
+               goto out;
+
        crypt_set_timeout(cd, opt_timeout);
        crypt_set_password_retry(cd, opt_tries);
 
@@ -942,7 +956,7 @@ static int action_luksSuspend(int arg __attribute__((unused)))
        struct crypt_device *cd = NULL;
        int r;
 
-       r = crypt_init_by_name(&cd, action_argv[0]);
+       r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
        if (!r)
                r = crypt_suspend(cd, action_argv[0]);
 
@@ -955,7 +969,7 @@ static int action_luksResume(int arg __attribute__((unused)))
        struct crypt_device *cd = NULL;
        int r;
 
-       if ((r = crypt_init_by_name(&cd, action_argv[0])))
+       if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device)))
                goto out;
 
        crypt_set_timeout(cd, opt_timeout);
@@ -1156,6 +1170,7 @@ int main(int argc, const char **argv)
                { "shared",            '\0', POPT_ARG_NONE, &opt_shared,                0, N_("Share device with another non-overlapping crypt segment."), NULL },
                { "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 },
                POPT_TABLEEND
        };
        poptContext popt_context;