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