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