]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.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 }