]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
cryptsetup: call static variables parsed from command line arg_XYZ like in all other...
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/mman.h>
25 #include <mntent.h>
26
27 #include <libcryptsetup.h>
28
29 #include "fileio.h"
30 #include "log.h"
31 #include "util.h"
32 #include "path-util.h"
33 #include "strv.h"
34 #include "ask-password-api.h"
35 #include "def.h"
36 #include "libudev.h"
37 #include "udev-util.h"
38
39 static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
40 static char *arg_cipher = NULL;
41 static unsigned arg_key_size = 0;
42 static int arg_key_slot = CRYPT_ANY_SLOT;
43 static unsigned arg_keyfile_size = 0;
44 static unsigned arg_keyfile_offset = 0;
45 static char *arg_hash = NULL;
46 static unsigned arg_tries = 3;
47 static bool arg_readonly = false;
48 static bool arg_verify = false;
49 static bool arg_discards = false;
50 static bool arg_tcrypt_hidden = false;
51 static bool arg_tcrypt_system = false;
52 static char **arg_tcrypt_keyfiles = NULL;
53 static usec_t arg_timeout = 0;
54
55 /* Options Debian's crypttab knows we don't:
56
57 offset=
58 skip=
59 precheck=
60 check=
61 checkargs=
62 noearly=
63 loud=
64 keyscript=
65 */
66
67 static int parse_one_option(const char *option) {
68 assert(option);
69
70 /* Handled outside of this tool */
71 if (streq(option, "noauto") || streq(option, "nofail"))
72 return 0;
73
74 if (startswith(option, "cipher=")) {
75 char *t;
76
77 t = strdup(option+7);
78 if (!t)
79 return log_oom();
80
81 free(arg_cipher);
82 arg_cipher = t;
83
84 } else if (startswith(option, "size=")) {
85
86 if (safe_atou(option+5, &arg_key_size) < 0) {
87 log_error("size= parse failure, ignoring.");
88 return 0;
89 }
90
91 } else if (startswith(option, "key-slot=")) {
92
93 arg_type = CRYPT_LUKS1;
94 if (safe_atoi(option+9, &arg_key_slot) < 0) {
95 log_error("key-slot= parse failure, ignoring.");
96 return 0;
97 }
98
99 } else if (startswith(option, "tcrypt-keyfile=")) {
100
101 arg_type = CRYPT_TCRYPT;
102 if (path_is_absolute(option+15)) {
103 if (strv_extend(&arg_tcrypt_keyfiles, option + 15) < 0)
104 return log_oom();
105 } else
106 log_error("Key file path '%s' is not absolute. Ignoring.", option+15);
107
108 } else if (startswith(option, "keyfile-size=")) {
109
110 if (safe_atou(option+13, &arg_keyfile_size) < 0) {
111 log_error("keyfile-size= parse failure, ignoring.");
112 return 0;
113 }
114
115 } else if (startswith(option, "keyfile-offset=")) {
116
117 if (safe_atou(option+15, &arg_keyfile_offset) < 0) {
118 log_error("keyfile-offset= parse failure, ignoring.");
119 return 0;
120 }
121
122 } else if (startswith(option, "hash=")) {
123 char *t;
124
125 t = strdup(option+5);
126 if (!t)
127 return log_oom();
128
129 free(arg_hash);
130 arg_hash = t;
131
132 } else if (startswith(option, "tries=")) {
133
134 if (safe_atou(option+6, &arg_tries) < 0) {
135 log_error("tries= parse failure, ignoring.");
136 return 0;
137 }
138
139 } else if (STR_IN_SET(option, "readonly", "read-only"))
140 arg_readonly = true;
141 else if (streq(option, "verify"))
142 arg_verify = true;
143 else if (STR_IN_SET(option, "allow-discards", "discard"))
144 arg_discards = true;
145 else if (streq(option, "luks"))
146 arg_type = CRYPT_LUKS1;
147 else if (streq(option, "tcrypt"))
148 arg_type = CRYPT_TCRYPT;
149 else if (streq(option, "tcrypt-hidden")) {
150 arg_type = CRYPT_TCRYPT;
151 arg_tcrypt_hidden = true;
152 } else if (streq(option, "tcrypt-system")) {
153 arg_type = CRYPT_TCRYPT;
154 arg_tcrypt_system = true;
155 } else if (STR_IN_SET(option, "plain", "swap", "tmp"))
156 arg_type = CRYPT_PLAIN;
157 else if (startswith(option, "timeout=")) {
158
159 if (parse_sec(option+8, &arg_timeout) < 0) {
160 log_error("timeout= parse failure, ignoring.");
161 return 0;
162 }
163
164 } else if (!streq(option, "none"))
165 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
166
167 return 0;
168 }
169
170 static int parse_options(const char *options) {
171 char *state, *w;
172 size_t l;
173 int r;
174
175 assert(options);
176
177 FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
178 _cleanup_free_ char *o;
179
180 o = strndup(w, l);
181 if (!o)
182 return -ENOMEM;
183 r = parse_one_option(o);
184 if (r < 0)
185 return r;
186 }
187
188 return 0;
189 }
190
191 static void log_glue(int level, const char *msg, void *usrptr) {
192 log_debug("%s", msg);
193 }
194
195 static char* disk_description(const char *path) {
196
197 static const char name_fields[] =
198 "ID_PART_ENTRY_NAME\0"
199 "DM_NAME\0"
200 "ID_MODEL_FROM_DATABASE\0"
201 "ID_MODEL\0";
202
203 _cleanup_udev_unref_ struct udev *udev = NULL;
204 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
205 struct stat st;
206 const char *i;
207
208 assert(path);
209
210 if (stat(path, &st) < 0)
211 return NULL;
212
213 if (!S_ISBLK(st.st_mode))
214 return NULL;
215
216 udev = udev_new();
217 if (!udev)
218 return NULL;
219
220 device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
221 if (!device)
222 return NULL;
223
224 NULSTR_FOREACH(i, name_fields) {
225 const char *name;
226
227 name = udev_device_get_property_value(device, i);
228 if (!isempty(name))
229 return strdup(name);
230 }
231
232 return NULL;
233 }
234
235 static char *disk_mount_point(const char *label) {
236 _cleanup_free_ char *device = NULL;
237 _cleanup_endmntent_ FILE *f = NULL;
238 struct mntent *m;
239
240 /* Yeah, we don't support native systemd unit files here for now */
241
242 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
243 return NULL;
244
245 f = setmntent("/etc/fstab", "r");
246 if (!f)
247 return NULL;
248
249 while ((m = getmntent(f)))
250 if (path_equal(m->mnt_fsname, device))
251 return strdup(m->mnt_dir);
252
253 return NULL;
254 }
255
256 static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) {
257 int r;
258 char **p;
259 _cleanup_free_ char *text = NULL;
260
261 assert(name);
262 assert(passwords);
263
264 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
265 return log_oom();
266
267 r = ask_password_auto(text, "drive-harddisk", until, accept_cached, passwords);
268 if (r < 0) {
269 log_error("Failed to query password: %s", strerror(-r));
270 return r;
271 }
272
273 if (arg_verify) {
274 _cleanup_strv_free_ char **passwords2 = NULL;
275
276 assert(strv_length(*passwords) == 1);
277
278 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
279 return log_oom();
280
281 r = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
282 if (r < 0) {
283 log_error("Failed to query verification password: %s", strerror(-r));
284 return r;
285 }
286
287 assert(strv_length(passwords2) == 1);
288
289 if (!streq(*passwords[0], passwords2[0])) {
290 log_warning("Passwords did not match, retrying.");
291 return -EAGAIN;
292 }
293 }
294
295 strv_uniq(*passwords);
296
297 STRV_FOREACH(p, *passwords) {
298 char *c;
299
300 if (strlen(*p)+1 >= arg_key_size)
301 continue;
302
303 /* Pad password if necessary */
304 if (!(c = new(char, arg_key_size)))
305 return log_oom();
306
307 strncpy(c, *p, arg_key_size);
308 free(*p);
309 *p = c;
310 }
311
312 return 0;
313 }
314
315 static int attach_tcrypt(struct crypt_device *cd,
316 const char *name,
317 const char *key_file,
318 char **passwords,
319 uint32_t flags) {
320 int r = 0;
321 _cleanup_free_ char *passphrase = NULL;
322 struct crypt_params_tcrypt params = {
323 .flags = CRYPT_TCRYPT_LEGACY_MODES,
324 .keyfiles = (const char **)arg_tcrypt_keyfiles,
325 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
326 };
327
328 assert(cd);
329 assert(name);
330 assert(key_file || passwords);
331
332 if (arg_tcrypt_hidden)
333 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
334
335 if (arg_tcrypt_system)
336 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
337
338 if (key_file) {
339 r = read_one_line_file(key_file, &passphrase);
340 if (r < 0) {
341 log_error("Failed to read password file '%s': %s", key_file, strerror(-r));
342 return -EAGAIN;
343 }
344
345 params.passphrase = passphrase;
346 } else
347 params.passphrase = passwords[0];
348 params.passphrase_size = strlen(params.passphrase);
349
350 r = crypt_load(cd, CRYPT_TCRYPT, &params);
351 if (r < 0) {
352 if (key_file && r == -EPERM) {
353 log_error("Failed to activate using password file '%s'.", key_file);
354 return -EAGAIN;
355 }
356 return r;
357 }
358
359 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);;
360 }
361
362 static int attach_luks_or_plain(struct crypt_device *cd,
363 const char *name,
364 const char *key_file,
365 char **passwords,
366 uint32_t flags) {
367 int r = 0;
368 bool pass_volume_key = false;
369
370 assert(cd);
371 assert(name);
372 assert(key_file || passwords);
373
374 if (!arg_type || streq(arg_type, CRYPT_LUKS1))
375 r = crypt_load(cd, CRYPT_LUKS1, NULL);
376
377 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
378 struct crypt_params_plain params = {};
379 const char *cipher, *cipher_mode;
380 _cleanup_free_ char *truncated_cipher = NULL;
381
382 if (arg_hash) {
383 /* plain isn't a real hash type. it just means "use no hash" */
384 if (!streq(arg_hash, "plain"))
385 params.hash = arg_hash;
386 } else
387 params.hash = "ripemd160";
388
389 if (arg_cipher) {
390 size_t l;
391
392 l = strcspn(arg_cipher, "-");
393 truncated_cipher = strndup(arg_cipher, l);
394 if (!truncated_cipher)
395 return log_oom();
396
397 cipher = truncated_cipher;
398 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
399 } else {
400 cipher = "aes";
401 cipher_mode = "cbc-essiv:sha256";
402 }
403
404 /* for CRYPT_PLAIN limit reads
405 * from keyfile to key length, and
406 * ignore keyfile-size */
407 arg_keyfile_size = arg_key_size / 8;
408
409 /* In contrast to what the name
410 * crypt_setup() might suggest this
411 * doesn't actually format anything,
412 * it just configures encryption
413 * parameters when used for plain
414 * mode. */
415 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
416 NULL, NULL, arg_keyfile_size, &params);
417
418 /* hash == NULL implies the user passed "plain" */
419 pass_volume_key = (params.hash == NULL);
420 }
421
422 if (r < 0) {
423 log_error("Loading of cryptographic parameters failed: %s", strerror(-r));
424 return r;
425 }
426
427 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
428 crypt_get_cipher(cd),
429 crypt_get_cipher_mode(cd),
430 crypt_get_volume_key_size(cd)*8,
431 crypt_get_device_name(cd));
432
433 if (key_file) {
434 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
435 key_file, arg_keyfile_size,
436 arg_keyfile_offset, flags);
437 if (r < 0) {
438 log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r));
439 return -EAGAIN;
440 }
441 } else {
442 char **p;
443
444 STRV_FOREACH(p, passwords) {
445 if (pass_volume_key)
446 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
447 else
448 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
449
450 if (r >= 0)
451 break;
452 }
453 }
454
455 return r;
456 }
457
458 static int help(void) {
459
460 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
461 "%s detach VOLUME\n\n"
462 "Attaches or detaches an encrypted block device.\n",
463 program_invocation_short_name,
464 program_invocation_short_name);
465
466 return 0;
467 }
468
469 int main(int argc, char *argv[]) {
470 int r = EXIT_FAILURE;
471 struct crypt_device *cd = NULL;
472
473 if (argc <= 1) {
474 help();
475 return EXIT_SUCCESS;
476 }
477
478 if (argc < 3) {
479 log_error("This program requires at least two arguments.");
480 return EXIT_FAILURE;
481 }
482
483 log_set_target(LOG_TARGET_AUTO);
484 log_parse_environment();
485 log_open();
486
487 umask(0022);
488
489 if (streq(argv[1], "attach")) {
490 uint32_t flags = 0;
491 int k;
492 unsigned tries;
493 usec_t until;
494 crypt_status_info status;
495 const char *key_file = NULL, *name = NULL;
496 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
497
498 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
499
500 if (argc < 4) {
501 log_error("attach requires at least two arguments.");
502 goto finish;
503 }
504
505 if (argc >= 5 &&
506 argv[4][0] &&
507 !streq(argv[4], "-") &&
508 !streq(argv[4], "none")) {
509
510 if (!path_is_absolute(argv[4]))
511 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
512 else
513 key_file = argv[4];
514 }
515
516 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
517 if (parse_options(argv[5]) < 0)
518 goto finish;
519 }
520
521 /* A delicious drop of snake oil */
522 mlockall(MCL_FUTURE);
523
524 description = disk_description(argv[3]);
525 mount_point = disk_mount_point(argv[2]);
526
527 if (description && streq(argv[2], description)) {
528 /* If the description string is simply the
529 * volume name, then let's not show this
530 * twice */
531 free(description);
532 description = NULL;
533 }
534
535 if (mount_point && description)
536 asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
537 else if (mount_point)
538 asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
539 else if (description)
540 asprintf(&name_buffer, "%s (%s)", description, argv[2]);
541
542 name = name_buffer ? name_buffer : argv[2];
543
544 k = crypt_init(&cd, argv[3]);
545 if (k) {
546 log_error("crypt_init() failed: %s", strerror(-k));
547 goto finish;
548 }
549
550 crypt_set_log_callback(cd, log_glue, NULL);
551
552 status = crypt_status(cd, argv[2]);
553 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
554 log_info("Volume %s already active.", argv[2]);
555 r = EXIT_SUCCESS;
556 goto finish;
557 }
558
559 if (arg_readonly)
560 flags |= CRYPT_ACTIVATE_READONLY;
561
562 if (arg_discards)
563 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
564
565 if (arg_timeout > 0)
566 until = now(CLOCK_MONOTONIC) + arg_timeout;
567 else
568 until = 0;
569
570 arg_key_size = (arg_key_size > 0 ? arg_key_size : 256);
571
572 if (key_file) {
573 struct stat st;
574
575 /* Ideally we'd do this on the open fd, but since this is just a
576 * warning it's OK to do this in two steps. */
577 if (stat(key_file, &st) >= 0 && (st.st_mode & 0005))
578 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
579 }
580
581 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
582 _cleanup_strv_free_ char **passwords = NULL;
583
584 if (!key_file) {
585 k = get_password(name, until, tries == 0 && !arg_verify, &passwords);
586 if (k == -EAGAIN)
587 continue;
588 else if (k < 0)
589 goto finish;
590 }
591
592 if (streq_ptr(arg_type, CRYPT_TCRYPT))
593 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
594 else
595 k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags);
596 if (k >= 0)
597 break;
598 else if (k == -EAGAIN) {
599 key_file = NULL;
600 continue;
601 } else if (k != -EPERM) {
602 log_error("Failed to activate: %s", strerror(-k));
603 goto finish;
604 }
605
606 log_warning("Invalid passphrase.");
607 }
608
609 if (arg_tries != 0 && tries >= arg_tries) {
610 log_error("Too many attempts; giving up.");
611 r = EXIT_FAILURE;
612 goto finish;
613 }
614
615 } else if (streq(argv[1], "detach")) {
616 int k;
617
618 k = crypt_init_by_name(&cd, argv[2]);
619 if (k) {
620 log_error("crypt_init() failed: %s", strerror(-k));
621 goto finish;
622 }
623
624 crypt_set_log_callback(cd, log_glue, NULL);
625
626 k = crypt_deactivate(cd, argv[2]);
627 if (k < 0) {
628 log_error("Failed to deactivate: %s", strerror(-k));
629 goto finish;
630 }
631
632 } else {
633 log_error("Unknown verb %s.", argv[1]);
634 goto finish;
635 }
636
637 r = EXIT_SUCCESS;
638
639 finish:
640
641 if (cd)
642 crypt_free(cd);
643
644 free(arg_cipher);
645 free(arg_hash);
646 strv_free(arg_tcrypt_keyfiles);
647
648 return r;
649 }