chiark / gitweb /
core: there's no point to complain so loudly about non-isolatable boot targets
[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, *device = NULL;
219         FILE *f = NULL;
220         struct mntent *m;
221
222         /* Yeah, we don't support native systemd unit files here for now */
223
224         if (asprintf(&device, "/dev/mapper/%s", label) < 0)
225                 goto finish;
226
227         f = setmntent("/etc/fstab", "r");
228         if (!f)
229                 goto finish;
230
231         while ((m = getmntent(f)))
232                 if (path_equal(m->mnt_fsname, device)) {
233                         mp = strdup(m->mnt_dir);
234                         break;
235                 }
236
237 finish:
238         if (f)
239                 endmntent(f);
240
241         free(device);
242
243         return mp;
244 }
245
246 static int help(void) {
247
248         printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
249                "%s detach VOLUME\n\n"
250                "Attaches or detaches an encrypted block device.\n",
251                program_invocation_short_name,
252                program_invocation_short_name);
253
254         return 0;
255 }
256
257 int main(int argc, char *argv[]) {
258         int r = EXIT_FAILURE;
259         struct crypt_device *cd = NULL;
260         char **passwords = NULL, *truncated_cipher = NULL;
261         const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
262         char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
263
264         if (argc <= 1) {
265                 help();
266                 return EXIT_SUCCESS;
267         }
268
269         if (argc < 3) {
270                 log_error("This program requires at least two arguments.");
271                 return EXIT_FAILURE;
272         }
273
274         log_set_target(LOG_TARGET_AUTO);
275         log_parse_environment();
276         log_open();
277
278         umask(0022);
279
280         if (streq(argv[1], "attach")) {
281                 uint32_t flags = 0;
282                 int k;
283                 unsigned try;
284                 const char *key_file = NULL;
285                 usec_t until;
286                 crypt_status_info status;
287
288                 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
289
290                 if (argc < 4) {
291                         log_error("attach requires at least two arguments.");
292                         goto finish;
293                 }
294
295                 if (argc >= 5 &&
296                     argv[4][0] &&
297                     !streq(argv[4], "-") &&
298                     !streq(argv[4], "none")) {
299
300                         if (!path_is_absolute(argv[4]))
301                                 log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
302                         else
303                                 key_file = argv[4];
304                 }
305
306                 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
307                         if (parse_options(argv[5]) < 0)
308                                 goto finish;
309                 }
310
311                 /* A delicious drop of snake oil */
312                 mlockall(MCL_FUTURE);
313
314                 description = disk_description(argv[3]);
315                 mount_point = disk_mount_point(argv[2]);
316
317                 if (description && streq(argv[2], description)) {
318                         /* If the description string is simply the
319                          * volume name, then let's not show this
320                          * twice */
321                         free(description);
322                         description = NULL;
323                 }
324
325                 if (mount_point && description)
326                         asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
327                 else if (mount_point)
328                         asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
329                 else if (description)
330                         asprintf(&name_buffer, "%s (%s)", description, argv[2]);
331
332                 name = name_buffer ? name_buffer : argv[2];
333
334                 k = crypt_init(&cd, argv[3]);
335                 if (k) {
336                         log_error("crypt_init() failed: %s", strerror(-k));
337                         goto finish;
338                 }
339
340                 crypt_set_log_callback(cd, log_glue, NULL);
341
342                 status = crypt_status(cd, argv[2]);
343                 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
344                         log_info("Volume %s already active.", argv[2]);
345                         r = EXIT_SUCCESS;
346                         goto finish;
347                 }
348
349                 if (opt_readonly)
350                         flags |= CRYPT_ACTIVATE_READONLY;
351
352                 if (opt_discards)
353                         flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
354
355                 if (opt_timeout > 0)
356                         until = now(CLOCK_MONOTONIC) + opt_timeout;
357                 else
358                         until = 0;
359
360                 opt_tries = opt_tries > 0 ? opt_tries : 3;
361                 opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
362                 if (opt_hash) {
363                         /* plain isn't a real hash type. it just means "use no hash" */
364                         if (!streq(opt_hash, "plain"))
365                                 hash = opt_hash;
366                 } else
367                         hash = "ripemd160";
368
369                 if (opt_cipher) {
370                         size_t l;
371
372                         l = strcspn(opt_cipher, "-");
373                         truncated_cipher = strndup(opt_cipher, l);
374
375                         if (!truncated_cipher) {
376                                 log_oom();
377                                 goto finish;
378                         }
379
380                         cipher = truncated_cipher;
381                         cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
382                 } else {
383                         cipher = "aes";
384                         cipher_mode = "cbc-essiv:sha256";
385                 }
386
387                 for (try = 0; try < opt_tries; try++) {
388                         bool pass_volume_key = false;
389
390                         strv_free(passwords);
391                         passwords = NULL;
392
393                         if (!key_file) {
394                                 char *text, **p;
395
396                                 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
397                                         log_oom();
398                                         goto finish;
399                                 }
400
401                                 k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
402                                 free(text);
403
404                                 if (k < 0) {
405                                         log_error("Failed to query password: %s", strerror(-k));
406                                         goto finish;
407                                 }
408
409                                 if (opt_verify) {
410                                         char **passwords2 = NULL;
411
412                                         assert(strv_length(passwords) == 1);
413
414                                         if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
415                                                 log_oom();
416                                                 goto finish;
417                                         }
418
419                                         k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
420                                         free(text);
421
422                                         if (k < 0) {
423                                                 log_error("Failed to query verification password: %s", strerror(-k));
424                                                 goto finish;
425                                         }
426
427                                         assert(strv_length(passwords2) == 1);
428
429                                         if (!streq(passwords[0], passwords2[0])) {
430                                                 log_warning("Passwords did not match, retrying.");
431                                                 strv_free(passwords2);
432                                                 continue;
433                                         }
434
435                                         strv_free(passwords2);
436                                 }
437
438                                 strv_uniq(passwords);
439
440                                 STRV_FOREACH(p, passwords) {
441                                         char *c;
442
443                                         if (strlen(*p)+1 >= opt_key_size)
444                                                 continue;
445
446                                         /* Pad password if necessary */
447                                         if (!(c = new(char, opt_key_size))) {
448                                                 log_oom();
449                                                 goto finish;
450                                         }
451
452                                         strncpy(c, *p, opt_key_size);
453                                         free(*p);
454                                         *p = c;
455                                 }
456                         }
457
458                         k = 0;
459
460                         if (!opt_type || streq(opt_type, CRYPT_LUKS1))
461                                 k = crypt_load(cd, CRYPT_LUKS1, NULL);
462
463                         if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
464                                 struct crypt_params_plain params = { .hash = hash };
465
466                                 /* for CRYPT_PLAIN limit reads
467                                 * from keyfile to key length, and
468                                 * ignore keyfile-size */
469                                 opt_keyfile_size = opt_key_size / 8;
470
471                                 /* In contrast to what the name
472                                  * crypt_setup() might suggest this
473                                  * doesn't actually format anything,
474                                  * it just configures encryption
475                                  * parameters when used for plain
476                                  * mode. */
477                                 k = crypt_format(cd, CRYPT_PLAIN,
478                                                  cipher,
479                                                  cipher_mode,
480                                                  NULL,
481                                                  NULL,
482                                                  opt_keyfile_size,
483                                                  &params);
484
485                                 /* hash == NULL implies the user passed "plain" */
486                                 pass_volume_key = (hash == NULL);
487                         }
488
489                         if (k < 0) {
490                                 log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
491                                 goto finish;
492                         }
493
494                         log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
495                                  crypt_get_cipher(cd),
496                                  crypt_get_cipher_mode(cd),
497                                  crypt_get_volume_key_size(cd)*8,
498                                  argv[3]);
499
500                         if (key_file)
501                                 k = crypt_activate_by_keyfile_offset(cd, argv[2], CRYPT_ANY_SLOT, key_file, opt_keyfile_size,
502                                             opt_keyfile_offset, flags);
503                                 if (k < 0) {
504                                         log_error("Failed to activate with key file '%s': %s", key_file, strerror(-k));
505                                         key_file = NULL;
506                                         continue;
507                                 }
508                         else {
509                                 char **p;
510
511                                 STRV_FOREACH(p, passwords) {
512
513                                         if (pass_volume_key)
514                                                 k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
515                                         else
516                                                 k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
517
518                                         if (k >= 0)
519                                                 break;
520                                 }
521                         }
522
523                         if (k >= 0)
524                                 break;
525
526                         if (k != -EPERM) {
527                                 log_error("Failed to activate: %s", strerror(-k));
528                                 goto finish;
529                         }
530
531                         log_warning("Invalid passphrase.");
532                 }
533
534                 if (try >= opt_tries) {
535                         log_error("Too many attempts.");
536                         r = EXIT_FAILURE;
537                         goto finish;
538                 }
539
540         } else if (streq(argv[1], "detach")) {
541                 int k;
542
543                 k = crypt_init_by_name(&cd, argv[2]);
544                 if (k) {
545                         log_error("crypt_init() failed: %s", strerror(-k));
546                         goto finish;
547                 }
548
549                 crypt_set_log_callback(cd, log_glue, NULL);
550
551                 k = crypt_deactivate(cd, argv[2]);
552                 if (k < 0) {
553                         log_error("Failed to deactivate: %s", strerror(-k));
554                         goto finish;
555                 }
556
557         } else {
558                 log_error("Unknown verb %s.", argv[1]);
559                 goto finish;
560         }
561
562         r = EXIT_SUCCESS;
563
564 finish:
565
566         if (cd)
567                 crypt_free(cd);
568
569         free(opt_cipher);
570         free(opt_hash);
571
572         free(truncated_cipher);
573
574         strv_free(passwords);
575
576         free(description);
577         free(mount_point);
578         free(name_buffer);
579
580         return r;
581 }