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