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