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