Hi,
Attached is a patch that fixes this issue. In the process, it also gets
rid of getpass() (which is considered obsolete, and should not be used;
see the manpage). Instead, we use select()+read(), along w/ manually
disabling ECHO in the terminal.
------------------------------------------------------------
revno: 2
committer: Andres Salomon <[EMAIL PROTECTED]>
branch nick: cryptsetup-1.0.2+1.0.3-rc3
timestamp: Fri 2006-04-21 20:55:53 -0400
message:
Instead of using getpass() (which the manpage claims is obsolete), manually
read() and disabling ECHO on the terminal. Remove the signal based timeout,
and instead select on a (buffered) descriptor. This should fix a bug
described in <http://bugs.debian.org/364153>.
------------------------------------------------------------
revno: 1
committer: Andres Salomon <[EMAIL PROTECTED]>
branch nick: cryptsetup-1.0.2+1.0.3-rc3
timestamp: Fri 2006-04-21 13:45:56 -0400
message:
Initial import.
=== modified file 'lib/setup.c'
--- lib/setup.c
+++ lib/setup.c
@@ -7,6 +7,7 @@
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
+#include <termios.h>
#include <errno.h>
#include <signal.h>
#include <assert.h>
@@ -23,12 +24,6 @@
static int memory_unsafe = 0;
static char *default_backend = NULL;
-
-static void catch_alarm(int sig_num)
-{
- fprintf(stderr, "Operation timed out. Exiting.\n");
- exit(0);
-}
static int setup_enter(struct setup_backend *backend)
{
@@ -70,6 +65,66 @@
munlockall();
return 0;
+}
+
+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;
+ }
+ return i;
+}
+
+static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
+{
+ struct timeval t;
+ fd_set fds;
+ 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);
+ else
+ fprintf(stderr, "Operation timed out.\n");
+ return failed;
+}
+
+static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
+ long timeout)
+{
+ struct termios orig, tmp;
+ int failed = -1;
+
+ if (maxlen < 1)
+ goto out_err;
+
+ if (tcgetattr(STDIN_FILENO, &orig)) {
+ set_error("Unable to get terminal");
+ goto out_err;
+ }
+ memcpy(&tmp, &orig, sizeof(tmp));
+ tmp.c_lflag &= ~ECHO;
+
+ write(STDOUT_FILENO, prompt, strlen(prompt));
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tmp);
+ if (timeout)
+ failed = timed_read(STDIN_FILENO, pass, maxlen, timeout);
+ else
+ failed = untimed_read(STDIN_FILENO, pass, maxlen);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig);
+
+out_err:
+ if (!failed)
+ write(STDOUT_FILENO, "\n", 1);
+ return failed;
}
/*
@@ -107,32 +162,23 @@
newline_stop = 1;
}
- signal(SIGALRM, catch_alarm);
- if(options->timeout) {
- alarm(options->timeout);
- } else {
- alarm(0);
- }
-
/* Interactive case */
if(isatty(fd)) {
- char *pass2;
-
- pass2 = getpass(prompt);
- if (!pass2) {
+ int i;
+
+ pass = safe_alloc(512);
+ if (!pass || (i = interactive_pass(prompt, pass, 512, options->timeout))) {
set_error("Error reading passphrase");
goto out_err;
}
- pass = safe_strdup(pass2);
- memset(pass2, 0, strlen(pass2));
-
if (verify || verify_if_possible) {
- char *pass_verify = getpass("Verify passphrase: ");
- if (!pass_verify || strcmp(pass, pass_verify) != 0) {
+ char pass_verify[512];
+ i = interactive_pass("Verify passphrase: ", pass_verify, sizeof(pass_verify), options->timeout);
+ if (i || strcmp(pass, pass_verify) != 0) {
set_error("Passphrases do not match");
goto out_err;
}
- memset(pass_verify, 0, strlen(pass_verify));
+ memset(pass_verify, 0, sizeof(pass_verify));
}
*passLen = strlen(pass);
*key = pass;
@@ -185,7 +231,6 @@
pass[i] = 0;
*key = pass;
*passLen = i;
- alarm(0);
}
return;