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