]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <libcryptsetup.h>
23 #include <mntent.h>
24 #include <string.h>
25 #include <sys/mman.h>
26
27 #include "sd-device.h"
28
29 #include "alloc-util.h"
30 #include "ask-password-api.h"
31 #include "device-util.h"
32 #include "escape.h"
33 #include "fileio.h"
34 #include "log.h"
35 #include "mount-util.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "util.h"
41
42 /* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
43 #ifndef CRYPT_LUKS
44 #define CRYPT_LUKS NULL
45 #endif
46
47 /* internal helper */
48 #define ANY_LUKS "LUKS"
49
50 static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
51 static char *arg_cipher = NULL;
52 static unsigned arg_key_size = 0;
53 static int arg_key_slot = CRYPT_ANY_SLOT;
54 static unsigned arg_keyfile_size = 0;
55 static unsigned arg_keyfile_offset = 0;
56 static char *arg_hash = NULL;
57 static char *arg_header = NULL;
58 static unsigned arg_tries = 3;
59 static bool arg_readonly = false;
60 static bool arg_verify = false;
61 static bool arg_discards = false;
62 static bool arg_tcrypt_hidden = false;
63 static bool arg_tcrypt_system = false;
64 #ifdef CRYPT_TCRYPT_VERA_MODES
65 static bool arg_tcrypt_veracrypt = false;
66 #endif
67 static char **arg_tcrypt_keyfiles = NULL;
68 static uint64_t arg_offset = 0;
69 static uint64_t arg_skip = 0;
70 static usec_t arg_timeout = USEC_INFINITY;
71
72 /* Options Debian's crypttab knows we don't:
73
74 precheck=
75 check=
76 checkargs=
77 noearly=
78 loud=
79 keyscript=
80 */
81
82 static int parse_one_option(const char *option) {
83 const char *val;
84 int r;
85
86 assert(option);
87
88 /* Handled outside of this tool */
89 if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev"))
90 return 0;
91
92 if ((val = startswith(option, "cipher="))) {
93 r = free_and_strdup(&arg_cipher, val);
94 if (r < 0)
95 return log_oom();
96
97 } else if ((val = startswith(option, "size="))) {
98
99 r = safe_atou(val, &arg_key_size);
100 if (r < 0) {
101 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
102 return 0;
103 }
104
105 if (arg_key_size % 8) {
106 log_error("size= not a multiple of 8, ignoring.");
107 return 0;
108 }
109
110 arg_key_size /= 8;
111
112 } else if ((val = startswith(option, "key-slot="))) {
113
114 arg_type = ANY_LUKS;
115 r = safe_atoi(val, &arg_key_slot);
116 if (r < 0) {
117 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
118 return 0;
119 }
120
121 } else if ((val = startswith(option, "tcrypt-keyfile="))) {
122
123 arg_type = CRYPT_TCRYPT;
124 if (path_is_absolute(val)) {
125 if (strv_extend(&arg_tcrypt_keyfiles, val) < 0)
126 return log_oom();
127 } else
128 log_error("Key file path \"%s\" is not absolute. Ignoring.", val);
129
130 } else if ((val = startswith(option, "keyfile-size="))) {
131
132 r = safe_atou(val, &arg_keyfile_size);
133 if (r < 0) {
134 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
135 return 0;
136 }
137
138 } else if ((val = startswith(option, "keyfile-offset="))) {
139
140 r = safe_atou(val, &arg_keyfile_offset);
141 if (r < 0) {
142 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
143 return 0;
144 }
145
146 } else if ((val = startswith(option, "hash="))) {
147 r = free_and_strdup(&arg_hash, val);
148 if (r < 0)
149 return log_oom();
150
151 } else if ((val = startswith(option, "header="))) {
152 arg_type = ANY_LUKS;
153
154 if (!path_is_absolute(val)) {
155 log_error("Header path \"%s\" is not absolute, refusing.", val);
156 return -EINVAL;
157 }
158
159 if (arg_header) {
160 log_error("Duplicate header= option, refusing.");
161 return -EINVAL;
162 }
163
164 arg_header = strdup(val);
165 if (!arg_header)
166 return log_oom();
167
168 } else if ((val = startswith(option, "tries="))) {
169
170 r = safe_atou(val, &arg_tries);
171 if (r < 0) {
172 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
173 return 0;
174 }
175
176 } else if (STR_IN_SET(option, "readonly", "read-only"))
177 arg_readonly = true;
178 else if (streq(option, "verify"))
179 arg_verify = true;
180 else if (STR_IN_SET(option, "allow-discards", "discard"))
181 arg_discards = true;
182 else if (streq(option, "luks"))
183 arg_type = ANY_LUKS;
184 else if (streq(option, "tcrypt"))
185 arg_type = CRYPT_TCRYPT;
186 else if (streq(option, "tcrypt-hidden")) {
187 arg_type = CRYPT_TCRYPT;
188 arg_tcrypt_hidden = true;
189 } else if (streq(option, "tcrypt-system")) {
190 arg_type = CRYPT_TCRYPT;
191 arg_tcrypt_system = true;
192 } else if (streq(option, "tcrypt-veracrypt")) {
193 #ifdef CRYPT_TCRYPT_VERA_MODES
194 arg_type = CRYPT_TCRYPT;
195 arg_tcrypt_veracrypt = true;
196 #else
197 log_error("This version of cryptsetup does not support tcrypt-veracrypt; refusing.");
198 return -EINVAL;
199 #endif
200 } else if (STR_IN_SET(option, "plain", "swap", "tmp"))
201 arg_type = CRYPT_PLAIN;
202 else if ((val = startswith(option, "timeout="))) {
203
204 r = parse_sec_fix_0(val, &arg_timeout);
205 if (r < 0) {
206 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
207 return 0;
208 }
209
210 } else if ((val = startswith(option, "offset="))) {
211
212 r = safe_atou64(val, &arg_offset);
213 if (r < 0)
214 return log_error_errno(r, "Failed to parse %s: %m", option);
215
216 } else if ((val = startswith(option, "skip="))) {
217
218 r = safe_atou64(val, &arg_skip);
219 if (r < 0)
220 return log_error_errno(r, "Failed to parse %s: %m", option);
221
222 } else if (!streq(option, "none"))
223 log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
224
225 return 0;
226 }
227
228 static int parse_options(const char *options) {
229 const char *word, *state;
230 size_t l;
231 int r;
232
233 assert(options);
234
235 FOREACH_WORD_SEPARATOR(word, l, options, ",", state) {
236 _cleanup_free_ char *o;
237
238 o = strndup(word, l);
239 if (!o)
240 return -ENOMEM;
241 r = parse_one_option(o);
242 if (r < 0)
243 return r;
244 }
245
246 /* sanity-check options */
247 if (arg_type != NULL && !streq(arg_type, CRYPT_PLAIN)) {
248 if (arg_offset)
249 log_warning("offset= ignored with type %s", arg_type);
250 if (arg_skip)
251 log_warning("skip= ignored with type %s", arg_type);
252 }
253
254 return 0;
255 }
256
257 static void log_glue(int level, const char *msg, void *usrptr) {
258 log_debug("%s", msg);
259 }
260
261 static int disk_major_minor(const char *path, char **ret) {
262 struct stat st;
263
264 assert(path);
265
266 if (stat(path, &st) < 0)
267 return -errno;
268
269 if (!S_ISBLK(st.st_mode))
270 return -EINVAL;
271
272 if (asprintf(ret, "/dev/block/%d:%d", major(st.st_rdev), minor(st.st_rdev)) < 0)
273 return -errno;
274
275 return 0;
276 }
277
278 static char* disk_description(const char *path) {
279
280 static const char name_fields[] =
281 "ID_PART_ENTRY_NAME\0"
282 "DM_NAME\0"
283 "ID_MODEL_FROM_DATABASE\0"
284 "ID_MODEL\0";
285
286 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
287 struct stat st;
288 const char *i;
289 int r;
290
291 assert(path);
292
293 if (stat(path, &st) < 0)
294 return NULL;
295
296 if (!S_ISBLK(st.st_mode))
297 return NULL;
298
299 r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
300 if (r < 0)
301 return NULL;
302
303 NULSTR_FOREACH(i, name_fields) {
304 const char *name;
305
306 r = sd_device_get_property_value(device, i, &name);
307 if (r >= 0 && !isempty(name))
308 return strdup(name);
309 }
310
311 return NULL;
312 }
313
314 static char *disk_mount_point(const char *label) {
315 _cleanup_free_ char *device = NULL;
316 _cleanup_endmntent_ FILE *f = NULL;
317 struct mntent *m;
318
319 /* Yeah, we don't support native systemd unit files here for now */
320
321 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
322 return NULL;
323
324 f = setmntent("/etc/fstab", "re");
325 if (!f)
326 return NULL;
327
328 while ((m = getmntent(f)))
329 if (path_equal(m->mnt_fsname, device))
330 return strdup(m->mnt_dir);
331
332 return NULL;
333 }
334
335 static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) {
336 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
337 _cleanup_strv_free_erase_ char **passwords = NULL;
338 const char *name = NULL;
339 char **p, *id;
340 int r = 0;
341
342 assert(vol);
343 assert(src);
344 assert(ret);
345
346 description = disk_description(src);
347 mount_point = disk_mount_point(vol);
348
349 if (description && streq(vol, description))
350 /* If the description string is simply the
351 * volume name, then let's not show this
352 * twice */
353 description = mfree(description);
354
355 if (mount_point && description)
356 r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point);
357 else if (mount_point)
358 r = asprintf(&name_buffer, "%s on %s", vol, mount_point);
359 else if (description)
360 r = asprintf(&name_buffer, "%s (%s)", description, vol);
361
362 if (r < 0)
363 return log_oom();
364
365 name = name_buffer ? name_buffer : vol;
366
367 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
368 return log_oom();
369
370 if (src)
371 (void) disk_major_minor(src, &maj_min);
372
373 if (maj_min) {
374 escaped_name = maj_min;
375 maj_min = NULL;
376 } else
377 escaped_name = cescape(name);
378
379 if (!escaped_name)
380 return log_oom();
381
382 id = strjoina("cryptsetup:", escaped_name);
383
384 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
385 ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
386 &passwords);
387 if (r < 0)
388 return log_error_errno(r, "Failed to query password: %m");
389
390 if (arg_verify) {
391 _cleanup_strv_free_erase_ char **passwords2 = NULL;
392
393 assert(strv_length(passwords) == 1);
394
395 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
396 return log_oom();
397
398 id = strjoina("cryptsetup-verification:", escaped_name);
399
400 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
401 if (r < 0)
402 return log_error_errno(r, "Failed to query verification password: %m");
403
404 assert(strv_length(passwords2) == 1);
405
406 if (!streq(passwords[0], passwords2[0])) {
407 log_warning("Passwords did not match, retrying.");
408 return -EAGAIN;
409 }
410 }
411
412 strv_uniq(passwords);
413
414 STRV_FOREACH(p, passwords) {
415 char *c;
416
417 if (strlen(*p)+1 >= arg_key_size)
418 continue;
419
420 /* Pad password if necessary */
421 c = new(char, arg_key_size);
422 if (!c)
423 return log_oom();
424
425 strncpy(c, *p, arg_key_size);
426 free(*p);
427 *p = c;
428 }
429
430 *ret = passwords;
431 passwords = NULL;
432
433 return 0;
434 }
435
436 static int attach_tcrypt(
437 struct crypt_device *cd,
438 const char *name,
439 const char *key_file,
440 char **passwords,
441 uint32_t flags) {
442
443 int r = 0;
444 _cleanup_free_ char *passphrase = NULL;
445 struct crypt_params_tcrypt params = {
446 .flags = CRYPT_TCRYPT_LEGACY_MODES,
447 .keyfiles = (const char **)arg_tcrypt_keyfiles,
448 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
449 };
450
451 assert(cd);
452 assert(name);
453 assert(key_file || (passwords && passwords[0]));
454
455 if (arg_tcrypt_hidden)
456 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
457
458 if (arg_tcrypt_system)
459 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
460
461 #ifdef CRYPT_TCRYPT_VERA_MODES
462 if (arg_tcrypt_veracrypt)
463 params.flags |= CRYPT_TCRYPT_VERA_MODES;
464 #endif
465
466 if (key_file) {
467 r = read_one_line_file(key_file, &passphrase);
468 if (r < 0) {
469 log_error_errno(r, "Failed to read password file '%s': %m", key_file);
470 return -EAGAIN;
471 }
472
473 params.passphrase = passphrase;
474 } else
475 params.passphrase = passwords[0];
476 params.passphrase_size = strlen(params.passphrase);
477
478 r = crypt_load(cd, CRYPT_TCRYPT, &params);
479 if (r < 0) {
480 if (key_file && r == -EPERM) {
481 log_error("Failed to activate using password file '%s'.", key_file);
482 return -EAGAIN;
483 }
484 return r;
485 }
486
487 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
488 }
489
490 static int attach_luks_or_plain(struct crypt_device *cd,
491 const char *name,
492 const char *key_file,
493 const char *data_device,
494 char **passwords,
495 uint32_t flags) {
496 int r = 0;
497 bool pass_volume_key = false;
498
499 assert(cd);
500 assert(name);
501 assert(key_file || passwords);
502
503 if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) {
504 r = crypt_load(cd, CRYPT_LUKS, NULL);
505 if (r < 0) {
506 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
507 return r;
508 }
509
510 if (data_device)
511 r = crypt_set_data_device(cd, data_device);
512 }
513
514 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
515 struct crypt_params_plain params = {
516 .offset = arg_offset,
517 .skip = arg_skip,
518 };
519 const char *cipher, *cipher_mode;
520 _cleanup_free_ char *truncated_cipher = NULL;
521
522 if (arg_hash) {
523 /* plain isn't a real hash type. it just means "use no hash" */
524 if (!streq(arg_hash, "plain"))
525 params.hash = arg_hash;
526 } else if (!key_file)
527 /* for CRYPT_PLAIN, the behaviour of cryptsetup
528 * package is to not hash when a key file is provided */
529 params.hash = "ripemd160";
530
531 if (arg_cipher) {
532 size_t l;
533
534 l = strcspn(arg_cipher, "-");
535 truncated_cipher = strndup(arg_cipher, l);
536 if (!truncated_cipher)
537 return log_oom();
538
539 cipher = truncated_cipher;
540 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
541 } else {
542 cipher = "aes";
543 cipher_mode = "cbc-essiv:sha256";
544 }
545
546 /* for CRYPT_PLAIN limit reads
547 * from keyfile to key length, and
548 * ignore keyfile-size */
549 arg_keyfile_size = arg_key_size;
550
551 /* In contrast to what the name
552 * crypt_setup() might suggest this
553 * doesn't actually format anything,
554 * it just configures encryption
555 * parameters when used for plain
556 * mode. */
557 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, &params);
558
559 /* hash == NULL implies the user passed "plain" */
560 pass_volume_key = (params.hash == NULL);
561 }
562
563 if (r < 0)
564 return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
565
566 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
567 crypt_get_cipher(cd),
568 crypt_get_cipher_mode(cd),
569 crypt_get_volume_key_size(cd)*8,
570 crypt_get_device_name(cd));
571
572 if (key_file) {
573 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
574 if (r < 0) {
575 log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
576 return -EAGAIN;
577 }
578 } else {
579 char **p;
580
581 STRV_FOREACH(p, passwords) {
582 if (pass_volume_key)
583 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
584 else
585 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
586
587 if (r >= 0)
588 break;
589 }
590 }
591
592 return r;
593 }
594
595 static int help(void) {
596
597 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
598 "%s detach VOLUME\n\n"
599 "Attaches or detaches an encrypted block device.\n",
600 program_invocation_short_name,
601 program_invocation_short_name);
602
603 return 0;
604 }
605
606 int main(int argc, char *argv[]) {
607 struct crypt_device *cd = NULL;
608 int r = -EINVAL;
609
610 if (argc <= 1) {
611 r = help();
612 goto finish;
613 }
614
615 if (argc < 3) {
616 log_error("This program requires at least two arguments.");
617 goto finish;
618 }
619
620 log_set_target(LOG_TARGET_AUTO);
621 log_parse_environment();
622 log_open();
623
624 umask(0022);
625
626 if (streq(argv[1], "attach")) {
627 uint32_t flags = 0;
628 unsigned tries;
629 usec_t until;
630 crypt_status_info status;
631 const char *key_file = NULL;
632
633 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
634
635 if (argc < 4) {
636 log_error("attach requires at least two arguments.");
637 goto finish;
638 }
639
640 if (argc >= 5 &&
641 argv[4][0] &&
642 !streq(argv[4], "-") &&
643 !streq(argv[4], "none")) {
644
645 if (!path_is_absolute(argv[4]))
646 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
647 else
648 key_file = argv[4];
649 }
650
651 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
652 if (parse_options(argv[5]) < 0)
653 goto finish;
654 }
655
656 /* A delicious drop of snake oil */
657 mlockall(MCL_FUTURE);
658
659 if (arg_header) {
660 log_debug("LUKS header: %s", arg_header);
661 r = crypt_init(&cd, arg_header);
662 } else
663 r = crypt_init(&cd, argv[3]);
664 if (r < 0) {
665 log_error_errno(r, "crypt_init() failed: %m");
666 goto finish;
667 }
668
669 crypt_set_log_callback(cd, log_glue, NULL);
670
671 status = crypt_status(cd, argv[2]);
672 if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
673 log_info("Volume %s already active.", argv[2]);
674 r = 0;
675 goto finish;
676 }
677
678 if (arg_readonly)
679 flags |= CRYPT_ACTIVATE_READONLY;
680
681 if (arg_discards)
682 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
683
684 if (arg_timeout == USEC_INFINITY)
685 until = 0;
686 else
687 until = now(CLOCK_MONOTONIC) + arg_timeout;
688
689 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
690
691 if (key_file) {
692 struct stat st;
693
694 /* Ideally we'd do this on the open fd, but since this is just a
695 * warning it's OK to do this in two steps. */
696 if (stat(key_file, &st) >= 0 && S_ISREG(st.st_mode) && (st.st_mode & 0005))
697 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
698 }
699
700 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
701 _cleanup_strv_free_erase_ char **passwords = NULL;
702
703 if (!key_file) {
704 r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
705 if (r == -EAGAIN)
706 continue;
707 if (r < 0)
708 goto finish;
709 }
710
711 if (streq_ptr(arg_type, CRYPT_TCRYPT))
712 r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
713 else
714 r = attach_luks_or_plain(cd,
715 argv[2],
716 key_file,
717 arg_header ? argv[3] : NULL,
718 passwords,
719 flags);
720 if (r >= 0)
721 break;
722 if (r == -EAGAIN) {
723 key_file = NULL;
724 continue;
725 }
726 if (r != -EPERM) {
727 log_error_errno(r, "Failed to activate: %m");
728 goto finish;
729 }
730
731 log_warning("Invalid passphrase.");
732 }
733
734 if (arg_tries != 0 && tries >= arg_tries) {
735 log_error("Too many attempts; giving up.");
736 r = -EPERM;
737 goto finish;
738 }
739
740 } else if (streq(argv[1], "detach")) {
741
742 r = crypt_init_by_name(&cd, argv[2]);
743 if (r == -ENODEV) {
744 log_info("Volume %s already inactive.", argv[2]);
745 r = 0;
746 goto finish;
747 }
748 if (r < 0) {
749 log_error_errno(r, "crypt_init_by_name() failed: %m");
750 goto finish;
751 }
752
753 crypt_set_log_callback(cd, log_glue, NULL);
754
755 r = crypt_deactivate(cd, argv[2]);
756 if (r < 0) {
757 log_error_errno(r, "Failed to deactivate: %m");
758 goto finish;
759 }
760
761 } else {
762 log_error("Unknown verb %s.", argv[1]);
763 goto finish;
764 }
765
766 r = 0;
767
768 finish:
769 if (cd)
770 crypt_free(cd);
771
772 free(arg_cipher);
773 free(arg_hash);
774 free(arg_header);
775 strv_free(arg_tcrypt_keyfiles);
776
777 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
778 }