chiark / gitweb /
6d4e965fe11be56eface30edb832816962058e69
[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 char *opt_hash = NULL;
41 static unsigned opt_tries = 0;
42 static bool opt_readonly = false;
43 static bool opt_verify = false;
44 static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC;
45
46 /* Options Debian's crypttab knows we don't:
47
48     offset=
49     skip=
50     precheck=
51     check=
52     checkargs=
53     noearly=
54     loud=
55     keyscript=
56 */
57
58 static int parse_one_option(const char *option) {
59         assert(option);
60
61         /* Handled outside of this tool */
62         if (streq(option, "noauto"))
63                 return 0;
64
65         if (startswith(option, "cipher=")) {
66                 char *t;
67
68                 if (!(t = strdup(option+7)))
69                         return -ENOMEM;
70
71                 free(opt_cipher);
72                 opt_cipher = t;
73
74         } else if (startswith(option, "size=")) {
75
76                 if (safe_atou(option+5, &opt_key_size) < 0) {
77                         log_error("size= parse failure, ignoring.");
78                         return 0;
79                 }
80
81         } else if (startswith(option, "hash=")) {
82                 char *t;
83
84                 if (!(t = strdup(option+5)))
85                         return -ENOMEM;
86
87                 free(opt_hash);
88                 opt_hash = t;
89
90         } else if (startswith(option, "tries=")) {
91
92                 if (safe_atou(option+6, &opt_tries) < 0) {
93                         log_error("tries= parse failure, ignoring.");
94                         return 0;
95                 }
96
97         } else if (streq(option, "readonly"))
98                 opt_readonly = true;
99         else if (streq(option, "verify"))
100                 opt_verify = true;
101         else if (streq(option, "luks"))
102                 opt_type = CRYPT_LUKS1;
103         else if (streq(option, "plain") ||
104                  streq(option, "swap") ||
105                  streq(option, "tmp"))
106                 opt_type = CRYPT_PLAIN;
107         else if (startswith(option, "timeout=")) {
108
109                 if (parse_usec(option+8, &opt_timeout) < 0) {
110                         log_error("timeout= parse failure, ignoring.");
111                         return 0;
112                 }
113
114         } else if (!streq(option, "none"))
115                 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
116
117         return 0;
118 }
119
120 static int parse_options(const char *options) {
121         char *state;
122         char *w;
123         size_t l;
124
125         assert(options);
126
127         FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
128                 char *o;
129                 int r;
130
131                 if (!(o = strndup(w, l)))
132                         return -ENOMEM;
133
134                 r = parse_one_option(o);
135                 free(o);
136
137                 if (r < 0)
138                         return r;
139         }
140
141         return 0;
142 }
143
144 static void log_glue(int level, const char *msg, void *usrptr) {
145         log_debug("%s", msg);
146 }
147
148 static char *disk_description(const char *path) {
149         struct udev *udev = NULL;
150         struct udev_device *device = NULL;
151         struct stat st;
152         char *description = NULL;
153         const char *model;
154
155         assert(path);
156
157         if (stat(path, &st) < 0)
158                 return NULL;
159
160         if (!S_ISBLK(st.st_mode))
161                 return NULL;
162
163         if (!(udev = udev_new()))
164                 return NULL;
165
166         if (!(device = udev_device_new_from_devnum(udev, 'b', st.st_rdev)))
167                 goto finish;
168
169         if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) ||
170             (model = udev_device_get_property_value(device, "ID_MODEL")) ||
171             (model = udev_device_get_property_value(device, "DM_NAME")))
172                 description = strdup(model);
173
174 finish:
175         if (device)
176                 udev_device_unref(device);
177
178         if (udev)
179                 udev_unref(udev);
180
181         return description;
182 }
183
184 static char *disk_mount_point(const char *label) {
185         char *mp = NULL, *device = NULL;
186         FILE *f = NULL;
187         struct mntent *m;
188
189         /* Yeah, we don't support native systemd unit files here for now */
190
191         if (asprintf(&device, "/dev/mapper/%s", label) < 0)
192                 goto finish;
193
194         f = setmntent("/etc/fstab", "r");
195         if (!f)
196                 goto finish;
197
198         while ((m = getmntent(f)))
199                 if (path_equal(m->mnt_fsname, device)) {
200                         mp = strdup(m->mnt_dir);
201                         break;
202                 }
203
204 finish:
205         if (f)
206                 endmntent(f);
207
208         free(device);
209
210         return mp;
211 }
212
213 static int help(void) {
214
215         printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
216                "%s detach VOLUME\n\n"
217                "Attaches or detaches an encrypted block device.\n",
218                program_invocation_short_name,
219                program_invocation_short_name);
220
221         return 0;
222 }
223
224 int main(int argc, char *argv[]) {
225         int r = EXIT_FAILURE;
226         struct crypt_device *cd = NULL;
227         char **passwords = NULL, *truncated_cipher = NULL;
228         const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
229         char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
230         unsigned keyfile_size = 0;
231
232         if (argc <= 1) {
233                 help();
234                 return EXIT_SUCCESS;
235         }
236
237         if (argc < 3) {
238                 log_error("This program requires at least two arguments.");
239                 return EXIT_FAILURE;
240         }
241
242         log_set_target(LOG_TARGET_AUTO);
243         log_parse_environment();
244         log_open();
245
246         umask(0022);
247
248         if (streq(argv[1], "attach")) {
249                 uint32_t flags = 0;
250                 int k;
251                 unsigned try;
252                 const char *key_file = NULL;
253                 usec_t until;
254                 crypt_status_info status;
255
256                 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
257
258                 if (argc < 4) {
259                         log_error("attach requires at least two arguments.");
260                         goto finish;
261                 }
262
263                 if (argc >= 5 &&
264                     argv[4][0] &&
265                     !streq(argv[4], "-") &&
266                     !streq(argv[4], "none")) {
267
268                         if (!path_is_absolute(argv[4]))
269                                 log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
270                         else
271                                 key_file = argv[4];
272                 }
273
274                 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-"))
275                         parse_options(argv[5]);
276
277                 /* A delicious drop of snake oil */
278                 mlockall(MCL_FUTURE);
279
280                 description = disk_description(argv[3]);
281                 mount_point = disk_mount_point(argv[2]);
282
283                 if (description && streq(argv[2], description)) {
284                         /* If the description string is simply the
285                          * volume name, then let's not show this
286                          * twice */
287                         free(description);
288                         description = NULL;
289                 }
290
291                 if (mount_point && description)
292                         asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
293                 else if (mount_point)
294                         asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
295                 else if (description)
296                         asprintf(&name_buffer, "%s (%s)", description, argv[2]);
297
298                 name = name_buffer ? name_buffer : argv[2];
299
300                 if ((k = crypt_init(&cd, argv[3]))) {
301                         log_error("crypt_init() failed: %s", strerror(-k));
302                         goto finish;
303                 }
304
305                 crypt_set_log_callback(cd, log_glue, NULL);
306
307                 status = crypt_status(cd, argv[2]);
308                 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
309                         log_info("Volume %s already active.", argv[2]);
310                         r = EXIT_SUCCESS;
311                         goto finish;
312                 }
313
314                 if (opt_readonly)
315                         flags |= CRYPT_ACTIVATE_READONLY;
316
317                 if (opt_timeout > 0)
318                         until = now(CLOCK_MONOTONIC) + opt_timeout;
319                 else
320                         until = 0;
321
322                 opt_tries = opt_tries > 0 ? opt_tries : 3;
323                 opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
324                 hash = opt_hash ? opt_hash : "ripemd160";
325
326                 if (opt_cipher) {
327                         size_t l;
328
329                         l = strcspn(opt_cipher, "-");
330
331                         if (!(truncated_cipher = strndup(opt_cipher, l))) {
332                                 log_error("Out of memory");
333                                 goto finish;
334                         }
335
336                         cipher = truncated_cipher;
337                         cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
338                 } else {
339                         cipher = "aes";
340                         cipher_mode = "cbc-essiv:sha256";
341                 }
342
343                 for (try = 0; try < opt_tries; try++) {
344                         bool pass_volume_key = false;
345
346                         strv_free(passwords);
347                         passwords = NULL;
348
349                         if (!key_file) {
350                                 char *text;
351                                 char **p;
352
353                                 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
354                                         log_error("Out of memory");
355                                         goto finish;
356                                 }
357
358                                 k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
359                                 free(text);
360
361                                 if (k < 0) {
362                                         log_error("Failed to query password: %s", strerror(-k));
363                                         goto finish;
364                                 }
365
366                                 if (opt_verify) {
367                                         char **passwords2 = NULL;
368
369                                         assert(strv_length(passwords) == 1);
370
371                                         if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
372                                                 log_error("Out of memory");
373                                                 goto finish;
374                                         }
375
376                                         k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
377                                         free(text);
378
379                                         if (k < 0) {
380                                                 log_error("Failed to query verification password: %s", strerror(-k));
381                                                 goto finish;
382                                         }
383
384                                         assert(strv_length(passwords2) == 1);
385
386                                         if (!streq(passwords[0], passwords2[0])) {
387                                                 log_warning("Passwords did not match, retrying.");
388                                                 strv_free(passwords2);
389                                                 continue;
390                                         }
391
392                                         strv_free(passwords2);
393                                 }
394
395                                 strv_uniq(passwords);
396
397                                 STRV_FOREACH(p, passwords) {
398                                         char *c;
399
400                                         if (strlen(*p)+1 >= opt_key_size)
401                                                 continue;
402
403                                         /* Pad password if necessary */
404                                         if (!(c = new(char, opt_key_size))) {
405                                                 log_error("Out of memory.");
406                                                 goto finish;
407                                         }
408
409                                         strncpy(c, *p, opt_key_size);
410                                         free(*p);
411                                         *p = c;
412                                 }
413                         }
414
415                         k = 0;
416
417                         if (!opt_type || streq(opt_type, CRYPT_LUKS1))
418                                 k = crypt_load(cd, CRYPT_LUKS1, NULL);
419
420                         if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
421                                 struct crypt_params_plain params;
422
423                                 zero(params);
424                                 params.hash = hash;
425
426                                 /* In contrast to what the name
427                                  * crypt_setup() might suggest this
428                                  * doesn't actually format anything,
429                                  * it just configures encryption
430                                  * parameters when used for plain
431                                  * mode. */
432                                 k = crypt_format(cd, CRYPT_PLAIN,
433                                                  cipher,
434                                                  cipher_mode,
435                                                  NULL,
436                                                  NULL,
437                                                  opt_key_size / 8,
438                                                  &params);
439
440                                 pass_volume_key = streq(hash, "plain");
441
442                                /* for CRYPT_PLAIN limit reads
443                                 * from keyfile to key length */
444                                 keyfile_size = opt_key_size / 8;
445                         }
446
447                         if (k < 0) {
448                                 log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
449                                 goto finish;
450                         }
451
452                         log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
453                                  crypt_get_cipher(cd),
454                                  crypt_get_cipher_mode(cd),
455                                  crypt_get_volume_key_size(cd)*8,
456                                  argv[3]);
457
458                         if (key_file)
459                                 k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size, flags);
460                         else {
461                                 char **p;
462
463                                 STRV_FOREACH(p, passwords) {
464
465                                         if (pass_volume_key)
466                                                 k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
467                                         else
468                                                 k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
469
470                                         if (k >= 0)
471                                                 break;
472                                 }
473                         }
474
475                         if (k >= 0)
476                                 break;
477
478                         if (k != -EPERM) {
479                                 log_error("Failed to activate: %s", strerror(-k));
480                                 goto finish;
481                         }
482
483                         log_warning("Invalid passphrase.");
484                 }
485
486                 if (try >= opt_tries) {
487                         log_error("Too many attempts.");
488                         r = EXIT_FAILURE;
489                         goto finish;
490                 }
491
492         } else if (streq(argv[1], "detach")) {
493                 int k;
494
495                 if ((k = crypt_init_by_name(&cd, argv[2]))) {
496                         log_error("crypt_init() failed: %s", strerror(-k));
497                         goto finish;
498                 }
499
500                 crypt_set_log_callback(cd, log_glue, NULL);
501
502                 if ((k = crypt_deactivate(cd, argv[2])) < 0) {
503                         log_error("Failed to deactivate: %s", strerror(-k));
504                         goto finish;
505                 }
506
507         } else {
508                 log_error("Unknown verb %s.", argv[1]);
509                 goto finish;
510         }
511
512         r = EXIT_SUCCESS;
513
514 finish:
515
516         if (cd)
517                 crypt_free(cd);
518
519         free(opt_cipher);
520         free(opt_hash);
521
522         free(truncated_cipher);
523
524         strv_free(passwords);
525
526         free(description);
527         free(mount_point);
528         free(name_buffer);
529
530         return r;
531 }