1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
27 #include <libcryptsetup.h>
32 #include "path-util.h"
34 #include "ask-password-api.h"
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 char *opt_hash = NULL;
41 static unsigned opt_tries = 0;
42 static bool opt_readonly = false;
43 static bool opt_verify = false;
44 static bool opt_discards = false;
45 static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC;
47 /* Options Debian's crypttab knows we don't:
59 static int parse_one_option(const char *option) {
62 /* Handled outside of this tool */
63 if (streq(option, "noauto"))
66 if (startswith(option, "cipher=")) {
69 if (!(t = strdup(option+7)))
75 } else if (startswith(option, "size=")) {
77 if (safe_atou(option+5, &opt_key_size) < 0) {
78 log_error("size= parse failure, ignoring.");
82 } else if (startswith(option, "hash=")) {
85 if (!(t = strdup(option+5)))
91 } else if (startswith(option, "tries=")) {
93 if (safe_atou(option+6, &opt_tries) < 0) {
94 log_error("tries= parse failure, ignoring.");
98 } else if (streq(option, "readonly"))
100 else if (streq(option, "verify"))
102 else if (streq(option, "allow-discards"))
104 else if (streq(option, "luks"))
105 opt_type = CRYPT_LUKS1;
106 else if (streq(option, "plain") ||
107 streq(option, "swap") ||
108 streq(option, "tmp"))
109 opt_type = CRYPT_PLAIN;
110 else if (startswith(option, "timeout=")) {
112 if (parse_usec(option+8, &opt_timeout) < 0) {
113 log_error("timeout= parse failure, ignoring.");
117 } else if (!streq(option, "none"))
118 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
123 static int parse_options(const char *options) {
130 FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
134 if (!(o = strndup(w, l)))
137 r = parse_one_option(o);
147 static void log_glue(int level, const char *msg, void *usrptr) {
148 log_debug("%s", msg);
151 static char *disk_description(const char *path) {
152 struct udev *udev = NULL;
153 struct udev_device *device = NULL;
155 char *description = NULL;
160 if (stat(path, &st) < 0)
163 if (!S_ISBLK(st.st_mode))
166 if (!(udev = udev_new()))
169 if (!(device = udev_device_new_from_devnum(udev, 'b', st.st_rdev)))
172 if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) ||
173 (model = udev_device_get_property_value(device, "ID_MODEL")) ||
174 (model = udev_device_get_property_value(device, "DM_NAME")))
175 description = strdup(model);
179 udev_device_unref(device);
187 static char *disk_mount_point(const char *label) {
188 char *mp = NULL, *device = NULL;
192 /* Yeah, we don't support native systemd unit files here for now */
194 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
197 f = setmntent("/etc/fstab", "r");
201 while ((m = getmntent(f)))
202 if (path_equal(m->mnt_fsname, device)) {
203 mp = strdup(m->mnt_dir);
216 static int help(void) {
218 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
219 "%s detach VOLUME\n\n"
220 "Attaches or detaches an encrypted block device.\n",
221 program_invocation_short_name,
222 program_invocation_short_name);
227 int main(int argc, char *argv[]) {
228 int r = EXIT_FAILURE;
229 struct crypt_device *cd = NULL;
230 char **passwords = NULL, *truncated_cipher = NULL;
231 const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
232 char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
233 unsigned keyfile_size = 0;
241 log_error("This program requires at least two arguments.");
245 log_set_target(LOG_TARGET_AUTO);
246 log_parse_environment();
251 if (streq(argv[1], "attach")) {
255 const char *key_file = NULL;
257 crypt_status_info status;
259 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
262 log_error("attach requires at least two arguments.");
268 !streq(argv[4], "-") &&
269 !streq(argv[4], "none")) {
271 if (!path_is_absolute(argv[4]))
272 log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
277 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-"))
278 parse_options(argv[5]);
280 /* A delicious drop of snake oil */
281 mlockall(MCL_FUTURE);
283 description = disk_description(argv[3]);
284 mount_point = disk_mount_point(argv[2]);
286 if (description && streq(argv[2], description)) {
287 /* If the description string is simply the
288 * volume name, then let's not show this
294 if (mount_point && description)
295 asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
296 else if (mount_point)
297 asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
298 else if (description)
299 asprintf(&name_buffer, "%s (%s)", description, argv[2]);
301 name = name_buffer ? name_buffer : argv[2];
303 if ((k = crypt_init(&cd, argv[3]))) {
304 log_error("crypt_init() failed: %s", strerror(-k));
308 crypt_set_log_callback(cd, log_glue, NULL);
310 status = crypt_status(cd, argv[2]);
311 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
312 log_info("Volume %s already active.", argv[2]);
318 flags |= CRYPT_ACTIVATE_READONLY;
321 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
324 until = now(CLOCK_MONOTONIC) + opt_timeout;
328 opt_tries = opt_tries > 0 ? opt_tries : 3;
329 opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
330 hash = opt_hash ? opt_hash : "ripemd160";
335 l = strcspn(opt_cipher, "-");
337 if (!(truncated_cipher = strndup(opt_cipher, l))) {
338 log_error("Out of memory");
342 cipher = truncated_cipher;
343 cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
346 cipher_mode = "cbc-essiv:sha256";
349 for (try = 0; try < opt_tries; try++) {
350 bool pass_volume_key = false;
352 strv_free(passwords);
359 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
360 log_error("Out of memory");
364 k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
368 log_error("Failed to query password: %s", strerror(-k));
373 char **passwords2 = NULL;
375 assert(strv_length(passwords) == 1);
377 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
378 log_error("Out of memory");
382 k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
386 log_error("Failed to query verification password: %s", strerror(-k));
390 assert(strv_length(passwords2) == 1);
392 if (!streq(passwords[0], passwords2[0])) {
393 log_warning("Passwords did not match, retrying.");
394 strv_free(passwords2);
398 strv_free(passwords2);
401 strv_uniq(passwords);
403 STRV_FOREACH(p, passwords) {
406 if (strlen(*p)+1 >= opt_key_size)
409 /* Pad password if necessary */
410 if (!(c = new(char, opt_key_size))) {
411 log_error("Out of memory.");
415 strncpy(c, *p, opt_key_size);
423 if (!opt_type || streq(opt_type, CRYPT_LUKS1))
424 k = crypt_load(cd, CRYPT_LUKS1, NULL);
426 if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
427 struct crypt_params_plain params;
432 /* In contrast to what the name
433 * crypt_setup() might suggest this
434 * doesn't actually format anything,
435 * it just configures encryption
436 * parameters when used for plain
438 k = crypt_format(cd, CRYPT_PLAIN,
446 pass_volume_key = streq(hash, "plain");
448 /* for CRYPT_PLAIN limit reads
449 * from keyfile to key length */
450 keyfile_size = opt_key_size / 8;
454 log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
458 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
459 crypt_get_cipher(cd),
460 crypt_get_cipher_mode(cd),
461 crypt_get_volume_key_size(cd)*8,
465 k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size, flags);
469 STRV_FOREACH(p, passwords) {
472 k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
474 k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
485 log_error("Failed to activate: %s", strerror(-k));
489 log_warning("Invalid passphrase.");
492 if (try >= opt_tries) {
493 log_error("Too many attempts.");
498 } else if (streq(argv[1], "detach")) {
501 if ((k = crypt_init_by_name(&cd, argv[2]))) {
502 log_error("crypt_init() failed: %s", strerror(-k));
506 crypt_set_log_callback(cd, log_glue, NULL);
508 if ((k = crypt_deactivate(cd, argv[2])) < 0) {
509 log_error("Failed to deactivate: %s", strerror(-k));
514 log_error("Unknown verb %s.", argv[1]);
528 free(truncated_cipher);
530 strv_free(passwords);