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