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