chiark / gitweb /
Introduce _cleanup_endmntent_
[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         _cleanup_free_ char *device = NULL;
240         _cleanup_endmntent_ FILE *f = NULL;
241         struct mntent *m;
242
243         /* Yeah, we don't support native systemd unit files here for now */
244
245         if (asprintf(&device, "/dev/mapper/%s", label) < 0)
246                 return NULL;
247
248         f = setmntent("/etc/fstab", "r");
249         if (!f)
250                 return NULL;
251
252         while ((m = getmntent(f)))
253                 if (path_equal(m->mnt_fsname, device))
254                         return strdup(m->mnt_dir);
255
256         return NULL;
257 }
258
259 static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) {
260         int r;
261         char **p;
262         _cleanup_free_ char *text = NULL;
263
264         assert(name);
265         assert(passwords);
266
267         if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
268                 return log_oom();
269
270         r = ask_password_auto(text, "drive-harddisk", until, accept_cached, passwords);
271         if (r < 0) {
272                 log_error("Failed to query password: %s", strerror(-r));
273                 return r;
274         }
275
276         if (opt_verify) {
277                 _cleanup_strv_free_ char **passwords2 = NULL;
278
279                 assert(strv_length(*passwords) == 1);
280
281                 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
282                         return log_oom();
283
284                 r = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
285                 if (r < 0) {
286                         log_error("Failed to query verification password: %s", strerror(-r));
287                         return r;
288                 }
289
290                 assert(strv_length(passwords2) == 1);
291
292                 if (!streq(*passwords[0], passwords2[0])) {
293                         log_warning("Passwords did not match, retrying.");
294                         return -EAGAIN;
295                 }
296         }
297
298         strv_uniq(*passwords);
299
300         STRV_FOREACH(p, *passwords) {
301                 char *c;
302
303                 if (strlen(*p)+1 >= opt_key_size)
304                         continue;
305
306                 /* Pad password if necessary */
307                 if (!(c = new(char, opt_key_size)))
308                         return log_oom();
309
310                 strncpy(c, *p, opt_key_size);
311                 free(*p);
312                 *p = c;
313         }
314
315         return 0;
316 }
317
318 static int attach_tcrypt(struct crypt_device *cd,
319                                 const char *name,
320                                 const char *key_file,
321                                 char **passwords,
322                                 uint32_t flags) {
323         int r = 0;
324         _cleanup_free_ char *passphrase = NULL;
325         struct crypt_params_tcrypt params = {
326                 .flags = CRYPT_TCRYPT_LEGACY_MODES,
327                 .keyfiles = (const char **)opt_tcrypt_keyfiles,
328                 .keyfiles_count = strv_length(opt_tcrypt_keyfiles)
329         };
330
331         assert(cd);
332         assert(name);
333         assert(key_file || passwords);
334
335         if (opt_tcrypt_hidden)
336                 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
337
338         if (opt_tcrypt_system)
339                 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
340
341         if (key_file) {
342                 r = read_one_line_file(key_file, &passphrase);
343                 if (r < 0) {
344                         log_error("Failed to read password file '%s': %s", key_file, strerror(-r));
345                         return -EAGAIN;
346                 }
347
348                 params.passphrase = passphrase;
349         } else
350                 params.passphrase = passwords[0];
351         params.passphrase_size = strlen(params.passphrase);
352
353         r = crypt_load(cd, CRYPT_TCRYPT, &params);
354         if (r < 0) {
355                 if (key_file && r == -EPERM) {
356                         log_error("Failed to activate using password file '%s'.", key_file);
357                         return -EAGAIN;
358                 }
359                 return r;
360         }
361
362         return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);;
363 }
364
365 static int attach_luks_or_plain(struct crypt_device *cd,
366                                 const char *name,
367                                 const char *key_file,
368                                 char **passwords,
369                                 uint32_t flags) {
370         int r = 0;
371         bool pass_volume_key = false;
372
373         assert(cd);
374         assert(name);
375         assert(key_file || passwords);
376
377         if (!opt_type || streq(opt_type, CRYPT_LUKS1))
378                 r = crypt_load(cd, CRYPT_LUKS1, NULL);
379
380         if ((!opt_type && r < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
381                 struct crypt_params_plain params = {};
382                 const char *cipher, *cipher_mode;
383                 _cleanup_free_ char *truncated_cipher = NULL;
384
385                 if (opt_hash) {
386                         /* plain isn't a real hash type. it just means "use no hash" */
387                         if (!streq(opt_hash, "plain"))
388                                 params.hash = opt_hash;
389                 } else
390                         params.hash = "ripemd160";
391
392                 if (opt_cipher) {
393                         size_t l;
394
395                         l = strcspn(opt_cipher, "-");
396                         truncated_cipher = strndup(opt_cipher, l);
397                         if (!truncated_cipher)
398                                 return log_oom();
399
400                         cipher = truncated_cipher;
401                         cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
402                 } else {
403                         cipher = "aes";
404                         cipher_mode = "cbc-essiv:sha256";
405                 }
406
407                 /* for CRYPT_PLAIN limit reads
408                  * from keyfile to key length, and
409                  * ignore keyfile-size */
410                 opt_keyfile_size = opt_key_size / 8;
411
412                 /* In contrast to what the name
413                  * crypt_setup() might suggest this
414                  * doesn't actually format anything,
415                  * it just configures encryption
416                  * parameters when used for plain
417                  * mode. */
418                 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
419                                  NULL, NULL, opt_keyfile_size, &params);
420
421                 /* hash == NULL implies the user passed "plain" */
422                 pass_volume_key = (params.hash == NULL);
423         }
424
425         if (r < 0) {
426                 log_error("Loading of cryptographic parameters failed: %s", strerror(-r));
427                 return r;
428         }
429
430         log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
431                  crypt_get_cipher(cd),
432                  crypt_get_cipher_mode(cd),
433                  crypt_get_volume_key_size(cd)*8,
434                  crypt_get_device_name(cd));
435
436         if (key_file) {
437                 r = crypt_activate_by_keyfile_offset(cd, name, CRYPT_ANY_SLOT,
438                                                      key_file, opt_keyfile_size,
439                                                      opt_keyfile_offset, flags);
440                 if (r < 0) {
441                         log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r));
442                         return -EAGAIN;
443                 }
444         } else {
445                 char **p;
446
447                 STRV_FOREACH(p, passwords) {
448                         if (pass_volume_key)
449                                 r = crypt_activate_by_volume_key(cd, name, *p, opt_key_size, flags);
450                         else
451                                 r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, *p, strlen(*p), flags);
452
453                         if (r >= 0)
454                                 break;
455                 }
456         }
457
458         return r;
459 }
460
461 static int help(void) {
462
463         printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
464                "%s detach VOLUME\n\n"
465                "Attaches or detaches an encrypted block device.\n",
466                program_invocation_short_name,
467                program_invocation_short_name);
468
469         return 0;
470 }
471
472 int main(int argc, char *argv[]) {
473         int r = EXIT_FAILURE;
474         struct crypt_device *cd = NULL;
475
476         if (argc <= 1) {
477                 help();
478                 return EXIT_SUCCESS;
479         }
480
481         if (argc < 3) {
482                 log_error("This program requires at least two arguments.");
483                 return EXIT_FAILURE;
484         }
485
486         log_set_target(LOG_TARGET_AUTO);
487         log_parse_environment();
488         log_open();
489
490         umask(0022);
491
492         if (streq(argv[1], "attach")) {
493                 uint32_t flags = 0;
494                 int k;
495                 unsigned tries;
496                 usec_t until;
497                 crypt_status_info status;
498                 const char *key_file = NULL, *name = NULL;
499                 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
500
501                 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
502
503                 if (argc < 4) {
504                         log_error("attach requires at least two arguments.");
505                         goto finish;
506                 }
507
508                 if (argc >= 5 &&
509                     argv[4][0] &&
510                     !streq(argv[4], "-") &&
511                     !streq(argv[4], "none")) {
512
513                         if (!path_is_absolute(argv[4]))
514                                 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
515                         else
516                                 key_file = argv[4];
517                 }
518
519                 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
520                         if (parse_options(argv[5]) < 0)
521                                 goto finish;
522                 }
523
524                 /* A delicious drop of snake oil */
525                 mlockall(MCL_FUTURE);
526
527                 description = disk_description(argv[3]);
528                 mount_point = disk_mount_point(argv[2]);
529
530                 if (description && streq(argv[2], description)) {
531                         /* If the description string is simply the
532                          * volume name, then let's not show this
533                          * twice */
534                         free(description);
535                         description = NULL;
536                 }
537
538                 if (mount_point && description)
539                         asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
540                 else if (mount_point)
541                         asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
542                 else if (description)
543                         asprintf(&name_buffer, "%s (%s)", description, argv[2]);
544
545                 name = name_buffer ? name_buffer : argv[2];
546
547                 k = crypt_init(&cd, argv[3]);
548                 if (k) {
549                         log_error("crypt_init() failed: %s", strerror(-k));
550                         goto finish;
551                 }
552
553                 crypt_set_log_callback(cd, log_glue, NULL);
554
555                 status = crypt_status(cd, argv[2]);
556                 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
557                         log_info("Volume %s already active.", argv[2]);
558                         r = EXIT_SUCCESS;
559                         goto finish;
560                 }
561
562                 if (opt_readonly)
563                         flags |= CRYPT_ACTIVATE_READONLY;
564
565                 if (opt_discards)
566                         flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
567
568                 if (opt_timeout > 0)
569                         until = now(CLOCK_MONOTONIC) + opt_timeout;
570                 else
571                         until = 0;
572
573                 opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
574
575                 if (key_file) {
576                         struct stat st;
577
578                         /* Ideally we'd do this on the open fd, but since this is just a
579                          * warning it's OK to do this in two steps. */
580                         if (stat(key_file, &st) >= 0 && (st.st_mode & 0005))
581                                 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
582                 }
583
584                 for (tries = 0; opt_tries == 0 || tries < opt_tries; tries++) {
585                         _cleanup_strv_free_ char **passwords = NULL;
586
587                         if (!key_file) {
588                                 k = get_password(name, until, tries == 0 && !opt_verify, &passwords);
589                                 if (k == -EAGAIN)
590                                         continue;
591                                 else if (k < 0)
592                                         goto finish;
593                         }
594
595                         if (streq_ptr(opt_type, CRYPT_TCRYPT))
596                                 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
597                         else
598                                 k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags);
599                         if (k >= 0)
600                                 break;
601                         else if (k == -EAGAIN) {
602                                 key_file = NULL;
603                                 continue;
604                         } else if (k != -EPERM) {
605                                 log_error("Failed to activate: %s", strerror(-k));
606                                 goto finish;
607                         }
608
609                         log_warning("Invalid passphrase.");
610                 }
611
612                 if (opt_tries != 0 && tries >= opt_tries) {
613                         log_error("Too many attempts; giving up.");
614                         r = EXIT_FAILURE;
615                         goto finish;
616                 }
617
618         } else if (streq(argv[1], "detach")) {
619                 int k;
620
621                 k = crypt_init_by_name(&cd, argv[2]);
622                 if (k) {
623                         log_error("crypt_init() failed: %s", strerror(-k));
624                         goto finish;
625                 }
626
627                 crypt_set_log_callback(cd, log_glue, NULL);
628
629                 k = crypt_deactivate(cd, argv[2]);
630                 if (k < 0) {
631                         log_error("Failed to deactivate: %s", strerror(-k));
632                         goto finish;
633                 }
634
635         } else {
636                 log_error("Unknown verb %s.", argv[1]);
637                 goto finish;
638         }
639
640         r = EXIT_SUCCESS;
641
642 finish:
643
644         if (cd)
645                 crypt_free(cd);
646
647         free(opt_cipher);
648         free(opt_hash);
649         strv_free(opt_tcrypt_keyfiles);
650
651         return r;
652 }