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