Commit 5293f5aa authored by Milan Broz's avatar Milan Broz

Move terminal handling to tools wrapper.

parent 39698fa6
......@@ -31,7 +31,6 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include "libcryptsetup.h"
#include "nls.h"
......@@ -150,138 +149,6 @@ void *crypt_safe_realloc(void *data, size_t size)
return new_data;
}
/* 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(cd, _("Out of memory while reading passphrase.\n"));
return -ENOMEM;
}
if (interactive_pass(prompt, pass, key_size_max, timeout)) {
log_err(cd, _("Error reading passphrase from terminal.\n"));
goto out_err;
}
pass[key_size_max] = '\0';
if (verify) {
pass_verify = crypt_safe_alloc(key_size_max);
if (!pass_verify) {
log_err(cd, _("Out of memory while reading passphrase.\n"));
r = -ENOMEM;
goto out_err;
}
if (interactive_pass(_("Verify passphrase: "),
pass_verify, key_size_max, timeout)) {
log_err(cd, _("Error reading passphrase from terminal.\n"));
goto out_err;
}
if (strncmp(pass, pass_verify, key_size_max)) {
log_err(cd, _("Passphrases do not match.\n"));
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;
}
/*
* A simple call to lseek(3) might not be possible for some inputs (e.g.
* reading from a pipe), so this function instead reads of up to BUFSIZ bytes
......@@ -451,39 +318,6 @@ out_err:
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)
* timeout and verify options only applies to tty input
*/
int crypt_get_key(const char *prompt,
char **key, size_t *key_size,
size_t keyfile_offset, size_t keyfile_size_max,
const char *key_file, int timeout, int verify,
struct crypt_device *cd)
{
int read_stdin;
/* Passphrase read from stdin? */
read_stdin = (!key_file || !strcmp(key_file, "-")) ? 1 : 0;
if (read_stdin && isatty(STDIN_FILENO)) {
if (keyfile_offset) {
log_err(cd, _("Cannot use offset with terminal input.\n"));
return -EINVAL;
}
return crypt_get_key_tty(prompt, key, key_size, timeout, verify, cd);
}
if (read_stdin)
log_dbg("STDIN descriptor passphrase entry requested.");
else
log_dbg("File descriptor passphrase entry requested.");
return crypt_keyfile_read(cd, key_file, key, key_size, keyfile_offset, keyfile_size_max);
}
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
{
char buf[3] = "xx\0", *endp, *bytes;
......
......@@ -34,13 +34,6 @@ struct crypt_device;
int crypt_parse_name_and_mode(const char *s, char *cipher,
int *key_nums, char *cipher_mode);
int crypt_get_key(const char *prompt,
char **key, size_t *key_size,
size_t keyfile_offset, size_t keyfile_size_max,
const char *key_file,
int timeout, int verify,
struct crypt_device *cd);
void *crypt_safe_alloc(size_t size);
void crypt_safe_free(void *data);
void *crypt_safe_realloc(void *data, size_t size);
......
......@@ -74,6 +74,7 @@ if REENCRYPT
cryptsetup_reencrypt_SOURCES = \
$(top_builddir)/lib/utils_crypt.c \
utils_tools.c \
utils_password.c \
cryptsetup_reencrypt.c \
cryptsetup.h
......
......@@ -987,17 +987,13 @@ static int init_passphrase1(struct reenc_ctx *rc, struct crypt_device *cd,
retry_count = opt_tries ?: 1;
while (retry_count--) {
set_int_handler(0);
r = crypt_get_key(msg, &password, &passwordLen,
0, 0, NULL /*opt_key_file*/,
0, 0, cd);
r = tools_get_key(msg, &password, &passwordLen, 0, 0,
NULL /*opt_key_file*/, 0, 0, 0 /*pwquality*/, cd);
if (r < 0)
return r;
if (quit)
return -EAGAIN;
/* library uses sigint internally, until it is fixed...*/
set_int_block(1);
if (check)
r = crypt_activate_by_passphrase(cd, NULL, slot_to_check,
password, passwordLen, 0);
......@@ -1032,8 +1028,8 @@ static int init_keyfile(struct reenc_ctx *rc, struct crypt_device *cd, int slot_
int r;
size_t passwordLen;
r = crypt_get_key(NULL, &password, &passwordLen, opt_keyfile_offset,
opt_keyfile_size, opt_key_file, 0, 0, cd);
r = tools_get_key(NULL, &password, &passwordLen, opt_keyfile_offset,
opt_keyfile_size, opt_key_file, 0, 0, 0, cd);
if (r < 0)
return r;
......
......@@ -20,6 +20,7 @@
*/
#include "cryptsetup.h"
#include <termios.h>
int opt_force_password = 0;
......@@ -112,6 +113,170 @@ int tools_is_stdin(const char *key_file)
return strcmp(key_file, "-") ? 0 : 1;
}
/* 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.\n"));
return -ENOMEM;
}
if (interactive_pass(prompt, pass, key_size_max, timeout)) {
log_err(_("Error reading passphrase from terminal.\n"));
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.\n"));
r = -ENOMEM;
goto out_err;
}
if (interactive_pass(_("Verify passphrase: "),
pass_verify, key_size_max, timeout)) {
log_err(_("Error reading passphrase from terminal.\n"));
goto out_err;
}
if (strncmp(pass, pass_verify, key_size_max)) {
log_err(_("Passphrases do not match.\n"));
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)
* timeout and verify options only applies to tty input
*/
static int crypt_get_key(const char *prompt,
char **key, size_t *key_size,
size_t keyfile_offset, size_t keyfile_size_max,
const char *key_file, int timeout, int verify,
struct crypt_device *cd)
{
int read_stdin;
/* Passphrase read from stdin? */
read_stdin = (!key_file || !strcmp(key_file, "-")) ? 1 : 0;
if (read_stdin && isatty(STDIN_FILENO)) {
if (keyfile_offset) {
log_err(_("Cannot use offset with terminal input.\n"));
return -EINVAL;
}
return crypt_get_key_tty(prompt, key, key_size, timeout, verify, cd);
}
if (read_stdin)
log_dbg("STDIN descriptor passphrase entry requested.");
else
log_dbg("File descriptor passphrase entry requested.");
return crypt_keyfile_read(cd, key_file, key, key_size, keyfile_offset, keyfile_size_max);
}
int tools_get_key(const char *prompt,
char **key, size_t *key_size,
size_t keyfile_offset, size_t keyfile_size_max,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment