mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-01 03:22:48 -05:00
Revamp SSH authentication code so that user interaction is more
abstracted out; replace loops structured around a single interaction per loop with less tortuous code (fixes: `ki-multiprompt-crash', `ssh1-bad-passphrase-crash'; makes `ssh2-password-expiry' and `proxy-password-prompt' easier). The new interaction abstraction has a lot of fields that are unused in the current code (things like window captions); this is groundwork for `gui-auth'. However, ssh.c still writes directly to stderr; that may want to be fixed. In the GUI apps, user interaction is moved to terminal.c. This should make it easier to fix things like UTF-8 username entry, although I haven't attempted to do so. Also, control character filtering can be tailored to be appropriate for individual front-ends; so far I don't promise anything other than not having made it any worse. I've tried to test this fairly exhaustively (although Mac stuff is untested, as usual). It all seems to basically work, but I bet there are new bugs. (One I know about is that you can no longer make the PuTTY window go away with a ^D at the password prompt; this should be fixed.) [originally from svn r6437] [this svn revision also touched putty-wishlist]
This commit is contained in:
@ -298,48 +298,90 @@ void logevent(void *frontend, const char *string)
|
||||
log_eventlog(console_logctx, string);
|
||||
}
|
||||
|
||||
int console_get_line(const char *prompt, char *str,
|
||||
int maxlen, int is_pw)
|
||||
static void console_data_untrusted(HANDLE hout, const char *data, int len)
|
||||
{
|
||||
DWORD dummy;
|
||||
/* FIXME: control-character filtering */
|
||||
WriteFile(hout, data, len, &dummy, NULL);
|
||||
}
|
||||
|
||||
int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
|
||||
{
|
||||
HANDLE hin, hout;
|
||||
DWORD savemode, newmode, i;
|
||||
size_t curr_prompt;
|
||||
|
||||
if (console_batch_mode) {
|
||||
if (maxlen > 0)
|
||||
str[0] = '\0';
|
||||
/*
|
||||
* Zero all the results, in case we abort half-way through.
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < p->n_prompts; i++)
|
||||
memset(p->prompts[i]->result, 0, p->prompts[i]->result_len);
|
||||
}
|
||||
|
||||
if (console_batch_mode)
|
||||
return 0;
|
||||
} else {
|
||||
hin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
hout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Cannot get standard input/output handles\n");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
|
||||
hin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
hout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Cannot get standard input/output handles\n");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Preamble.
|
||||
*/
|
||||
/* We only print the `name' caption if we have to... */
|
||||
if (p->name_reqd && p->name) {
|
||||
size_t l = strlen(p->name);
|
||||
console_data_untrusted(hout, p->name, l);
|
||||
if (p->name[l-1] != '\n')
|
||||
console_data_untrusted(hout, "\n", 1);
|
||||
}
|
||||
/* ...but we always print any `instruction'. */
|
||||
if (p->instruction) {
|
||||
size_t l = strlen(p->instruction);
|
||||
console_data_untrusted(hout, p->instruction, l);
|
||||
if (p->instruction[l-1] != '\n')
|
||||
console_data_untrusted(hout, "\n", 1);
|
||||
}
|
||||
|
||||
for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
|
||||
|
||||
DWORD savemode, newmode, i = 0;
|
||||
prompt_t *pr = p->prompts[curr_prompt];
|
||||
BOOL r;
|
||||
|
||||
GetConsoleMode(hin, &savemode);
|
||||
newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
|
||||
if (is_pw)
|
||||
if (!pr->echo)
|
||||
newmode &= ~ENABLE_ECHO_INPUT;
|
||||
else
|
||||
newmode |= ENABLE_ECHO_INPUT;
|
||||
SetConsoleMode(hin, newmode);
|
||||
|
||||
WriteFile(hout, prompt, strlen(prompt), &i, NULL);
|
||||
ReadFile(hin, str, maxlen - 1, &i, NULL);
|
||||
console_data_untrusted(hout, pr->prompt, strlen(pr->prompt));
|
||||
|
||||
r = ReadFile(hin, pr->result, pr->result_len - 1, &i, NULL);
|
||||
|
||||
SetConsoleMode(hin, savemode);
|
||||
|
||||
if ((int) i > maxlen)
|
||||
i = maxlen - 1;
|
||||
if ((int) i > pr->result_len)
|
||||
i = pr->result_len - 1;
|
||||
else
|
||||
i = i - 2;
|
||||
str[i] = '\0';
|
||||
pr->result[i] = '\0';
|
||||
|
||||
if (is_pw)
|
||||
WriteFile(hout, "\r\n", 2, &i, NULL);
|
||||
if (!pr->echo) {
|
||||
DWORD dummy;
|
||||
WriteFile(hout, "\r\n", 2, &dummy, NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1; /* success */
|
||||
|
||||
}
|
||||
|
||||
void frontend_keypress(void *handle)
|
||||
|
@ -5069,6 +5069,20 @@ int from_backend(void *frontend, int is_stderr, const char *data, int len)
|
||||
return term_data(term, is_stderr, data, len);
|
||||
}
|
||||
|
||||
int from_backend_untrusted(void *frontend, const char *data, int len)
|
||||
{
|
||||
return term_data_untrusted(term, data, len);
|
||||
}
|
||||
|
||||
int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
|
||||
{
|
||||
int ret;
|
||||
ret = cmdline_get_passwd_input(p, in, inlen);
|
||||
if (ret == -1)
|
||||
ret = term_get_userpass_input(term, p, in, inlen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void agent_schedule_callback(void (*callback)(void *, void *, int),
|
||||
void *callback_ctx, void *data, int len)
|
||||
{
|
||||
|
@ -189,6 +189,25 @@ int from_backend(void *frontend_handle, int is_stderr,
|
||||
return osize + esize;
|
||||
}
|
||||
|
||||
int from_backend_untrusted(void *frontend_handle, const char *data, int len)
|
||||
{
|
||||
/*
|
||||
* No "untrusted" output should get here (the way the code is
|
||||
* currently, it's all diverted by FLAG_STDERR).
|
||||
*/
|
||||
assert(!"Unexpected call to from_backend_untrusted()");
|
||||
return 0; /* not reached */
|
||||
}
|
||||
|
||||
int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
|
||||
{
|
||||
int ret;
|
||||
ret = cmdline_get_passwd_input(p, in, inlen);
|
||||
if (ret == -1)
|
||||
ret = console_get_userpass_input(p, in, inlen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD main_thread_id;
|
||||
|
||||
void agent_schedule_callback(void (*callback)(void *, void *, int),
|
||||
@ -285,8 +304,6 @@ int main(int argc, char **argv)
|
||||
int use_subsystem = 0;
|
||||
long now, next;
|
||||
|
||||
ssh_get_line = console_get_line;
|
||||
|
||||
sklist = NULL;
|
||||
skcount = sksize = 0;
|
||||
/*
|
||||
|
@ -127,6 +127,15 @@ void gui_enable(char *arg)
|
||||
|
||||
char *get_ttymode(void *frontend, const char *mode) { return NULL; }
|
||||
|
||||
int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
|
||||
{
|
||||
int ret;
|
||||
ret = cmdline_get_passwd_input(p, in, inlen);
|
||||
if (ret == -1)
|
||||
ret = console_get_userpass_input(p, in, inlen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* File access abstraction.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user