chiark / gitweb /
conf-parse: rename config_parse_level() to config_parse_log_level()
[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 *opt_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
40 static char *opt_cipher = NULL;
41 static unsigned opt_key_size = 0;
42 static int opt_key_slot = CRYPT_ANY_SLOT;
43 static unsigned opt_keyfile_size = 0;
44 static unsigned opt_keyfile_offset = 0;
45 static char *opt_hash = NULL;
46 static unsigned opt_tries = 3;
47 static bool opt_readonly = false;
48 static bool opt_verify = false;
49 static bool opt_discards = false;
50 static bool opt_tcrypt_hidden = false;
51 static bool opt_tcrypt_system = false;
52 static char **opt_tcrypt_keyfiles = NULL;
53 static usec_t opt_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(opt_cipher);
82                 opt_cipher = t;
83
84         } else if (startswith(option, "size=")) {
85
86                 if (safe_atou(option+5, &opt_key_size) < 0) {
87                         log_error("size= parse failure, ignoring.");
88                         return 0;
89                 }
90
91         } else if (startswith(option, "key-slot=")) {
92
93                 opt_type = CRYPT_LUKS1;
94                 if (safe_atoi(option+9, &opt_key_slot) < 0) {
95                         log_error("key-slot= parse failure, ignoring.");
96                         return 0;
97                 }
98
99         } else if (startswith(option, "tcrypt-keyfile=")) {
100
101                 opt_type = CRYPT_TCRYPT;
102                 if (path_is_absolute(option+15)) {
103                         if (strv_extend(&opt_tcrypt_keyfiles, option + 15) < 0)
104                                 return log_oom();
105                 } else
106                         log_error("Key file path '%s' is not absolute. Ignoring.", option+15);
107
108         } else if (startswith(option, "keyfile-size=")) {
109
110                 if (safe_atou(option+13, &opt_keyfile_size) < 0) {
111                         log_error("keyfile-size= parse failure, ignoring.");
112                         return 0;
113                 }
114
115         } else if (startswith(option, "keyfile-offset=")) {
116
117                 if (safe_atou(option+15, &opt_keyfile_offset) < 0) {
118                         log_error("keyfile-offset= parse failure, ignoring.");
119                         return 0;
120                 }
121
122         } else if (startswith(option, "hash=")) {
123                 char *t;
124
125                 t = strdup(option+5);
126                 if (!t)
127                         return log_oom();
128
129                 free(opt_hash);
130                 opt_hash = t;
131
132         } else if (startswith(option, "tries=")) {
133
134                 if (safe_atou(option+6, &opt_tries) < 0) {
135                         log_error("tries= parse failure, ignoring.");
136                         return 0;
137                 }
138
139         } else if (streq(option, "readonly") || streq(option, "read-only"))
140                 opt_readonly = true;
141         else if (streq(option, "verify"))
142                 opt_verify = true;
143         else if (streq(option, "allow-discards") || streq(option, "discard"))
144                 opt_discards = true;
145         else if (streq(option, "luks"))
146                 opt_type = CRYPT_LUKS1;
147         else if (streq(option, "tcrypt"))
148                 opt_type = CRYPT_TCRYPT;
149         else if (streq(option, "tcrypt-hidden")) {
150                 opt_type = CRYPT_TCRYPT;
151                 opt_tcrypt_hidden = true;
152         } else if (streq(option, "tcrypt-system")) {
153                 opt_type = CRYPT_TCRYPT;
154                 opt_tcrypt_system = true;
155         } else if (streq(option, "plain") ||
156                  streq(option, "swap") ||
157                  streq(option, "tmp"))
158                 opt_type = CRYPT_PLAIN;
159         else if (startswith(option, "timeout=")) {
160
161                 if (parse_sec(option+8, &opt_timeout) < 0) {
162                         log_error("timeout= parse failure, ignoring.");
163                         return 0;
164                 }
165
166         } else if (!streq(option, "none"))
167                 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
168
169         return 0;
170 }
171
172 static int parse_options(const char *options) {
173         char *state, *w;
174         size_t l;
175         int r;
176
177         assert(options);
178
179         FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
180                 _cleanup_free_ char *o;
181
182                 o = strndup(w, l);
183                 if (!o)
184                         return -ENOMEM;
185                 r = parse_one_option(o);
186                 if (r < 0)
187                         return r;
188         }
189
190         return 0;
191 }
192
193 static void log_glue(int level, const char *msg, void *usrptr) {
194         log_debug("%s", msg);
195 }
196
197 static char* disk_description(const char *path) {
198
199         static const char name_fields[] = {
200                 "ID_PART_ENTRY_NAME\0"
201                 "DM_NAME\0"
202                 "ID_MODEL_FROM_DATABASE\0"
203                 "ID_MODEL\0"
204         };
205
206         _cleanup_udev_unref_ struct udev *udev = NULL;
207         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
208         struct stat st;
209         const char *i;
210
211         assert(path);
212
213         if (stat(path, &st) < 0)
214                 return NULL;
215
216         if (!S_ISBLK(st.st_mode))
217                 return NULL;
218
219         udev = udev_new();
220         if (!udev)
221                 return NULL;
222
223         device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
224         if (!device)
225                 return NULL;
226
227         NULSTR_FOREACH(i, name_fields) {
228                 const char *name;
229
230                 name = udev_device_get_property_value(device, i);
231                 if (!isempty(name))
232                         return strdup(name);
233         }
234
235         return NULL;
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, opt_key_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, opt_key_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 }