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