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