mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Fix spurious EAGAIN in Plink host key (and other) prompts.
Plink sets standard input into nonblocking mode, meaning that read() from fd 0 in an interactive context will typically return -1 EAGAIN. But the prompt functions in uxcons.c, used for verifying SSH host keys and suchlike, were doing an unguarded read() from fd 0, and then panicking and aborting the session when they got EAGAIN. Fixed by inventing a wrapper around read(2) which handles EAGAIN but passes all other errors back to the caller. (Seemed slightly less dangerous than the stateful alternative of temporarily re-blockifying the file descriptor.)
This commit is contained in:
parent
5f6e443b55
commit
bea758a7ae
@ -7,6 +7,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
@ -74,6 +75,38 @@ void timer_change_notify(unsigned long next)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around Unix read(2), suitable for use on a file descriptor
|
||||
* that's been set into nonblocking mode. Handles EAGAIN/EWOULDBLOCK
|
||||
* by means of doing a one-fd select and then trying again; all other
|
||||
* errors (including errors from select) are returned to the caller.
|
||||
*/
|
||||
static int block_and_read(int fd, void *buf, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while ((ret = read(fd, buf, len)) < 0 && (
|
||||
#ifdef EAGAIN
|
||||
(errno == EAGAIN) ||
|
||||
#endif
|
||||
#ifdef EWOULDBLOCK
|
||||
(errno == EWOULDBLOCK) ||
|
||||
#endif
|
||||
0)) {
|
||||
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd, &rfds);
|
||||
ret = select(fd+1, &rfds, NULL, NULL, NULL);
|
||||
assert(ret != 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
assert(FD_ISSET(fd, &rfds));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int verify_ssh_host_key(void *frontend, char *host, int port,
|
||||
const char *keytype, char *keystr, char *fingerprint,
|
||||
void (*callback)(void *ctx, int result), void *ctx)
|
||||
@ -163,7 +196,7 @@ int verify_ssh_host_key(void *frontend, char *host, int port,
|
||||
newmode.c_lflag |= ECHO | ISIG | ICANON;
|
||||
tcsetattr(0, TCSANOW, &newmode);
|
||||
line[0] = '\0';
|
||||
if (read(0, line, sizeof(line) - 1) <= 0)
|
||||
if (block_and_read(0, line, sizeof(line) - 1) <= 0)
|
||||
/* handled below */;
|
||||
tcsetattr(0, TCSANOW, &oldmode);
|
||||
}
|
||||
@ -216,7 +249,7 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
newmode.c_lflag |= ECHO | ISIG | ICANON;
|
||||
tcsetattr(0, TCSANOW, &newmode);
|
||||
line[0] = '\0';
|
||||
if (read(0, line, sizeof(line) - 1) <= 0)
|
||||
if (block_and_read(0, line, sizeof(line) - 1) <= 0)
|
||||
/* handled below */;
|
||||
tcsetattr(0, TCSANOW, &oldmode);
|
||||
}
|
||||
@ -270,7 +303,7 @@ int askappend(void *frontend, Filename *filename,
|
||||
newmode.c_lflag |= ECHO | ISIG | ICANON;
|
||||
tcsetattr(0, TCSANOW, &newmode);
|
||||
line[0] = '\0';
|
||||
if (read(0, line, sizeof(line) - 1) <= 0)
|
||||
if (block_and_read(0, line, sizeof(line) - 1) <= 0)
|
||||
/* handled below */;
|
||||
tcsetattr(0, TCSANOW, &oldmode);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user