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