WIP: Introduce libcryptsetup_cli.

Introducing new library supposed to be used in
cryptsetup tools and future cryptsetup loadable plugins

TODO:
  - distribution
  - cleanup header files
  - incorporate also plugin API?
This commit is contained in:
Ondrej Kozina
2020-06-26 14:03:25 +02:00
committed by Milan Broz
parent 5ebf128023
commit a985c12659
13 changed files with 607 additions and 295 deletions

View File

@@ -6,6 +6,7 @@ DISTCLEAN_TARGETS =
AM_CPPFLAGS = \ AM_CPPFLAGS = \
-include config.h \ -include config.h \
-I$(top_srcdir)/lib \ -I$(top_srcdir)/lib \
-I$(top_srcdir)/lib/cli \
-DDATADIR=\""$(datadir)"\" \ -DDATADIR=\""$(datadir)"\" \
-DLOCALEDIR=\""$(datadir)/locale"\" \ -DLOCALEDIR=\""$(datadir)/locale"\" \
-DLIBDIR=\""$(libdir)"\" \ -DLIBDIR=\""$(libdir)"\" \
@@ -19,10 +20,13 @@ LDADD = $(LTLIBINTL) -lm
tmpfilesddir = @DEFAULT_TMPFILESDIR@ tmpfilesddir = @DEFAULT_TMPFILESDIR@
include_HEADERS =
lib_LTLIBRARIES =
noinst_LTLIBRARIES = noinst_LTLIBRARIES =
sbin_PROGRAMS = sbin_PROGRAMS =
man8_MANS = man8_MANS =
tmpfilesd_DATA = tmpfilesd_DATA =
pkgconfig_DATA =
include man/Makemodule.am include man/Makemodule.am
@@ -33,6 +37,7 @@ include lib/crypto_backend/argon2/Makemodule.am
endif endif
include lib/crypto_backend/Makemodule.am include lib/crypto_backend/Makemodule.am
include lib/Makemodule.am include lib/Makemodule.am
include lib/cli/Makemodule.am
include src/Makemodule.am include src/Makemodule.am

View File

@@ -5,6 +5,9 @@ dnl library version from <major>.<minor>.<release>[-<suffix>]
LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-) LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-)
LIBCRYPTSETUP_VERSION_INFO=18:0:6 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]) AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(src/cryptsetup.c) AC_CONFIG_SRCDIR(src/cryptsetup.c)
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@@ -539,6 +542,9 @@ AC_SUBST([BLKID_LIBS])
AC_SUBST([LIBCRYPTSETUP_VERSION]) AC_SUBST([LIBCRYPTSETUP_VERSION])
AC_SUBST([LIBCRYPTSETUP_VERSION_INFO]) AC_SUBST([LIBCRYPTSETUP_VERSION_INFO])
AC_SUBST([LIBCRYPTSETUP_CLI_VERSION])
AC_SUBST([LIBCRYPTSETUP_CLI_VERSION_INFO])
dnl ========================================================================== dnl ==========================================================================
AC_ARG_ENABLE([dev-random], AC_ARG_ENABLE([dev-random],
AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)])) AS_HELP_STRING([--enable-dev-random], [use /dev/random by default for key generation (otherwise use /dev/urandom)]))
@@ -648,6 +654,7 @@ dnl ==========================================================================
AC_CONFIG_FILES([ Makefile AC_CONFIG_FILES([ Makefile
lib/libcryptsetup.pc lib/libcryptsetup.pc
lib/cli/libcryptsetup_cli.pc
po/Makefile.in po/Makefile.in
scripts/cryptsetup.conf scripts/cryptsetup.conf
tests/Makefile tests/Makefile

View File

@@ -1,11 +1,11 @@
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = lib/libcryptsetup.pc pkgconfig_DATA += lib/libcryptsetup.pc
lib_LTLIBRARIES = libcryptsetup.la lib_LTLIBRARIES += libcryptsetup.la
noinst_LTLIBRARIES += libutils_io.la noinst_LTLIBRARIES += libutils_io.la
include_HEADERS = lib/libcryptsetup.h include_HEADERS += lib/libcryptsetup.h
EXTRA_DIST += lib/libcryptsetup.pc.in lib/libcryptsetup.sym EXTRA_DIST += lib/libcryptsetup.pc.in lib/libcryptsetup.sym

28
lib/cli/Makemodule.am Normal file
View File

@@ -0,0 +1,28 @@
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/cli/cli.c

391
lib/cli/cli.c Normal file
View File

@@ -0,0 +1,391 @@
/*
* 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 <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include "nls.h"
#include "utils_loop.h"
#include "libcryptsetup.h"
#include "libcryptsetup_cli.h"
#include "cli_internal.h"
#define log_dbg(x...) clogger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
#define log_std(x...) clogger(NULL, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
#define log_verbose(x...) clogger(NULL, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)
#define log_err(x...) clogger(NULL, CRYPT_LOG_ERROR, __FILE__, __LINE__, x)
#define LOG_MAX_LEN 4096
/* 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 <pwquality.h>
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 <passwdqc.h>
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(&params);
if (*config && passwdqc_params_load(&params, &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(&params.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 */
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;
}
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) {
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);
}
/* Check pwquality for password (not keyfile) */
if (pwquality && !key_file && !r)
r = tools_check_pwquality(*key);
return r;
}
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;
}

50
lib/cli/cli_internal.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* 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 <stdbool.h>
#include <sys/types.h>
#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

View File

