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