chiark / gitweb /
cryptsetup: Move password query out of main
[elogind.git] / src / cryptsetup / cryptsetup.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/mman.h>
25 #include <mntent.h>
26
27 #include <libcryptsetup.h>
28 #include <libudev.h>
29
30 #include "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
37 static const char *opt_type = NULL; /* LUKS1 or PLAIN */
38 static char *opt_cipher = NULL;
39 static unsigned opt_key_size = 0;
40 static unsigned opt_keyfile_size = 0;
41 static unsigned opt_keyfile_offset = 0;
42 static char *opt_hash = NULL;
43 static unsigned opt_tries = 0;
44 static bool opt_readonly = false;
45 static bool opt_verify = false;
46 static bool opt_discards = false;
47 static usec_t opt_timeout = 0;
48
49 /* Options Debian's crypttab knows we don't:
50
51     offset=
52     skip=
53     precheck=
54     check=
55     checkargs=
56     noearly=
57     loud=
58     keyscript=
59 */
60
61 static int parse_one_option(const char *option) {
62         assert(option);
63
64         /* Handled outside of this tool */
65         if (streq(option, "noauto") || streq(option, "nofail"))
66                 return 0;
67
68         if (startswith(option, "cipher=")) {
69                 char *t;
70
71                 t = strdup(option+7);
72                 if (!t)
73                         return -ENOMEM;
74
75                 free(opt_cipher);
76                 opt_cipher = t;
77
78         } else if (startswith(option, "size=")) {
79
80                 if (safe_atou(option+5, &opt_key_size) < 0) {
81                         log_error("size= parse failure, ignoring.");
82                         return 0;
83                 }
84
85         } else if (startswith(option, "keyfile-size=")) {
86
87                 if (safe_atou(option+13, &opt_keyfile_size) < 0) {
88                         log_error("keyfile-size= parse failure, ignoring.");
89                         return 0;
90                 }
91
92         } else if (startswith(option, "keyfile-offset=")) {
93
94                 if (safe_atou(option+15, &opt_keyfile_offset) < 0) {
95                         log_error("keyfile-offset= parse failure, ignoring.");
96                         return 0;
97                 }
98
99         } else if (startswith(option, "hash=")) {
100                 char *t;
101
102                 t = strdup(option+5);
103                 if (!t)
104                         return -ENOMEM;
105
106                 free(opt_hash);
107                 opt_hash = t;
108
109         } else if (startswith(option, "tries=")) {
110
111                 if (safe_atou(option+6, &opt_tries) < 0) {
112                         log_error("tries= parse failure, ignoring.");
113                         return 0;
114                 }
115
116         } else if (streq(option, "readonly") || streq(option, "read-only"))
117                 opt_readonly = true;
118         else if (streq(option, "verify"))
119                 opt_verify = true;
120         else if (streq(option, "allow-discards"))
121                 opt_discards = true;
122         else if (streq(option, "luks"))
123                 opt_type = CRYPT_LUKS1;
124         else if (streq(option, "plain") ||
125                  streq(option, "swap") ||
126                  streq(option, "tmp"))
127                 opt_type = CRYPT_PLAIN;
128         else if (startswith(option, "timeout=")) {
129
130                 if (parse_sec(option+8, &opt_timeout) < 0) {
131                         log_error("timeout= parse failure, ignoring.");
132                         return 0;
133                 }
134
135         } else if (!streq(option, "none"))
136                 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
137
138         return 0;
139 }
140
141 static int parse_options(const char *options) {
142         char *state, *w;
143         size_t l;
144         int r;
145
146         assert(options);
147
148         FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
149                 _cleanup_free_ char *o;
150
151                 o = strndup(w, l);
152                 if (!o)
153                         return -ENOMEM;
154                 r = parse_one_option(o);
155                 if (r < 0)
156                         return r;
157         }
158
159         return 0;
160 }
161
162 static void log_glue(int level, const char *msg, void *usrptr) {
163         log_debug("%s", msg);
164 }
165
166 static char *disk_description(const char *path) {
167
168         static const char name_fields[] = {
169                 "ID_PART_ENTRY_NAME\0"
170                 "DM_NAME\0"
171                 "ID_MODEL_FROM_DATABASE\0"
172                 "ID_MODEL\0"
173         };
174
175         struct udev *udev = NULL;
176         struct udev_device *device = NULL;
177         struct stat st;
178         char *description = NULL;
179         const char *i;
180
181         assert(path);
182
183         if (stat(path, &st) < 0)
184                 return NULL;
185
186         if (!S_ISBLK(st.st_mode))
187                 return NULL;
188
189         udev = udev_new();
190         if (!udev)
191                 return NULL;
192
193         device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
194         if (!device)
195                 goto finish;
196
197         NULSTR_FOREACH(i, name_fields) {
198                 const char *name;
199
200                 name = udev_device_get_property_value(device, i);
201                 if (!isempty(name)) {
202                         description = strdup(name);
203                         break;
204                 }
205         }
206
207 finish:
208         if (device)
209                 udev_device_unref(device);
210
211         if (udev)
212                 udev_unref(udev);
213
214         return description;
215 }
216
217 static char *disk_mount_point(const char *label) {
218         char *mp = NULL;
219         _cleanup_free_ char *device = NULL;
220         FILE *f = NULL;
221         struct mntent *m;
222
223         /* Yeah, we don't support native systemd unit files here for now */
224
225         if (asprintf(&device, "/dev/mapper/%s", label) < 0)
226                 goto finish;
227
228         f = setmntent("/etc/fstab", "r");
229         if (!f)
230                 goto finish;
231
232         while ((m = getmntent(f)))
233                 if (path_equal(m->mnt_fsname, device)) {
234                         mp = strdup(m->mnt_dir);
235                         break;
236                 }
237
238 finish:
239         if (f)
240                 endmntent(f);
241
242         return mp;
243 }
244
245 static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) {
246         int r;
247         char **p;
248         _cleanup_free_ char *text = NULL;
249
250         assert(name);
251         assert(passwords);
252
253         if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
254                 return log_oom();
255
256         r = ask_password_auto(text, "drive-harddisk", until, accept_cached, passwords);
257         if (r < 0) {
258                 log_error("Failed to query password: %s", strerror(-r));
259                 return r;
260         }
261
262         if (opt_verify) {
263                 _cleanup_strv_free_ char **passwords2 = NULL;
264
265                 assert(strv_length(*passwords) == 1);
266
267                 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
268                         return log_oom();
269
270                 r = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
271                 if (r < 0) {
272                         log_error("Failed to query verification password: %s", strerror(-r));
273                         return r;
274                 }
275
276                 assert(strv_length(passwords2) == 1);
277
278                 if (!streq(*passwords[0], passwords2[0])) {
279                         log_warning("Passwords did not match, retrying.");
280                         return -EAGAIN;
281                 }
282         }
283
284         strv_uniq(*passwords);
285
286         STRV_FOREACH(p, *passwords) {
287                 char *c;
288
289                 if (strlen(*p)+1 >= opt_key_size)
290                         continue;
291
292                 /* Pad password if necessary */
293                 if (!(c = new(char, opt_key_size)))
294                         return log_oom();
295
296                 strncpy(c, *p, opt_key_size);
297                 free(*p);
298                 *p = c;
299         }
300
301         return 0;
302 }
303
304 static int help(void) {
305
306         printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
307                "%s detach VOLUME\n\n"
308                "Attaches or detaches an encrypted block device.\n",
309                program_invocation_short_name,
310                program_invocation_short_name);
311
312         return 0;
313 }
314
315 int main(int argc, char *argv[]) {
316         int r = EXIT_FAILURE;
317         struct crypt_device *cd = NULL;
318
319         if (argc <= 1) {
320                 help();
321                 return EXIT_SUCCESS;
322         }
323
324         if (argc < 3) {
325                 log_error("This program requires at least two arguments.");
326                 return EXIT_FAILURE;
327         }
328
329         log_set_target(LOG_TARGET_AUTO);
330         log_parse_environment();
331         log_open();
332
333         umask(0022);
334
335         if (streq(argv[1], "attach")) {
336                 uint32_t flags = 0;
337                 int k;
338                 unsigned try;
339                 usec_t until;
340                 crypt_status_info status;
341                 const char *key_file = NULL, *cipher = NULL, *cipher_mode = NULL,
342                            *hash = NULL, *name = NULL;
343                 _cleanup_free_ char *description = NULL, *name_buffer = NULL,
344                                     *mount_point = NULL, *truncated_cipher = NULL;
345
346                 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
347
348                 if (argc < 4) {
349                         log_error("attach requires at least two arguments.");
350                         goto finish;
351                 }
352
353                 if (argc >= 5 &&
354                     argv[4][0] &&
355                     !streq(argv[4], "-") &&
356                     !streq(argv[4], "none")) {
357
358                         if (!path_is_absolute(argv[4]))
359                                 log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
360                         else
361                                 key_file = argv[4];
362                 }
363
364                 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
365                         if (parse_options(argv[5]) < 0)
366                                 goto finish;
367                 }
368
369                 /* A delicious drop of snake oil */
370                 mlockall(MCL_FUTURE);
371
372                 description = disk_description(argv[3]);
373                 mount_point = disk_mount_point(argv[2]);
374
375                 if (description && streq(argv[2], description)) {
376                         /* If the description string is simply the
377                          * volume name, then let's not show this
378                          * twice */
379                         free(description);
380                         description = NULL;
381                 }
382
383                 if (mount_point && description)
384                         asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
385                 else if (mount_point)
386                         asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
387                 else if (description)
388                         asprintf(&name_buffer, "%s (%s)", description, argv[2]);
389
390                 name = name_buffer ? name_buffer : argv[2];
391
392                 k = crypt_init(&cd, argv[3]);
393                 if (k) {
394                         log_error("crypt_init() failed: %s", strerror(-k));
395                         goto finish;
396                 }
397
398                 crypt_set_log_callback(cd, log_glue, NULL);
399
400                 status = crypt_status(cd, argv[2]);
401                 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
402                         log_info("Volume %s already active.", argv[2]);
403                         r = EXIT_SUCCESS;
404                         goto finish;
405                 }
406
407                 if (opt_readonly)
408                         flags |= CRYPT_ACTIVATE_READONLY;
409
410                 if (opt_discards)
411                         flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
412
413                 if (opt_timeout > 0)
414                         until = now(CLOCK_MONOTONIC) + opt_timeout;
415                 else
416                         until = 0;
417
418                 opt_tries = opt_tries > 0 ? opt_tries : 3;
419                 opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
420                 if (opt_hash) {
421                         /* plain isn't a real hash type. it just means "use no hash" */
422                         if (!streq(opt_hash, "plain"))
423                                 hash = opt_hash;
424                 } else
425                         hash = "ripemd160";
426
427                 if (opt_cipher) {
428                         size_t l;
429
430                         l = strcspn(opt_cipher, "-");
431                         truncated_cipher = strndup(opt_cipher, l);
432
433                         if (!truncated_cipher) {
434                                 log_oom();
435                                 goto finish;
436                         }
437
438                         cipher = truncated_cipher;
439                         cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
440                 } else {
441                         cipher = "aes";
442                         cipher_mode = "cbc-essiv:sha256";
443                 }
444
445                 for (try = 0; try < opt_tries; try++) {
446                         bool pass_volume_key = false;
447                         _cleanup_strv_free_ char **passwords = NULL;
448
449                         if (!key_file) {
450                                 k = get_password(name, until, try == 0 && !opt_verify, &passwords);
451                                 if (k == -EAGAIN)
452                                         continue;
453                                 else if (k < 0)
454                                         goto finish;
455                         }
456
457                         k = 0;
458
459                         if (!opt_type || streq(opt_type, CRYPT_LUKS1))
460                                 k = crypt_load(cd, CRYPT_LUKS1, NULL);
461
462                         if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
463                                 struct crypt_params_plain params = { .hash = hash };
464
465                                 /* for CRYPT_PLAIN limit reads
466                                  * from keyfile to key length, and
467                                  * ignore keyfile-size */
468                                 opt_keyfile_size = opt_key_size / 8;
469
470                                 /* In contrast to what the name
471                                  * crypt_setup() might suggest this
472                                  * doesn't actually format anything,
473                                  * it just configures encryption
474                                  * parameters when used for plain
475                                  * mode. */
476                                 k = crypt_format(cd, CRYPT_PLAIN,
477                                                  cipher,
478                                                  cipher_mode,
479                                                  NULL,
480                                                  NULL,
481                                                  opt_keyfile_size,
482                                                  &params);
483
484                                 /* hash == NULL implies the user passed "plain" */
485                                 pass_volume_key = (hash == NULL);
486                         }
487
488                         if (k < 0) {
489                                 log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
490                                 goto finish;
491                         }
492
493                         log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
494                                  crypt_get_cipher(cd),
495                                  crypt_get_cipher_mode(cd),
496                                  crypt_get_volume_key_size(cd)*8,
497                                  argv[3]);
498
499                         if (key_file) {
500                                 struct stat st;
501
502                                 /* Ideally we'd do this on the open
503                                  * fd, but since this is just a
504                                  * warning it's OK to do this in two
505                                  * steps */
506                                 if (stat(key_file, &st) >= 0 && (st.st_mode & 0005))
507                                         log_warning("Key file %s is world-readable. That's certainly not a good idea.", key_file);
508
509                                 k = crypt_activate_by_keyfile_offset(
510                                                 cd, argv[2], CRYPT_ANY_SLOT, key_file, opt_keyfile_size,
511                                                 opt_keyfile_offset, flags);
512                                 if (k < 0) {
513                                         log_error("Failed to activate with key file '%s': %s", key_file, strerror(-k));
514                                         key_file = NULL;
515                                         continue;
516                                 }
517                         } else {
518                                 char **p;
519
520                                 STRV_FOREACH(p, passwords) {
521
522                                         if (pass_volume_key)
523                                                 k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
524                                         else
525                                                 k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
526
527                                         if (k >= 0)
528                                                 break;
529                                 }
530                         }
531
532                         if (k >= 0)
533                                 break;
534
535                         if (k != -EPERM) {
536                                 log_error("Failed to activate: %s", strerror(-k));
537                                 goto finish;
538                         }
539
540                         log_warning("Invalid passphrase.");
541                 }
542
543                 if (try >= opt_tries) {
544                         log_error("Too many attempts.");
545                         r = EXIT_FAILURE;
546                         goto finish;
547                 }
548
549         } else if (streq(argv[1], "detach")) {
550                 int k;
551
552                 k = crypt_init_by_name(&cd, argv[2]);
553                 if (k) {
554                         log_error("crypt_init() failed: %s", strerror(-k));
555                         goto finish;
556                 }
557
558                 crypt_set_log_callback(cd, log_glue, NULL);
559
560                 k = crypt_deactivate(cd, argv[2]);
561                 if (k < 0) {
562                         log_error("Failed to deactivate: %s", strerror(-k));
563                         goto finish;
564                 }
565
566         } else {
567                 log_error("Unknown verb %s.", argv[1]);
568                 goto finish;
569         }
570
571         r = EXIT_SUCCESS;
572
573 finish:
574
575         if (cd)
576                 crypt_free(cd);
577
578         free(opt_cipher);
579         free(opt_hash);
580
581         return r;
582 }