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