From d294d1d0dce7e827fed9a3f85975a766d13702ea Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 18 May 2018 11:01:12 +0100 Subject: [PATCH] Restructure some loops with crReturn in them. A large part of the purpose of the 20-patch series just past is to arrange that user input is never dropped on the floor: if you type it at a moment where the active protocol coroutine has nothing it can usefully do with it, the default action will now be to leave it on the user_input queue where it will eventually be picked up by some later coroutine, or later phase of this one, that does. And did I _test_ this feature, end to end, just once, before pushing the giant patch series? I did not. It doesn't work, and the reason why it doesn't work is because various loops that spin round alternating a crReturn with a check of the input queue do the first crReturn _before_ the first queue check. So if there's already data in the queue, well, it won't be _dropped_, but it also won't be passed on immediately to where it needs to be - instead, it will sit in the queue until you press _another_ key, at which point a queue check will happen and all your backed-up typeahead data will come out. Fixed by restructuring those loops to do a queue check first. This applies to the final loop in do_ssh2_connection, and all the little loops during userauth that prompt for usernames, passwords, passphrases etc via get_userpass_input. --- ssh.c | 96 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 35 deletions(-) diff --git a/ssh.c b/ssh.c index 5b2a3bc0..7481acd6 100644 --- a/ssh.c +++ b/ssh.c @@ -4551,13 +4551,17 @@ static void do_ssh1_login(void *vctx) s->cur_prompt->name = dupstr("SSH login name"); add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -4849,13 +4853,17 @@ static void do_ssh1_login(void *vctx) dupprintf("Passphrase for key \"%.100s\": ", s->publickey_comment), FALSE); s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -5072,13 +5080,17 @@ static void do_ssh1_login(void *vctx) * authentication. */ s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -10315,13 +10327,17 @@ static void do_ssh2_userauth(void *vctx) s->cur_prompt->name = dupstr("SSH login name"); add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -10745,14 +10761,17 @@ static void do_ssh2_userauth(void *vctx) FALSE); s->userpass_ret = get_userpass_input( s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) { + bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); - } + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -11131,14 +11150,17 @@ static void do_ssh2_userauth(void *vctx) * response(s). */ s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) { + bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); - } + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -11201,14 +11223,17 @@ static void do_ssh2_userauth(void *vctx) FALSE); s->userpass_ret = get_userpass_input(s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) { + bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); - } + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -11315,16 +11340,17 @@ static void do_ssh2_userauth(void *vctx) while (!got_new) { s->userpass_ret = get_userpass_input( s->cur_prompt, NULL); - while (s->userpass_ret < 0) { - ssh->send_ok = 1; - crReturnV; + while (1) { while (s->userpass_ret < 0 && - bufchain_size(&ssh->user_input) > 0) { + bufchain_size(&ssh->user_input) > 0) s->userpass_ret = get_userpass_input( s->cur_prompt, &ssh->user_input); - if (s->userpass_ret >= 0) - break; - } + + if (s->userpass_ret >= 0) + break; + + ssh->send_ok = 1; + crReturnV; ssh->send_ok = 0; } if (!s->userpass_ret) { @@ -11743,7 +11769,6 @@ static void do_ssh2_connection(void *vctx) if (ssh->mainchan) ssh->send_ok = 1; while (1) { - crReturnV; if ((pktin = pq_pop(&ssh->pq_ssh2_connection)) != NULL) { /* @@ -11765,6 +11790,7 @@ static void do_ssh2_connection(void *vctx) ssh_send_channel_data(ssh->mainchan, data, len); bufchain_consume(&ssh->user_input, len); } + crReturnV; } crFinishV;