From b7c1f1e13d646e0c6b3a353b6ba255d2e836dc56 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Mon, 18 Jan 2021 18:36:28 +0100 Subject: [PATCH] Revert libcryptsetup_cli. This reverts mostly these commits: 42692418c2b50638567b9456daa30e80fc9dfe78 a985c12659006d3cc8eb0999f431c1f8c06bb346 The library was ment to export common functions shared by all cryptsetup tools and planned LUKS2 tokens plugins. It is no longer needed. --- Makefile.am | 2 - configure.ac | 7 - lib/cli/Makemodule.am | 31 --- lib/cli/cli.c | 417 -------------------------------- lib/cli/cli_internal.h | 50 ---- lib/cli/libcryptsetup_cli.h | 63 ----- lib/cli/libcryptsetup_cli.pc.in | 10 - lib/cli/libcryptsetup_cli.sym | 10 - src/Makemodule.am | 16 +- src/cryptsetup.c | 31 +-- src/cryptsetup.h | 39 ++- src/cryptsetup_args.h | 1 - src/cryptsetup_reencrypt.c | 2 +- src/integritysetup.c | 6 +- src/utils_password.c | 318 ++++++++++++++++++++++-- src/veritysetup.c | 2 +- 16 files changed, 351 insertions(+), 654 deletions(-) delete mode 100644 lib/cli/Makemodule.am delete mode 100644 lib/cli/cli.c delete mode 100644 lib/cli/cli_internal.h delete mode 100644 lib/cli/libcryptsetup_cli.h delete mode 100644 lib/cli/libcryptsetup_cli.pc.in delete mode 100644 lib/cli/libcryptsetup_cli.sym diff --git a/Makefile.am b/Makefile.am index 43f81786..49dcda77 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,6 @@ DISTCLEAN_TARGETS = AM_CPPFLAGS = \ -include config.h \ -I$(top_srcdir)/lib \ - -I$(top_srcdir)/lib/cli \ -DDATADIR=\""$(datadir)"\" \ -DLOCALEDIR=\""$(datadir)/locale"\" \ -DLIBDIR=\""$(libdir)"\" \ @@ -37,7 +36,6 @@ include lib/crypto_backend/argon2/Makemodule.am endif include lib/crypto_backend/Makemodule.am include lib/Makemodule.am -include lib/cli/Makemodule.am include src/Makemodule.am diff --git a/configure.ac b/configure.ac index b7a46e6a..e988572e 100644 --- a/configure.ac +++ b/configure.ac @@ -5,9 +5,6 @@ dnl library version from ..[-] LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-) LIBCRYPTSETUP_VERSION_INFO=18:0:6 -LIBCRYPTSETUP_CLI_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-) -LIBCRYPTSETUP_CLI_VERSION_INFO=1:0:0 - AM_SILENT_RULES([yes]) AC_CONFIG_SRCDIR(src/cryptsetup.c) AC_CONFIG_MACRO_DIR([m4]) @@ -542,9 +539,6 @@ AC_SUBST([BLKID_LIBS]) AC_SUBST([LIBCRYPTSETUP_VERSION]) AC_SUBST([LIBCRYPTSETUP_VERSION_INFO]) -AC_SUBST([LIBCRYPTSETUP_CLI_VERSION]) -AC_SUBST([LIBCRYPTSETUP_CLI_VERSION_INFO]) - dnl ========================================================================== AC_ARG_ENABLE([dev-random], AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)])) @@ -654,7 +648,6 @@ dnl ========================================================================== AC_CONFIG_FILES([ Makefile lib/libcryptsetup.pc -lib/cli/libcryptsetup_cli.pc po/Makefile.in scripts/cryptsetup.conf tests/Makefile diff --git a/lib/cli/Makemodule.am b/lib/cli/Makemodule.am deleted file mode 100644 index 1c52a985..00000000 --- a/lib/cli/Makemodule.am +++ /dev/null @@ -1,31 +0,0 @@ -pkgconfig_DATA += lib/cli/libcryptsetup_cli.pc - -lib_LTLIBRARIES += libcryptsetup_cli.la - -include_HEADERS += lib/cli/libcryptsetup_cli.h - -EXTRA_DIST += lib/cli/libcryptsetup_cli.pc.in lib/cli/libcryptsetup_cli.sym - -# libcryptsetup_cli_la_CPPFLAGS = $(AM_CPPFLAGS) - -libcryptsetup_cli_la_DEPENDENCIES = lib/cli/libcryptsetup_cli.sym libcryptsetup.la - -libcryptsetup_cli_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ - -Wl,--version-script=$(top_srcdir)/lib/cli/libcryptsetup_cli.sym \ - -version-info @LIBCRYPTSETUP_CLI_VERSION_INFO@ - -libcryptsetup_cli_la_CFLAGS = $(AM_CFLAGS) \ - -I $(top_srcdir)/src - -libcryptsetup_cli_la_LIBADD = \ - $(LTLIBICONV) \ - @PWQUALITY_LIBS@ \ - @PASSWDQC_LIBS@ \ - libcryptsetup.la - -libcryptsetup_cli_la_SOURCES = \ - lib/utils_loop.c \ - lib/utils_io.c \ - lib/cli/cli.c \ - lib/cli/libcryptsetup_cli.h \ - lib/cli/cli_internal.h diff --git a/lib/cli/cli.c b/lib/cli/cli.c deleted file mode 100644 index 466dfda6..00000000 --- a/lib/cli/cli.c +++ /dev/null @@ -1,417 +0,0 @@ -/* - * libcryptsetup_cli - cryptsetup command line tools library - * - * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. - * Copyright (C) 2012-2020 Milan Broz - * Copyright (C) 2020 Ondrej Kozina - * - * This file 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. - * - * This file 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 this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nls.h" -#include "utils_loop.h" -#include "utils_io.h" -#include "libcryptsetup.h" -#include "libcryptsetup_cli.h" -#include "cli_internal.h" - -/* Password reading helpers */ -static int untimed_read(int fd, char *pass, size_t maxlen) -{ - ssize_t i; - - i = read(fd, pass, maxlen); - if (i > 0) { - pass[i-1] = '\0'; - i = 0; - } else if (i == 0) { /* EOF */ - *pass = 0; - i = -1; - } - return i; -} - -static int timed_read(int fd, char *pass, size_t maxlen, long timeout) -{ - struct timeval t; - fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */ - int failed = -1; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - t.tv_sec = timeout; - t.tv_usec = 0; - - if (select(fd+1, &fds, NULL, NULL, &t) > 0) - failed = untimed_read(fd, pass, maxlen); - - return failed; -} - -#if defined ENABLE_PWQUALITY -#include - -static int tools_check_pwquality(struct crypt_device *cd, const char *password) -{ - int r; - void *auxerror; - pwquality_settings_t *pwq; - - crypt_logf(cd, CRYPT_LOG_DEBUG, "Checking new password using default pwquality settings."); - pwq = pwquality_default_settings(); - if (!pwq) - return -EINVAL; - - r = pwquality_read_config(pwq, NULL, &auxerror); - if (r) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Cannot check password quality: %s"), - pwquality_strerror(NULL, 0, r, auxerror)); - pwquality_free_settings(pwq); - return -EINVAL; - } - - r = pwquality_check(pwq, password, NULL, NULL, &auxerror); - if (r < 0) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Password quality check failed:\n %s"), - pwquality_strerror(NULL, 0, r, auxerror)); - r = -EPERM; - } else { - crypt_logf(cd, CRYPT_LOG_DEBUG, "New password libpwquality score is %d.", r); - r = 0; - } - - pwquality_free_settings(pwq); - return r; -} -#elif defined ENABLE_PASSWDQC -#include - -static int tools_check_pwquality(struct crypt_device *cd, const char *password) -{ - passwdqc_params_t params; - char *parse_reason; - const char *check_reason; - const char *config = PASSWDQC_CONFIG_FILE; - - passwdqc_params_reset(¶ms); - - if (*config && passwdqc_params_load(¶ms, &parse_reason, config)) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Cannot check password quality: %s"), - (parse_reason ? parse_reason : "Out of memory")); - free(parse_reason); - return -EINVAL; - } - - check_reason = passwdqc_check(¶ms.qc, password, NULL, NULL); - if (check_reason) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Password quality check failed: Bad passphrase (%s)"), - check_reason); - return -EPERM; - } - - return 0; -} -#else /* !(ENABLE_PWQUALITY || ENABLE_PASSWDQC) */ -static int tools_check_pwquality(struct crypt_device *cd, const char *password) -{ - return 0; -} -#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */ - -static int interactive_pass(const char *prompt, char *pass, size_t maxlen, - long timeout) -{ - struct termios orig, tmp; - int failed = -1; - int infd, outfd; - - if (maxlen < 1) - return failed; - - /* Read and write to /dev/tty if available */ - infd = open("/dev/tty", O_RDWR); - if (infd == -1) { - infd = STDIN_FILENO; - outfd = STDERR_FILENO; - } else - outfd = infd; - - if (tcgetattr(infd, &orig)) - goto out_err; - - memcpy(&tmp, &orig, sizeof(tmp)); - tmp.c_lflag &= ~ECHO; - - if (prompt && write(outfd, prompt, strlen(prompt)) < 0) - goto out_err; - - tcsetattr(infd, TCSAFLUSH, &tmp); - if (timeout) - failed = timed_read(infd, pass, maxlen, timeout); - else - failed = untimed_read(infd, pass, maxlen); - tcsetattr(infd, TCSAFLUSH, &orig); - -out_err: - if (!failed && write(outfd, "\n", 1)) {}; - - if (infd != STDIN_FILENO) - close(infd); - return failed; -} - -static int crypt_get_key_tty(const char *prompt, - char **key, size_t *key_size, - int timeout, int verify, - struct crypt_device *cd) -{ - int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX; - int r = -EINVAL; - char *pass = NULL, *pass_verify = NULL; - - *key = NULL; - *key_size = 0; - - crypt_logf(cd, CRYPT_LOG_DEBUG, "Interactive passphrase entry requested."); - - pass = crypt_safe_alloc(key_size_max + 1); - if (!pass) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Out of memory while reading passphrase.")); - return -ENOMEM; - } - - if (interactive_pass(prompt, pass, key_size_max, timeout)) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Error reading passphrase from terminal.")); - goto out_err; - } - pass[key_size_max] = '\0'; - - if (verify) { - pass_verify = crypt_safe_alloc(key_size_max); - if (!pass_verify) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Out of memory while reading passphrase.")); - r = -ENOMEM; - goto out_err; - } - - if (interactive_pass(_("Verify passphrase: "), - pass_verify, key_size_max, timeout)) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Error reading passphrase from terminal.")); - goto out_err; - } - - if (strncmp(pass, pass_verify, key_size_max)) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Passphrases do not match.")); - r = -EPERM; - goto out_err; - } - } - - *key = pass; - *key_size = strlen(pass); - r = 0; -out_err: - crypt_safe_free(pass_verify); - if (r) - crypt_safe_free(pass); - return r; -} - -static int tools_is_stdin(const char *key_file) -{ - if (!key_file) - return 1; - - return strcmp(key_file, "-") ? 0 : 1; -} - -/* - * Note: --key-file=- is interpreted as a read from a binary file (stdin) - * key_size_max == 0 means detect maximum according to input type (tty/file) - */ -int crypt_cli_get_key(const char *prompt, - char **key, size_t *key_size, - uint64_t keyfile_offset, size_t keyfile_size_max, - const char *key_file, - int timeout, int verify, int pwquality, - struct crypt_device *cd, struct crypt_cli *ctx __attribute__((unused))) -{ - char tmp[PATH_MAX], *backing_file; - int r = -EINVAL; - - if (tools_is_stdin(key_file)) { - if (isatty(STDIN_FILENO)) { - if (keyfile_offset) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Cannot use offset with terminal input.")); - } else { - if (!prompt && !crypt_get_device_name(cd)) - snprintf(tmp, sizeof(tmp), _("Enter passphrase: ")); - else if (!prompt) { - backing_file = crypt_loop_backing_file(crypt_get_device_name(cd)); - snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd)); - free(backing_file); - } - r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify, cd); - } - } else { - crypt_logf(cd, CRYPT_LOG_DEBUG, "STDIN descriptor passphrase entry requested."); - /* No keyfile means STDIN with EOL handling (\n will end input)). */ - r = crypt_keyfile_device_read(cd, NULL, key, key_size, - keyfile_offset, keyfile_size_max, - key_file ? 0 : CRYPT_KEYFILE_STOP_EOL); - } - } else { - crypt_logf(cd, CRYPT_LOG_DEBUG, "File descriptor passphrase entry requested."); - r = crypt_keyfile_device_read(cd, key_file, key, key_size, - keyfile_offset, keyfile_size_max, 0); - } - - /* Check pwquality for password (not keyfile) */ - if (pwquality && !key_file && !r) - r = tools_check_pwquality(cd, *key); - - return r; -} - -int crypt_cli_read_mk(struct crypt_device *cd, const char *file, char **key, size_t keysize) -{ - int fd; - ssize_t ret; - - if (!keysize || !key) - return -EINVAL; - - *key = crypt_safe_alloc(keysize); - if (!*key) - return -ENOMEM; - - fd = open(file, O_RDONLY); - if (fd == -1) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Cannot read keyfile %s."), file); - goto fail; - } - - ret = read_buffer(fd, *key, keysize); - if (ret < 0 || (size_t)ret != keysize) { - crypt_logf(cd, CRYPT_LOG_ERROR, _("Cannot read %d bytes from keyfile %s."), keysize, file); - close(fd); - goto fail; - } - close(fd); - return 0; -fail: - crypt_safe_free(*key); - *key = NULL; - return -EINVAL; -} - -static const struct tools_arg *find_arg_in_args(const char *name, const struct tools_arg *args, size_t args_len) -{ - size_t i; - - if (!args || !args_len) - return NULL; - - for (i = 0; i < args_len; i++) { - if (args[i].name && !strcmp(name, args[i].name)) - return args + i; - } - - return NULL; -} - -static const struct tools_arg *find_arg_by_name(struct crypt_cli *ctx, const char *name) -{ - return find_arg_in_args(name, ctx->core_args, ctx->core_args_count); -} - -int crypt_cli_arg_value(struct crypt_cli *ctx, const char *name, void *value) -{ - const struct tools_arg *arg; - - if (!name || !ctx || !value) - return -EINVAL; - - arg = find_arg_by_name(ctx, name); - if (!arg) - return -ENOENT; - - switch (arg->type) { - case CRYPT_ARG_BOOL: - *((bool *)value) = arg->set; - break; - case CRYPT_ARG_STRING: - *((char **)value) = arg->u.str_value; - break; - case CRYPT_ARG_INT32: - *((int32_t *)value) = arg->u.i32_value; - break; - case CRYPT_ARG_UINT32: - *((uint32_t *)value) = arg->u.u32_value; - break; - case CRYPT_ARG_INT64: - *((int64_t *)value) = arg->u.i64_value; - break; - case CRYPT_ARG_UINT64: - *((uint64_t *)value) = arg->u.u64_value; - break; - default: - return -EINVAL; - } - - return 0; -} - -int crypt_cli_arg_type(struct crypt_cli *ctx, const char *name, crypt_arg_type_info *type) -{ - const struct tools_arg *arg; - - if (!name || !type || !ctx) - return -EINVAL; - - arg = find_arg_by_name(ctx, name); - if (!arg) - return -ENOENT; - - *type = arg->type; - - return 0; -} - -bool crypt_cli_arg_set(struct crypt_cli *ctx, const char *name) -{ - const struct tools_arg *arg; - - if (!name || !ctx) - return false; - - arg = find_arg_by_name(ctx, name); - if (!arg) - return false; - - return arg->set; -} diff --git a/lib/cli/cli_internal.h b/lib/cli/cli_internal.h deleted file mode 100644 index 38be83c8..00000000 --- a/lib/cli/cli_internal.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * libcryptsetup_cli - cryptsetup command line tools library - * - * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. - * Copyright (C) 2012-2020 Milan Broz - * Copyright (C) 2020 Ondrej Kozina - * - * This file 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. - * - * This file 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 this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef CLI_INTERNAL_H -#define CLI_INTERNAL_H - -#include -#include - -#define MAX_ACTIONS 16 - -struct tools_arg { - const char *name; - bool set; - crypt_arg_type_info type; - union { - char *str_value; - uint64_t u64_value; - uint32_t u32_value; - int32_t i32_value; - int64_t i64_value; - } u; - const char *actions_array[MAX_ACTIONS]; -}; - -struct crypt_cli { - const struct tools_arg *core_args; - size_t core_args_count; -}; - -#endif diff --git a/lib/cli/libcryptsetup_cli.h b/lib/cli/libcryptsetup_cli.h deleted file mode 100644 index fd2b67d4..00000000 --- a/lib/cli/libcryptsetup_cli.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * libcryptsetup_cli - cryptsetup command line tools library - * - * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. - * Copyright (C) 2012-2020 Milan Broz - * Copyright (C) 2020 Ondrej Kozina - * - * This file 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. - * - * This file 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 this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _LIBCRYPTSETUP_CLI_H -#define _LIBCRYPTSETUP_CLI_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -struct crypt_cli; -struct crypt_device; - -typedef enum { - CRYPT_ARG_BOOL = 0, - CRYPT_ARG_STRING, - CRYPT_ARG_INT32, - CRYPT_ARG_UINT32, - CRYPT_ARG_INT64, - CRYPT_ARG_UINT64 -} crypt_arg_type_info; - -int crypt_cli_get_key(const char *prompt, - char **key, size_t *key_size, - uint64_t keyfile_offset, size_t keyfile_size_max, - const char *key_file, - int timeout, int verify, int pwquality, - struct crypt_device *cd, struct crypt_cli *ctx); - -int crypt_cli_read_mk(struct crypt_device *cd, const char *file, char **key, size_t keysize); - -bool crypt_cli_arg_set(struct crypt_cli *ctx, const char *name); - -int crypt_cli_arg_value(struct crypt_cli *ctx, const char *name, void *value); - -int crypt_cli_arg_type(struct crypt_cli *ctx, const char *name, crypt_arg_type_info *type); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/cli/libcryptsetup_cli.pc.in b/lib/cli/libcryptsetup_cli.pc.in deleted file mode 100644 index a6b5b1fa..00000000 --- a/lib/cli/libcryptsetup_cli.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libclidir=@libdir@ -includedir=@includedir@ - -Name: cryptsetup-cli -Description: cryptsetup cli library -Version: @LIBCRYPTSETUP_VERSION@ -Cflags: -I${includedir} -Libs: -L${libdir} -lcryptsetup_cli diff --git a/lib/cli/libcryptsetup_cli.sym b/lib/cli/libcryptsetup_cli.sym deleted file mode 100644 index d3992017..00000000 --- a/lib/cli/libcryptsetup_cli.sym +++ /dev/null @@ -1,10 +0,0 @@ -CRYPTSETUP_CLI_1.0 { - global: - crypt_cli_get_key; - crypt_cli_read_mk; - crypt_cli_arg_set; - crypt_cli_arg_type; - crypt_cli_arg_value; - local: - *; -}; diff --git a/src/Makemodule.am b/src/Makemodule.am index beb136f0..a6dc50cf 100644 --- a/src/Makemodule.am +++ b/src/Makemodule.am @@ -1,9 +1,6 @@ # cryptsetup if CRYPTSETUP -# cryptsetup_CPPFLAGS = $(AM_CPPFLAGS) \ -# -I $(top_srcdir)/lib/cli - cryptsetup_SOURCES = \ lib/utils_crypt.c \ lib/utils_loop.c \ @@ -23,8 +20,9 @@ cryptsetup_SOURCES = \ cryptsetup_LDADD = $(LDADD) \ libcryptsetup.la \ - libcryptsetup_cli.la \ @POPT_LIBS@ \ + @PWQUALITY_LIBS@ \ + @PASSWDQC_LIBS@ \ @UUID_LIBS@ \ @BLKID_LIBS@ @@ -62,8 +60,9 @@ veritysetup_SOURCES = \ veritysetup_LDADD = $(LDADD) \ libcryptsetup.la \ - libcryptsetup_cli.la \ @POPT_LIBS@ \ + @PWQUALITY_LIBS@ \ + @PASSWDQC_LIBS@ \ @BLKID_LIBS@ sbin_PROGRAMS += veritysetup @@ -92,6 +91,7 @@ integritysetup_SOURCES = \ src/utils_arg_names.h \ src/utils_arg_macros.h \ src/utils_tools.c \ + src/utils_password.c \ src/utils_blockdev.c \ src/integritysetup.c \ src/integritysetup_args.h \ @@ -100,8 +100,9 @@ integritysetup_SOURCES = \ integritysetup_LDADD = $(LDADD) \ libcryptsetup.la \ - libcryptsetup_cli.la \ @POPT_LIBS@ \ + @PWQUALITY_LIBS@ \ + @PASSWDQC_LIBS@ \ @UUID_LIBS@ \ @BLKID_LIBS@ @@ -136,8 +137,9 @@ cryptsetup_reencrypt_SOURCES = \ cryptsetup_reencrypt_LDADD = $(LDADD) \ libcryptsetup.la \ - libcryptsetup_cli.la \ @POPT_LIBS@ \ + @PWQUALITY_LIBS@ \ + @PASSWDQC_LIBS@ \ @UUID_LIBS@ \ @BLKID_LIBS@ diff --git a/src/cryptsetup.c b/src/cryptsetup.c index a0f8898a..105cf577 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -167,25 +167,6 @@ static int _set_tries_tty(void) return (tools_is_stdin(ARG_STR(OPT_KEY_FILE_ID)) && isatty(STDIN_FILENO)) ? ARG_UINT32(OPT_TRIES_ID) : 1; } -static int tools_write_mk(const char *file, const char *key, int keysize) -{ - int fd, r = -EINVAL; - - fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR); - if (fd < 0) { - log_err(_("Cannot open keyfile %s for write."), file); - return r; - } - - if (write_buffer(fd, key, keysize) == keysize) - r = 0; - else - log_err(_("Cannot write to keyfile %s."), file); - - close(fd); - return r; -} - static int action_open_plain(void) { struct crypt_device *cd = NULL, *cd1 = NULL; @@ -515,7 +496,7 @@ static int action_open_bitlk(void) } else if (!keysize) keysize = ARG_UINT32(OPT_KEY_SIZE_ID) / 8; - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); if (r < 0) goto out; r = crypt_activate_by_volume_key(cd, activated_name, @@ -1411,7 +1392,7 @@ static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_ goto out; if (ARG_SET(OPT_MASTER_KEY_FILE_ID)) { - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); if (r < 0) goto out; } @@ -1520,7 +1501,7 @@ static int action_open_luks(void) } else if (!keysize) keysize = ARG_UINT32(OPT_KEY_SIZE_ID) / 8; - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); if (r < 0) goto out; r = crypt_activate_by_volume_key(cd, activated_name, @@ -1764,7 +1745,7 @@ static int luksAddUnboundKey(void) } if (ARG_SET(OPT_MASTER_KEY_FILE_ID)) { - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); if (r < 0) goto out; @@ -1836,7 +1817,7 @@ static int action_luksAddKey(void) } else if (!keysize) keysize = ARG_UINT32(OPT_KEY_SIZE_ID) / 8; - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, keysize); if (r < 0) goto out; @@ -3258,7 +3239,7 @@ static int action_reencrypt_luks2(struct crypt_device *cd) goto err; if (ARG_SET(OPT_MASTER_KEY_FILE_ID)) { - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &vk, key_size); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &vk, key_size); if (r < 0) goto err; } diff --git a/src/cryptsetup.h b/src/cryptsetup.h index 65f6d0dc..44d5aebe 100644 --- a/src/cryptsetup.h +++ b/src/cryptsetup.h @@ -48,8 +48,6 @@ #include "lib/utils_blkid.h" #include "libcryptsetup.h" -#include "libcryptsetup_cli.h" -#include "lib/cli/cli_internal.h" #define CONST_CAST(x) (x)(uintptr_t) #define DEFAULT_CIPHER(type) (DEFAULT_##type##_CIPHER "-" DEFAULT_##type##_MODE) @@ -109,6 +107,9 @@ struct tools_progress_params { int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr); int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr); +int tools_read_mk(const char *file, char **key, int keysize); +int tools_write_mk(const char *file, const char *key, int keysize); + int tools_read_json_file(struct crypt_device *cd, const char *file, char **json, size_t *json_size, bool batch_mode); int tools_write_json_file(struct crypt_device *cd, const char *file, const char *json); @@ -118,11 +119,6 @@ int tools_wipe_all_signatures(const char *path); int tools_lookup_crypt_device(struct crypt_device *cd, const char *type, const char *data_device_path, char *name, size_t name_length); -void tools_parse_arg_value(poptContext popt_context, crypt_arg_type_info type, struct tools_arg *arg, const char *popt_arg, int popt_val, bool(*needs_size_conv_fn)(unsigned arg_id)); - -void tools_args_free(struct tools_arg *args, size_t args_count); - -void tools_check_args(const char *action, const struct tools_arg *args, size_t args_size, poptContext popt_context); /* each utility is required to implement it */ void tools_cleanup(void); @@ -135,6 +131,35 @@ void tools_cleanup(void); #define log_verbose(x...) crypt_logf(NULL, CRYPT_LOG_VERBOSE, x) #define log_err(x...) crypt_logf(NULL, CRYPT_LOG_ERROR, x) +typedef enum { + CRYPT_ARG_BOOL = 0, + CRYPT_ARG_STRING, + CRYPT_ARG_INT32, + CRYPT_ARG_UINT32, + CRYPT_ARG_INT64, + CRYPT_ARG_UINT64 +} crypt_arg_type_info; + +struct tools_arg { + const char *name; + bool set; + crypt_arg_type_info type; + union { + char *str_value; + uint64_t u64_value; + uint32_t u32_value; + int32_t i32_value; + int64_t i64_value; + } u; + const char *actions_array[MAX_ACTIONS]; +}; + +void tools_parse_arg_value(poptContext popt_context, crypt_arg_type_info type, struct tools_arg *arg, const char *popt_arg, int popt_val, bool(*needs_size_conv_fn)(unsigned arg_id)); + +void tools_args_free(struct tools_arg *args, size_t args_count); + +void tools_check_args(const char *action, const struct tools_arg *args, size_t args_size, poptContext popt_context); + struct tools_log_params { bool verbose; bool debug; diff --git a/src/cryptsetup_args.h b/src/cryptsetup_args.h index 5056bc0e..03e84ed9 100644 --- a/src/cryptsetup_args.h +++ b/src/cryptsetup_args.h @@ -24,7 +24,6 @@ #include "utils_arg_names.h" #include "utils_arg_macros.h" -#include "lib/cli/cli_internal.h" #define BITLKDUMP_ACTION "bitlkDump" #define BENCHMARK_ACTION "benchmark" diff --git a/src/cryptsetup_reencrypt.c b/src/cryptsetup_reencrypt.c index 7fce6b23..5dfb26b6 100644 --- a/src/cryptsetup_reencrypt.c +++ b/src/cryptsetup_reencrypt.c @@ -717,7 +717,7 @@ static int backup_luks_headers(struct reenc_ctx *rc) rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen); } else if (ARG_SET(OPT_MASTER_KEY_FILE_ID)) { log_dbg("Loading new key from file."); - r = crypt_cli_read_mk(cd, ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, key_size); + r = tools_read_mk(ARG_STR(OPT_MASTER_KEY_FILE_ID), &key, key_size); } if (r < 0) diff --git a/src/integritysetup.c b/src/integritysetup.c index eb2ba7de..0e97f8b3 100644 --- a/src/integritysetup.c +++ b/src/integritysetup.c @@ -46,14 +46,14 @@ static int _read_keys(char **integrity_key, struct crypt_params_integrity *param int r; if (integrity_key && ARG_SET(OPT_INTEGRITY_KEY_FILE_ID)) { - r = crypt_cli_read_mk(NULL, ARG_STR(OPT_INTEGRITY_KEY_FILE_ID), &int_key, ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID)); + r = tools_read_mk(ARG_STR(OPT_INTEGRITY_KEY_FILE_ID), &int_key, ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID)); if (r < 0) return r; params->integrity_key_size = ARG_UINT32(OPT_INTEGRITY_KEY_SIZE_ID); } if (ARG_SET(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID)) { - r = crypt_cli_read_mk(NULL, ARG_STR(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID), &journal_integrity_key, ARG_UINT32(OPT_JOURNAL_INTEGRITY_KEY_SIZE_ID)); + r = tools_read_mk(ARG_STR(OPT_JOURNAL_INTEGRITY_KEY_FILE_ID), &journal_integrity_key, ARG_UINT32(OPT_JOURNAL_INTEGRITY_KEY_SIZE_ID)); if (r < 0) { crypt_safe_free(int_key); return r; @@ -63,7 +63,7 @@ static int _read_keys(char **integrity_key, struct crypt_params_integrity *param } if (ARG_SET(OPT_JOURNAL_CRYPT_KEY_FILE_ID)) { - r = crypt_cli_read_mk(NULL, ARG_STR(OPT_JOURNAL_CRYPT_KEY_FILE_ID), &journal_crypt_key, ARG_UINT32(OPT_JOURNAL_CRYPT_KEY_SIZE_ID)); + r = tools_read_mk(ARG_STR(OPT_JOURNAL_CRYPT_KEY_FILE_ID), &journal_crypt_key, ARG_UINT32(OPT_JOURNAL_CRYPT_KEY_SIZE_ID)); if (r < 0) { crypt_safe_free(int_key); crypt_safe_free(journal_integrity_key); diff --git a/src/utils_password.c b/src/utils_password.c index 826fbbe7..f58ed85e 100644 --- a/src/utils_password.c +++ b/src/utils_password.c @@ -20,6 +20,264 @@ */ #include "cryptsetup.h" +#include + +#if defined ENABLE_PWQUALITY +#include + +static int tools_check_pwquality(const char *password) +{ + int r; + void *auxerror; + pwquality_settings_t *pwq; + + log_dbg("Checking new password using default pwquality settings."); + pwq = pwquality_default_settings(); + if (!pwq) + return -EINVAL; + + r = pwquality_read_config(pwq, NULL, &auxerror); + if (r) { + log_err(_("Cannot check password quality: %s"), + pwquality_strerror(NULL, 0, r, auxerror)); + pwquality_free_settings(pwq); + return -EINVAL; + } + + r = pwquality_check(pwq, password, NULL, NULL, &auxerror); + if (r < 0) { + log_err(_("Password quality check failed:\n %s"), + pwquality_strerror(NULL, 0, r, auxerror)); + r = -EPERM; + } else { + log_dbg("New password libpwquality score is %d.", r); + r = 0; + } + + pwquality_free_settings(pwq); + return r; +} +#elif defined ENABLE_PASSWDQC +#include + +static int tools_check_pwquality(const char *password) +{ + passwdqc_params_t params; + char *parse_reason; + const char *check_reason; + const char *config = PASSWDQC_CONFIG_FILE; + + passwdqc_params_reset(¶ms); + + if (*config && passwdqc_params_load(¶ms, &parse_reason, config)) { + log_err(_("Cannot check password quality: %s"), + (parse_reason ? parse_reason : "Out of memory")); + free(parse_reason); + return -EINVAL; + } + + check_reason = passwdqc_check(¶ms.qc, password, NULL, NULL); + if (check_reason) { + log_err(_("Password quality check failed: Bad passphrase (%s)"), + check_reason); + return -EPERM; + } + + return 0; +} +#else /* !(ENABLE_PWQUALITY || ENABLE_PASSWDQC) */ +static int tools_check_pwquality(const char *password) +{ + return 0; +} +#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */ + +/* Password reading helpers */ +static int untimed_read(int fd, char *pass, size_t maxlen) +{ + ssize_t i; + + i = read(fd, pass, maxlen); + if (i > 0) { + pass[i-1] = '\0'; + i = 0; + } else if (i == 0) { /* EOF */ + *pass = 0; + i = -1; + } + return i; +} + +static int timed_read(int fd, char *pass, size_t maxlen, long timeout) +{ + struct timeval t; + fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */ + int failed = -1; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + t.tv_sec = timeout; + t.tv_usec = 0; + + if (select(fd+1, &fds, NULL, NULL, &t) > 0) + failed = untimed_read(fd, pass, maxlen); + + return failed; +} + +static int interactive_pass(const char *prompt, char *pass, size_t maxlen, + long timeout) +{ + struct termios orig, tmp; + int failed = -1; + int infd, outfd; + + if (maxlen < 1) + return failed; + + /* Read and write to /dev/tty if available */ + infd = open("/dev/tty", O_RDWR); + if (infd == -1) { + infd = STDIN_FILENO; + outfd = STDERR_FILENO; + } else + outfd = infd; + + if (tcgetattr(infd, &orig)) + goto out_err; + + memcpy(&tmp, &orig, sizeof(tmp)); + tmp.c_lflag &= ~ECHO; + + if (prompt && write(outfd, prompt, strlen(prompt)) < 0) + goto out_err; + + tcsetattr(infd, TCSAFLUSH, &tmp); + if (timeout) + failed = timed_read(infd, pass, maxlen, timeout); + else + failed = untimed_read(infd, pass, maxlen); + tcsetattr(infd, TCSAFLUSH, &orig); + +out_err: + if (!failed && write(outfd, "\n", 1)) {}; + + if (infd != STDIN_FILENO) + close(infd); + return failed; +} + +static int crypt_get_key_tty(const char *prompt, + char **key, size_t *key_size, + int timeout, int verify, + struct crypt_device *cd) +{ + int key_size_max = DEFAULT_PASSPHRASE_SIZE_MAX; + int r = -EINVAL; + char *pass = NULL, *pass_verify = NULL; + + *key = NULL; + *key_size = 0; + + log_dbg("Interactive passphrase entry requested."); + + pass = crypt_safe_alloc(key_size_max + 1); + if (!pass) { + log_err( _("Out of memory while reading passphrase.")); + return -ENOMEM; + } + + if (interactive_pass(prompt, pass, key_size_max, timeout)) { + log_err(_("Error reading passphrase from terminal.")); + goto out_err; + } + pass[key_size_max] = '\0'; + + if (verify) { + pass_verify = crypt_safe_alloc(key_size_max); + if (!pass_verify) { + log_err(_("Out of memory while reading passphrase.")); + r = -ENOMEM; + goto out_err; + } + + if (interactive_pass(_("Verify passphrase: "), + pass_verify, key_size_max, timeout)) { + log_err(_("Error reading passphrase from terminal.")); + goto out_err; + } + + if (strncmp(pass, pass_verify, key_size_max)) { + log_err(_("Passphrases do not match.")); + r = -EPERM; + goto out_err; + } + } + + *key = pass; + *key_size = strlen(pass); + r = 0; +out_err: + crypt_safe_free(pass_verify); + if (r) + crypt_safe_free(pass); + return r; +} + +/* + * Note: --key-file=- is interpreted as a read from a binary file (stdin) + * key_size_max == 0 means detect maximum according to input type (tty/file) + */ +int tools_get_key(const char *prompt, + char **key, size_t *key_size, + uint64_t keyfile_offset, size_t keyfile_size_max, + const char *key_file, + int timeout, int verify, int pwquality, + struct crypt_device *cd) +{ + char tmp[PATH_MAX], *backing_file; + int r = -EINVAL, block; + + block = tools_signals_blocked(); + if (block) + set_int_block(0); + + if (tools_is_stdin(key_file)) { + if (isatty(STDIN_FILENO)) { + if (keyfile_offset) { + log_err(_("Cannot use offset with terminal input.")); + } else { + if (!prompt && !crypt_get_device_name(cd)) + snprintf(tmp, sizeof(tmp), _("Enter passphrase: ")); + else if (!prompt) { + backing_file = crypt_loop_backing_file(crypt_get_device_name(cd)); + snprintf(tmp, sizeof(tmp), _("Enter passphrase for %s: "), backing_file ?: crypt_get_device_name(cd)); + free(backing_file); + } + r = crypt_get_key_tty(prompt ?: tmp, key, key_size, timeout, verify, cd); + } + } else { + log_dbg("STDIN descriptor passphrase entry requested."); + /* No keyfile means STDIN with EOL handling (\n will end input)). */ + r = crypt_keyfile_device_read(cd, NULL, key, key_size, + keyfile_offset, keyfile_size_max, + key_file ? 0 : CRYPT_KEYFILE_STOP_EOL); + } + } else { + log_dbg("File descriptor passphrase entry requested."); + r = crypt_keyfile_device_read(cd, key_file, key, key_size, + keyfile_offset, keyfile_size_max, 0); + } + + if (block && !quit) + set_int_block(1); + + /* Check pwquality for password (not keyfile) */ + if (pwquality && !key_file && !r) + r = tools_check_pwquality(*key); + + return r; +} void tools_passphrase_msg(int r) { @@ -29,29 +287,51 @@ void tools_passphrase_msg(int r) log_err(_("No usable keyslot is available.")); } -/* - * Only tool that currently blocks signals explicitly is cryptsetup-reencrypt. - * Leave the tools_get_key stub with signals handling here and remove it later - * only if we find signals blocking obsolete. - */ -int tools_get_key(const char *prompt, - char **key, size_t *key_size, - uint64_t keyfile_offset, size_t keyfile_size_max, - const char *key_file, - int timeout, int verify, int pwquality, - struct crypt_device *cd) +int tools_read_mk(const char *file, char **key, int keysize) { - int r, block; + int fd; - block = tools_signals_blocked(); - if (block) - set_int_block(0); + if (!keysize || !key) + return -EINVAL; - r = crypt_cli_get_key(prompt, key, key_size, keyfile_offset, - keyfile_size_max, key_file, timeout, verify, pwquality, cd, NULL); + *key = crypt_safe_alloc(keysize); + if (!*key) + return -ENOMEM; - if (block && !quit) - set_int_block(1); + fd = open(file, O_RDONLY); + if (fd == -1) { + log_err(_("Cannot read keyfile %s."), file); + goto fail; + } + if (read_buffer(fd, *key, keysize) != keysize) { + log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file); + close(fd); + goto fail; + } + close(fd); + return 0; +fail: + crypt_safe_free(*key); + *key = NULL; + return -EINVAL; +} + +int tools_write_mk(const char *file, const char *key, int keysize) +{ + int fd, r = -EINVAL; + + fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR); + if (fd < 0) { + log_err(_("Cannot open keyfile %s for write."), file); + return r; + } + + if (write_buffer(fd, key, keysize) == keysize) + r = 0; + else + log_err(_("Cannot write to keyfile %s."), file); + + close(fd); return r; } diff --git a/src/veritysetup.c b/src/veritysetup.c index 92bfcd4b..dc183e54 100644 --- a/src/veritysetup.c +++ b/src/veritysetup.c @@ -179,7 +179,7 @@ static int _activate(const char *dm_device, goto out; } signature_size = st.st_size; - r = crypt_cli_read_mk(cd, ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID), &signature, signature_size); + r = tools_read_mk(ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID), &signature, signature_size); if (r < 0) { log_err(_("Cannot read signature file %s."), ARG_STR(OPT_ROOT_HASH_SIGNATURE_ID)); goto out;