]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/cryptsetup/cryptsetup.c
Split out pretty-print.c and move pager.c and main-func.h to shared/
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup.c
index ab4d24ca3bc5bc50782c5a98b59f79bf5299e82c..8afff739907fdff6ed1924554619e378199b4403 100644 (file)
@@ -1,22 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
 
 #include <errno.h>
 #include <mntent.h>
 #include "escape.h"
 #include "fileio.h"
 #include "log.h"
+#include "main-func.h"
 #include "mount-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "pretty-print.h"
 #include "util.h"
 
 /* internal helper */
 #define ANY_LUKS "LUKS"
+/* as in src/cryptsetup.h */
+#define CRYPT_SECTOR_SIZE 512
+#define CRYPT_MAX_SECTOR_SIZE 4096
 
 static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
 static char *arg_cipher = NULL;
 static unsigned arg_key_size = 0;
+#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
+static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
+#endif
 static int arg_key_slot = CRYPT_ANY_SLOT;
 static unsigned arg_keyfile_size = 0;
-static unsigned arg_keyfile_offset = 0;
+static uint64_t arg_keyfile_offset = 0;
 static char *arg_hash = NULL;
 static char *arg_header = NULL;
 static unsigned arg_tries = 3;
@@ -64,6 +54,11 @@ static uint64_t arg_offset = 0;
 static uint64_t arg_skip = 0;
 static usec_t arg_timeout = USEC_INFINITY;
 
+STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_header, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_tcrypt_keyfiles, strv_freep);
+
 /* Options Debian's crypttab knows we don't:
 
     precheck=
@@ -104,6 +99,29 @@ static int parse_one_option(const char *option) {
 
                 arg_key_size /= 8;
 
+        } else if ((val = startswith(option, "sector-size="))) {
+
+#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
+                r = safe_atou(val, &arg_sector_size);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
+                        return 0;
+                }
+
+                if (arg_sector_size % 2) {
+                        log_error("sector-size= not a multiple of 2, ignoring.");
+                        return 0;
+                }
+
+                if (arg_sector_size < CRYPT_SECTOR_SIZE || arg_sector_size > CRYPT_MAX_SECTOR_SIZE) {
+                        log_error("sector-size= is outside of %u and %u, ignoring.", CRYPT_SECTOR_SIZE, CRYPT_MAX_SECTOR_SIZE);
+                        return 0;
+                }
+#else
+                log_error("sector-size= is not supported, compiled with old libcryptsetup.");
+                return 0;
+#endif
+
         } else if ((val = startswith(option, "key-slot="))) {
 
                 arg_type = ANY_LUKS;
@@ -131,13 +149,22 @@ static int parse_one_option(const char *option) {
                 }
 
         } else if ((val = startswith(option, "keyfile-offset="))) {
+                uint64_t off;
 
-                r = safe_atou(val, &arg_keyfile_offset);
+                r = safe_atou64(val, &off);
                 if (r < 0) {
                         log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
                         return 0;
                 }
 
+                if ((size_t) off != off) {
+                        /* https://gitlab.com/cryptsetup/cryptsetup/issues/359 */
+                        log_error("keyfile-offset= value would truncated to %zu, ignoring.", (size_t) off);
+                        return 0;
+                }
+
+                arg_keyfile_offset = off;
+
         } else if ((val = startswith(option, "hash="))) {
                 r = free_and_strdup(&arg_hash, val);
                 if (r < 0)
@@ -249,25 +276,7 @@ static int parse_options(const char *options) {
         return 0;
 }
 
-static int disk_major_minor(const char *path, char **ret) {
-        struct stat st;
-
-        assert(path);
-
-        if (stat(path, &st) < 0)
-                return -errno;
-
-        if (!S_ISBLK(st.st_mode))
-                return -EINVAL;
-
-        if (asprintf(ret, "/dev/block/%d:%d", major(st.st_rdev), minor(st.st_rdev)) < 0)
-                return -errno;
-
-        return 0;
-}
-
 static char* disk_description(const char *path) {
-
         static const char name_fields[] =
                 "ID_PART_ENTRY_NAME\0"
                 "DM_NAME\0"
@@ -275,9 +284,8 @@ static char* disk_description(const char *path) {
                 "ID_MODEL\0";
 
         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+        const char *i, *name;
         struct stat st;
-        const char *i;
-        int r;
 
         assert(path);
 
@@ -287,17 +295,13 @@ static char* disk_description(const char *path) {
         if (!S_ISBLK(st.st_mode))
                 return NULL;
 
-        r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
-        if (r < 0)
+        if (sd_device_new_from_devnum(&device, 'b', st.st_rdev) < 0)
                 return NULL;
 
-        NULSTR_FOREACH(i, name_fields) {
-                const char *name;
-
-                r = sd_device_get_property_value(device, i, &name);
-                if (r >= 0 && !isempty(name))
+        NULSTR_FOREACH(i, name_fields)
+                if (sd_device_get_property_value(device, i, &name) >= 0 &&
+                    !isempty(name))
                         return strdup(name);
-        }
 
         return NULL;
 }
@@ -324,7 +328,7 @@ static char *disk_mount_point(const char *label) {
 }
 
 static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) {
-        _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
+        _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *text = NULL, *disk_path = NULL;
         _cleanup_strv_free_erase_ char **passwords = NULL;
         const char *name = NULL;
         char **p, *id;
@@ -337,6 +341,10 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
         description = disk_description(src);
         mount_point = disk_mount_point(vol);
 
+        disk_path = cescape(src);
+        if (!disk_path)
+                return log_oom();
+
         if (description && streq(vol, description))
                 /* If the description string is simply the
                  * volume name, then let's not show this
@@ -355,22 +363,10 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
 
         name = name_buffer ? name_buffer : vol;
 
-        if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
+        if (asprintf(&text, "Please enter passphrase for disk %s:", name) < 0)
                 return log_oom();
 
-        if (src)
-                (void) disk_major_minor(src, &maj_min);
-
-        if (maj_min) {
-                escaped_name = maj_min;
-                maj_min = NULL;
-        } else
-                escaped_name = cescape(name);
-
-        if (!escaped_name)
-                return log_oom();
-
-        id = strjoina("cryptsetup:", escaped_name);
+        id = strjoina("cryptsetup:", disk_path);
 
         r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
                               ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
@@ -383,10 +379,10 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
 
                 assert(strv_length(passwords) == 1);
 
-                if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
+                if (asprintf(&text, "Please enter passphrase for disk %s (verification):", name) < 0)
                         return log_oom();
 
-                id = strjoina("cryptsetup-verification:", escaped_name);
+                id = strjoina("cryptsetup-verification:", disk_path);
 
                 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
                 if (r < 0)
@@ -418,8 +414,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
                 *p = c;
         }
 
-        *ret = passwords;
-        passwords = NULL;
+        *ret = TAKE_PTR(passwords);
 
         return 0;
 }
@@ -506,6 +501,9 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                 struct crypt_params_plain params = {
                         .offset = arg_offset,
                         .skip = arg_skip,
+#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
+                        .sector_size = arg_sector_size,
+#endif
                 };
                 const char *cipher, *cipher_mode;
                 _cleanup_free_ char *truncated_cipher = NULL;
@@ -584,33 +582,38 @@ static int attach_luks_or_plain(struct crypt_device *cd,
 }
 
 static int help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("systemd-cryptsetup@.service", "8", &link);
+        if (r < 0)
+                return log_oom();
 
         printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
                "%s detach VOLUME\n\n"
-               "Attaches or detaches an encrypted block device.\n",
-               program_invocation_short_name,
-               program_invocation_short_name);
+               "Attaches or detaches an encrypted block device.\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , program_invocation_short_name
+               , link
+        );
 
         return 0;
 }
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
         _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
-        int r = -EINVAL;
+        int r;
 
-        if (argc <= 1) {
-                r = help();
-                goto finish;
-        }
+        if (argc <= 1)
+                return help();
 
         if (argc < 3) {
                 log_error("This program requires at least two arguments.");
-                goto finish;
+                return -EINVAL;
         }
 
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
+        log_setup_service();
 
         umask(0022);
 
@@ -625,7 +628,7 @@ int main(int argc, char *argv[]) {
 
                 if (argc < 4) {
                         log_error("attach requires at least two arguments.");
-                        goto finish;
+                        return -EINVAL;
                 }
 
                 if (argc >= 5 &&
@@ -640,8 +643,9 @@ int main(int argc, char *argv[]) {
                 }
 
                 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
-                        if (parse_options(argv[5]) < 0)
-                                goto finish;
+                        r = parse_options(argv[5]);
+                        if (r < 0)
+                                return r;
                 }
 
                 /* A delicious drop of snake oil */
@@ -652,18 +656,15 @@ int main(int argc, char *argv[]) {
                         r = crypt_init(&cd, arg_header);
                 } else
                         r = crypt_init(&cd, argv[3]);
-                if (r < 0) {
-                        log_error_errno(r, "crypt_init() failed: %m");
-                        goto finish;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "crypt_init() failed: %m");
 
                 crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
 
                 status = crypt_status(cd, argv[2]);
                 if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
                         log_info("Volume %s already active.", argv[2]);
-                        r = 0;
-                        goto finish;
+                        return 0;
                 }
 
                 if (arg_readonly)
@@ -696,7 +697,7 @@ int main(int argc, char *argv[]) {
                                 if (r == -EAGAIN)
                                         continue;
                                 if (r < 0)
-                                        goto finish;
+                                        return r;
                         }
 
                         if (streq_ptr(arg_type, CRYPT_TCRYPT))
@@ -714,18 +715,15 @@ int main(int argc, char *argv[]) {
                                 key_file = NULL;
                                 continue;
                         }
-                        if (r != -EPERM) {
-                                log_error_errno(r, "Failed to activate: %m");
-                                goto finish;
-                        }
+                        if (r != -EPERM)
+                                return log_error_errno(r, "Failed to activate: %m");
 
                         log_warning("Invalid passphrase.");
                 }
 
                 if (arg_tries != 0 && tries >= arg_tries) {
                         log_error("Too many attempts; giving up.");
-                        r = -EPERM;
-                        goto finish;
+                        return -EPERM;
                 }
 
         } else if (streq(argv[1], "detach")) {
@@ -733,34 +731,23 @@ int main(int argc, char *argv[]) {
                 r = crypt_init_by_name(&cd, argv[2]);
                 if (r == -ENODEV) {
                         log_info("Volume %s already inactive.", argv[2]);
-                        r = 0;
-                        goto finish;
-                }
-                if (r < 0) {
-                        log_error_errno(r, "crypt_init_by_name() failed: %m");
-                        goto finish;
+                        return 0;
                 }
+                if (r < 0)
+                        return log_error_errno(r, "crypt_init_by_name() failed: %m");
 
                 crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
 
                 r = crypt_deactivate(cd, argv[2]);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to deactivate: %m");
-                        goto finish;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to deactivate: %m");
 
         } else {
                 log_error("Unknown verb %s.", argv[1]);
-                goto finish;
+                return -EINVAL;
         }
 
-        r = 0;
-
-finish:
-        free(arg_cipher);
-        free(arg_hash);
-        free(arg_header);
-        strv_free(arg_tcrypt_keyfiles);
-
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);