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