From f7f9e291f4a2d3465b1472b154f2d36af6c1459a Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Wed, 20 Jul 2011 17:39:26 +0000 Subject: [PATCH] * 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. git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@575 36d66b0a-2a48-0410-832c-cd162a569da5 --- ChangeLog | 2 + lib/libcryptsetup.h | 18 +++- lib/libcryptsetup.sym | 2 + lib/setup.c | 235 +++++++++++++++++++++++++++--------------- man/cryptsetup.8 | 21 +++- src/cryptsetup.c | 23 ++++- 6 files changed, 213 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1d8241a5..3b579431 100644 --- 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 * Remove old API functions (all functions using crypt_options). diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 92588267..a533b66c 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -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); /** @@ -112,6 +121,13 @@ void crypt_set_password_retry(struct crypt_device *cd, int tries); void crypt_set_iterarion_time(struct crypt_device *cd, uint64_t iteration_time_ms); 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 diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 10718b5b..53ccaad1 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -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; diff --git a/lib/setup.c b/lib/setup.c index 08eaf6f6..77e771fd 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -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); + if (header_device) { + r = crypt_init(cd, header_device); + } else { + r = crypt_init(cd, dmd.device); - /* Underlying device is not readable but crypt mapping exists */ - if (r == -ENOTBLK) { - free((char*)dmd.device); - dmd.device = NULL; - r = crypt_init(cd, NULL); + /* 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; + 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 (!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, 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 (!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; - } + 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) diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 index 70a334ef..9e6ca2ac 100644 --- a/man/cryptsetup.8 +++ b/man/cryptsetup.8 @@ -52,7 +52,8 @@ opens the LUKS partition and sets up a mapping after successful verification of the supplied key material (either via key file by \-\-key-file, or via prompting). -\fB\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly, \-\-allow-discards]. +\fB\fR can be [\-\-key-file, \-\-keyfile-size, \-\-readonly, \-\-allow-discards, +\-\-header]. .PP \fIluksClose\fR .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\fR can be [\-\-header]. .PP \fIluksResume\fR .IP Resumes suspended device and reinstates encryption key. You will need provide passphrase identical to \fIluksOpen\fR command (using prompting or key file). -\fB\fR can be [\-\-key-file, \-\-keyfile-size] +\fB\fR can be [\-\-key-file, \-\-keyfile-size, \-\-header] .PP \fIluksAddKey\fR [] .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 diff --git a/src/cryptsetup.c b/src/cryptsetup.c index b7e27ca0..82cbca11 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -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;