]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup.c
use "Out of memory." consistantly (or with "\n")
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup.c
CommitLineData
e23a0ce8
LP
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
5430f7f2
LP
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
e23a0ce8
LP
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
5430f7f2 16 Lesser General Public License for more details.
e23a0ce8 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
e23a0ce8
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <string.h>
7f4e0805 23#include <errno.h>
b853f6e9 24#include <sys/mman.h>
b61e476f 25#include <mntent.h>
7f4e0805
LP
26
27#include <libcryptsetup.h>
b1a2da0a 28#include <libudev.h>
e23a0ce8
LP
29
30#include "log.h"
31#include "util.h"
9eb977db 32#include "path-util.h"
21bc923a 33#include "strv.h"
7f4e0805 34#include "ask-password-api.h"
f6a6225e 35#include "def.h"
7f4e0805 36
260ab287 37static const char *opt_type = NULL; /* LUKS1 or PLAIN */
7f4e0805 38static char *opt_cipher = NULL;
260ab287 39static unsigned opt_key_size = 0;
880a599e 40static unsigned opt_keyfile_offset = 0;
7f4e0805 41static char *opt_hash = NULL;
260ab287 42static unsigned opt_tries = 0;
7f4e0805
LP
43static bool opt_readonly = false;
44static bool opt_verify = false;
2a2aab60 45static bool opt_discards = false;
90724929 46static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC;
7f4e0805 47
1fc76335
LP
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
7f4e0805
LP
60static int parse_one_option(const char *option) {
61 assert(option);
62
63 /* Handled outside of this tool */
260ab287 64 if (streq(option, "noauto"))
7f4e0805
LP
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
260ab287 78 if (safe_atou(option+5, &opt_key_size) < 0) {
7f4e0805
LP
79 log_error("size= parse failure, ignoring.");
80 return 0;
81 }
82
880a599e
TG
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
7f4e0805
LP
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;
2a2aab60
MM
110 else if (streq(option, "allow-discards"))
111 opt_discards = true;
260ab287
LP
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;
7f4e0805
LP
118 else if (startswith(option, "timeout=")) {
119
260ab287 120 if (parse_usec(option+8, &opt_timeout) < 0) {
7f4e0805
LP
121 log_error("timeout= parse failure, ignoring.");
122 return 0;
123 }
124
41e6f28a 125 } else if (!streq(option, "none"))
7f4e0805
LP
126 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
127
128 return 0;
129}
130
131static 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
155static void log_glue(int level, const char *msg, void *usrptr) {
260ab287 156 log_debug("%s", msg);
7f4e0805 157}
e23a0ce8 158
b1a2da0a
LP
159static 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")) ||
b61e476f
LP
181 (model = udev_device_get_property_value(device, "ID_MODEL")) ||
182 (model = udev_device_get_property_value(device, "DM_NAME")))
b1a2da0a
LP
183 description = strdup(model);
184
185finish:
186 if (device)
187 udev_device_unref(device);
188
189 if (udev)
190 udev_unref(udev);
191
192 return description;
193}
194
b61e476f
LP
195static 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
e0295d26
LP
205 f = setmntent("/etc/fstab", "r");
206 if (!f)
b61e476f
LP
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
215finish:
216 if (f)
217 endmntent(f);
218
219 free(device);
220
221 return mp;
222}
223
dd5e696d
LP
224static 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
e23a0ce8 235int main(int argc, char *argv[]) {
7f4e0805
LP
236 int r = EXIT_FAILURE;
237 struct crypt_device *cd = NULL;
21bc923a 238 char **passwords = NULL, *truncated_cipher = NULL;
b1a2da0a 239 const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
b61e476f 240 char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
2d745456 241 unsigned keyfile_size = 0;
e23a0ce8 242
dd5e696d
LP
243 if (argc <= 1) {
244 help();
245 return EXIT_SUCCESS;
246 }
247
e23a0ce8
LP
248 if (argc < 3) {
249 log_error("This program requires at least two arguments.");
250 return EXIT_FAILURE;
251 }
252
bb7df0da 253 log_set_target(LOG_TARGET_AUTO);
e23a0ce8
LP
254 log_parse_environment();
255 log_open();
256
4c12626c
LP
257 umask(0022);
258
260ab287 259 if (streq(argv[1], "attach")) {
7f4e0805
LP
260 uint32_t flags = 0;
261 int k;
260ab287 262 unsigned try;
7f4e0805 263 const char *key_file = NULL;
260ab287 264 usec_t until;
e2d480b9 265 crypt_status_info status;
7f4e0805 266
b61e476f
LP
267 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
268
7f4e0805
LP
269 if (argc < 4) {
270 log_error("attach requires at least two arguments.");
271 goto finish;
272 }
273
1fc76335
LP
274 if (argc >= 5 &&
275 argv[4][0] &&
276 !streq(argv[4], "-") &&
277 !streq(argv[4], "none")) {
7f4e0805
LP
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]);
e23a0ce8 287
b853f6e9
LP
288 /* A delicious drop of snake oil */
289 mlockall(MCL_FUTURE);
290
b1a2da0a 291 description = disk_description(argv[3]);
b61e476f
LP
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];
b1a2da0a 310
7f4e0805
LP
311 if ((k = crypt_init(&cd, argv[3]))) {
312 log_error("crypt_init() failed: %s", strerror(-k));
313 goto finish;
314 }
e23a0ce8 315
7f4e0805 316 crypt_set_log_callback(cd, log_glue, NULL);
7f4e0805 317
260ab287
LP
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;
7f4e0805
LP
322 goto finish;
323 }
324
325 if (opt_readonly)
326 flags |= CRYPT_ACTIVATE_READONLY;
327
2a2aab60
MM
328 if (opt_discards)
329 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
330
7dcda352
LP
331 if (opt_timeout > 0)
332 until = now(CLOCK_MONOTONIC) + opt_timeout;
333 else
334 until = 0;
260ab287
LP
335
336 opt_tries = opt_tries > 0 ? opt_tries : 3;
337 opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
260ab287
LP
338 hash = opt_hash ? opt_hash : "ripemd160";
339
e2d480b9
LP
340 if (opt_cipher) {
341 size_t l;
342
343 l = strcspn(opt_cipher, "-");
344
345 if (!(truncated_cipher = strndup(opt_cipher, l))) {
669241a0 346 log_error("Out of memory.");
e2d480b9
LP
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
260ab287
LP
357 for (try = 0; try < opt_tries; try++) {
358 bool pass_volume_key = false;
359
21bc923a
LP
360 strv_free(passwords);
361 passwords = NULL;
260ab287
LP
362
363 if (!key_file) {
494856b5 364 char *text;
21bc923a 365 char **p;
260ab287 366
1cd4a9f0 367 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
669241a0 368 log_error("Out of memory.");
494856b5
LP
369 goto finish;
370 }
371
21bc923a 372 k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
494856b5
LP
373 free(text);
374
375 if (k < 0) {
260ab287
LP
376 log_error("Failed to query password: %s", strerror(-k));
377 goto finish;
378 }
379
380 if (opt_verify) {
21bc923a
LP
381 char **passwords2 = NULL;
382
383 assert(strv_length(passwords) == 1);
260ab287 384
1cd4a9f0 385 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
669241a0 386 log_error("Out of memory.");
494856b5
LP
387 goto finish;
388 }
389
21bc923a 390 k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
494856b5
LP
391 free(text);
392
393 if (k < 0) {
260ab287
LP
394 log_error("Failed to query verification password: %s", strerror(-k));
395 goto finish;
396 }
397
21bc923a
LP
398 assert(strv_length(passwords2) == 1);
399
400 if (!streq(passwords[0], passwords2[0])) {
260ab287 401 log_warning("Passwords did not match, retrying.");
21bc923a 402 strv_free(passwords2);
260ab287
LP
403 continue;
404 }
405
21bc923a 406 strv_free(passwords2);
260ab287
LP
407 }
408
b61e476f
LP
409 strv_uniq(passwords);
410
21bc923a 411 STRV_FOREACH(p, passwords) {
260ab287
LP
412 char *c;
413
21bc923a
LP
414 if (strlen(*p)+1 >= opt_key_size)
415 continue;
260ab287 416
21bc923a 417 /* Pad password if necessary */
260ab287
LP
418 if (!(c = new(char, opt_key_size))) {
419 log_error("Out of memory.");
420 goto finish;
421 }
422
21bc923a
LP
423 strncpy(c, *p, opt_key_size);
424 free(*p);
425 *p = c;
260ab287
LP
426 }
427 }
428
7dcda352
LP
429 k = 0;
430
260ab287
LP
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");
2d745456
MB
455
456 /* for CRYPT_PLAIN limit reads
457 * from keyfile to key length */
458 keyfile_size = opt_key_size / 8;
260ab287
LP
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)
880a599e
TG
473 k = crypt_activate_by_keyfile_offset(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size,
474 opt_keyfile_offset, flags);
21bc923a
LP
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 }
260ab287
LP
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.");
7f4e0805
LP
499 }
500
260ab287
LP
501 if (try >= opt_tries) {
502 log_error("Too many attempts.");
503 r = EXIT_FAILURE;
bd40a2d8 504 goto finish;
7f4e0805
LP
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 }
e23a0ce8
LP
521
522 } else {
523 log_error("Unknown verb %s.", argv[1]);
524 goto finish;
525 }
526
7f4e0805
LP
527 r = EXIT_SUCCESS;
528
e23a0ce8 529finish:
7f4e0805
LP
530
531 if (cd)
532 crypt_free(cd);
533
260ab287 534 free(opt_cipher);
260ab287
LP
535 free(opt_hash);
536
e2d480b9
LP
537 free(truncated_cipher);
538
21bc923a 539 strv_free(passwords);
260ab287 540
b1a2da0a 541 free(description);
b61e476f
LP
542 free(mount_point);
543 free(name_buffer);
b1a2da0a 544
e23a0ce8
LP
545 return r;
546}