From 128d001c3eebae15fe97fc18dc48d8939ae72e98 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 20 Apr 2019 08:24:16 +0100 Subject: [PATCH] SSH-1: disable trust sigils after session starts. This exactly replicates the way it's done in SSH-2: at the start of the connection layer we set the trust status to untrusted, and if that reports that it didn't give any indication to the user, we fall back to presenting an interactive anti-spoofing prompt. I don't know how I forgot to do that in SSH-1, and even more, how we haven't noticed for a month. We noticed the same bug in _Rlogin_ within a day of the 0.71 release, after all! --- ssh1connection-client.c | 5 +++++ ssh1connection-server.c | 5 +++++ ssh1connection.c | 39 +++++++++++++++++++++++++++++++++++++++ ssh1connection.h | 5 +++++ 4 files changed, 54 insertions(+) diff --git a/ssh1connection-client.c b/ssh1connection-client.c index faa0df28..40107dc3 100644 --- a/ssh1connection-client.c +++ b/ssh1connection-client.c @@ -526,3 +526,8 @@ SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan) { unreachable("Should never be called in the client"); } + +bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s) +{ + return !seat_set_trust_status(s->ppl.seat, false); +} diff --git a/ssh1connection-server.c b/ssh1connection-server.c index 6cef5012..aa44c529 100644 --- a/ssh1connection-server.c +++ b/ssh1connection-server.c @@ -374,3 +374,8 @@ SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan) return &c->sc; } + +bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s) +{ + return false; +} diff --git a/ssh1connection.c b/ssh1connection.c index 8b0c3aa9..d9b98420 100644 --- a/ssh1connection.c +++ b/ssh1connection.c @@ -209,6 +209,9 @@ static void ssh1_connection_free(PacketProtocolLayer *ppl) freetree234(s->rportfwds); portfwdmgr_free(s->portfwdmgr); + if (s->antispoof_prompt) + free_prompts(s->antispoof_prompt); + delete_callbacks_for_context(s); sfree(s); @@ -376,6 +379,42 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl) crBegin(s->crState); + /* + * Signal the seat that authentication is done, so that it can + * deploy spoofing defences. If it doesn't have any, deploy our + * own fallback one. + * + * We do this here rather than at the end of userauth, because we + * might not have gone through userauth at all (if we're a + * connection-sharing downstream). + */ + if (ssh1_connection_need_antispoof_prompt(s)) { + s->antispoof_prompt = new_prompts(); + s->antispoof_prompt->to_server = true; + s->antispoof_prompt->from_server = false; + s->antispoof_prompt->name = dupstr("Authentication successful"); + add_prompt( + s->antispoof_prompt, + dupstr("Access granted. Press Return to begin session. "), false); + s->antispoof_ret = seat_get_userpass_input( + s->ppl.seat, s->antispoof_prompt, NULL); + while (1) { + while (s->antispoof_ret < 0 && + bufchain_size(s->ppl.user_input) > 0) + s->antispoof_ret = seat_get_userpass_input( + s->ppl.seat, s->antispoof_prompt, s->ppl.user_input); + + if (s->antispoof_ret >= 0) + break; + + s->want_user_input = true; + crReturnV; + s->want_user_input = false; + } + free_prompts(s->antispoof_prompt); + s->antispoof_prompt = NULL; + } + portfwdmgr_config(s->portfwdmgr, s->conf); s->portfwdmgr_configured = true; diff --git a/ssh1connection.h b/ssh1connection.h index 0e5a71fd..1ee5465d 100644 --- a/ssh1connection.h +++ b/ssh1connection.h @@ -52,6 +52,9 @@ struct ssh1_connection_state { bool compressing; /* used in server mode only */ bool sent_exit_status; /* also for server mode */ + prompts_t *antispoof_prompt; + int antispoof_ret; + const SshServerConfig *ssc; ConnectionLayer cl; @@ -120,3 +123,5 @@ bool ssh1_handle_direction_specific_packet( struct ssh1_connection_state *s, PktIn *pktin); bool ssh1_check_termination(struct ssh1_connection_state *s); + +bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s);