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