@@ -0,0 +1,61 @@
/*
* 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 <stdbool.h>
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);
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

View File

@@ -0,0 +1,10 @@
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

View File

@@ -0,0 +1,9 @@
CRYPTSETUP_CLI_1.0 {
global:
crypt_cli_get_key;
crypt_cli_arg_set;
crypt_cli_arg_type;
crypt_cli_arg_value;
local:
*;
};

View File

@@ -1,6 +1,9 @@
# cryptsetup # cryptsetup
if CRYPTSETUP if CRYPTSETUP
# cryptsetup_CPPFLAGS = $(AM_CPPFLAGS) \
# -I $(top_srcdir)/lib/cli
cryptsetup_SOURCES = \ cryptsetup_SOURCES = \
lib/utils_crypt.c \ lib/utils_crypt.c \
lib/utils_loop.c \ lib/utils_loop.c \
@@ -20,9 +23,8 @@ cryptsetup_SOURCES = \
cryptsetup_LDADD = $(LDADD) \ cryptsetup_LDADD = $(LDADD) \
libcryptsetup.la \ libcryptsetup.la \
libcryptsetup_cli.la \
@POPT_LIBS@ \ @POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@UUID_LIBS@ \ @UUID_LIBS@ \
@BLKID_LIBS@ @BLKID_LIBS@
@@ -60,9 +62,8 @@ veritysetup_SOURCES = \
veritysetup_LDADD = $(LDADD) \ veritysetup_LDADD = $(LDADD) \
libcryptsetup.la \ libcryptsetup.la \
libcryptsetup_cli.la \
@POPT_LIBS@ \ @POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@BLKID_LIBS@ @BLKID_LIBS@
sbin_PROGRAMS += veritysetup sbin_PROGRAMS += veritysetup
@@ -99,6 +100,7 @@ integritysetup_SOURCES = \
integritysetup_LDADD = $(LDADD) \ integritysetup_LDADD = $(LDADD) \
libcryptsetup.la \ libcryptsetup.la \
libcryptsetup_cli.la \
@POPT_LIBS@ \ @POPT_LIBS@ \
@UUID_LIBS@ \ @UUID_LIBS@ \
@BLKID_LIBS@ @BLKID_LIBS@
@@ -134,9 +136,8 @@ cryptsetup_reencrypt_SOURCES = \
cryptsetup_reencrypt_LDADD = $(LDADD) \ cryptsetup_reencrypt_LDADD = $(LDADD) \
libcryptsetup.la \ libcryptsetup.la \
libcryptsetup_cli.la \
@POPT_LIBS@ \ @POPT_LIBS@ \
@PWQUALITY_LIBS@ \
@PASSWDQC_LIBS@ \
@UUID_LIBS@ \ @UUID_LIBS@ \
@BLKID_LIBS@ @BLKID_LIBS@

View File

@@ -48,6 +48,8 @@
#include "lib/utils_blkid.h" #include "lib/utils_blkid.h"
#include "libcryptsetup.h" #include "libcryptsetup.h"
#include "libcryptsetup_cli.h"
#include "lib/cli/cli_internal.h"
#define CONST_CAST(x) (x)(uintptr_t) #define CONST_CAST(x) (x)(uintptr_t)
#define DEFAULT_CIPHER(type) (DEFAULT_##type##_CIPHER "-" DEFAULT_##type##_MODE) #define DEFAULT_CIPHER(type) (DEFAULT_##type##_CIPHER "-" DEFAULT_##type##_MODE)
@@ -119,6 +121,12 @@ int tools_wipe_all_signatures(const char *path);
int tools_lookup_crypt_device(struct crypt_device *cd, const char *type, int tools_lookup_crypt_device(struct crypt_device *cd, const char *type,
const char *data_device_path, char *name, size_t name_length); 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 */ /* each utility is required to implement it */
void tools_cleanup(void); void tools_cleanup(void);
@@ -130,33 +138,4 @@ void tools_cleanup(void);
#define log_verbose(x...) clogger(NULL, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x) #define log_verbose(x...) clogger(NULL, CRYPT_LOG_VERBOSE, __FILE__, __LINE__, x)
#define log_err(x...) clogger(NULL, CRYPT_LOG_ERROR, __FILE__, __LINE__, x) #define log_err(x...) clogger(NULL, CRYPT_LOG_ERROR, __FILE__, __LINE__, 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);
#endif /* CRYPTSETUP_H */ #endif /* CRYPTSETUP_H */

View File

@@ -24,6 +24,7 @@
#include "utils_arg_names.h" #include "utils_arg_names.h"
#include "utils_arg_macros.h" #include "utils_arg_macros.h"
#include "lib/cli/cli_internal.h"
#define BITLKDUMP_ACTION "bitlkDump" #define BITLKDUMP_ACTION "bitlkDump"
#define BENCHMARK_ACTION "benchmark" #define BENCHMARK_ACTION "benchmark"

View File

@@ -22,263 +22,6 @@
#include "cryptsetup.h" #include "cryptsetup.h"
#include <termios.h> #include <termios.h>
#if defined ENABLE_PWQUALITY
#include <pwquality.h>
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 <passwdqc.h>
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(&params);
if (*config && passwdqc_params_load(&params, &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(&params.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) void tools_passphrase_msg(int r)
{ {
if (r == -EPERM) if (r == -EPERM)
@@ -335,3 +78,30 @@ int tools_write_mk(const char *file, const char *key, int keysize)
close(fd); close(fd);
return r; return r;
} }
/*
* Only tool that currently blocks signals explicitely 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 r, block;
block = tools_signals_blocked();
if (block)
set_int_block(0);
r = crypt_cli_get_key(prompt, key, key_size, keyfile_offset,
keyfile_size_max, key_file, timeout, verify, pwquality, cd, NULL);
if (block && !quit)
set_int_block(1);
return r;
}