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