From 44272b53552100d6b562f351e9567aff5997c33a Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 29 Apr 2023 11:35:20 +0100 Subject: [PATCH] Packet protocol layers: new 'final_output' method. This is called just before closing the connection, and gives every PPL one last chance to output anything to the user that it might have buffered. No functional change: all implementations so far are trivial, except that the transport layer passes the call on to its higher layer (because otherwise nothing would do so). (cherry picked from commit d6e6919f69c29cf4d2a0f19fc1c6eab51ba1ac61) --- ssh/common.c | 4 ++++ ssh/connection1.c | 1 + ssh/connection2.c | 1 + ssh/login1-server.c | 1 + ssh/login1.c | 1 + ssh/ppl.h | 6 ++++++ ssh/ssh.c | 10 ++++++++++ ssh/transport2.c | 10 ++++++++++ ssh/userauth2-client.c | 1 + ssh/userauth2-server.c | 1 + 10 files changed, 36 insertions(+) diff --git a/ssh/common.c b/ssh/common.c index 02bf7322..ad2d4632 100644 --- a/ssh/common.c +++ b/ssh/common.c @@ -742,6 +742,10 @@ size_t ssh_ppl_default_queued_data_size(PacketProtocolLayer *ppl) return ppl->out_pq->pqb.total_size; } +void ssh_ppl_default_final_output(PacketProtocolLayer *ppl) +{ +} + static void ssh_ppl_prompts_callback(void *ctx) { ssh_ppl_process_queue((PacketProtocolLayer *)ctx); diff --git a/ssh/connection1.c b/ssh/connection1.c index 0b5485f8..7204450a 100644 --- a/ssh/connection1.c +++ b/ssh/connection1.c @@ -40,6 +40,7 @@ static const PacketProtocolLayerVtable ssh1_connection_vtable = { .special_cmd = ssh1_connection_special_cmd, .reconfigure = ssh1_connection_reconfigure, .queued_data_size = ssh_ppl_default_queued_data_size, + .final_output = ssh_ppl_default_final_output, .name = NULL, /* no layer names in SSH-1 */ }; diff --git a/ssh/connection2.c b/ssh/connection2.c index 77b8d0ec..b08dab5f 100644 --- a/ssh/connection2.c +++ b/ssh/connection2.c @@ -27,6 +27,7 @@ static const PacketProtocolLayerVtable ssh2_connection_vtable = { .special_cmd = ssh2_connection_special_cmd, .reconfigure = ssh2_connection_reconfigure, .queued_data_size = ssh_ppl_default_queued_data_size, + .final_output = ssh_ppl_default_final_output, .name = "ssh-connection", }; diff --git a/ssh/login1-server.c b/ssh/login1-server.c index d01c7f4c..661a4a17 100644 --- a/ssh/login1-server.c +++ b/ssh/login1-server.c @@ -61,6 +61,7 @@ static const PacketProtocolLayerVtable ssh1_login_server_vtable = { .special_cmd = ssh1_login_server_special_cmd, .reconfigure = ssh1_login_server_reconfigure, .queued_data_size = ssh_ppl_default_queued_data_size, + .final_output = ssh_ppl_default_final_output, .name = NULL, /* no layer names in SSH-1 */ }; diff --git a/ssh/login1.c b/ssh/login1.c index 52aaea0b..aa731848 100644 --- a/ssh/login1.c +++ b/ssh/login1.c @@ -81,6 +81,7 @@ static const PacketProtocolLayerVtable ssh1_login_vtable = { .special_cmd = ssh1_login_special_cmd, .reconfigure = ssh1_login_reconfigure, .queued_data_size = ssh_ppl_default_queued_data_size, + .final_output = ssh_ppl_default_final_output, .name = NULL, /* no layer names in SSH-1 */ }; diff --git a/ssh/ppl.h b/ssh/ppl.h index 78b08efa..cb9e044d 100644 --- a/ssh/ppl.h +++ b/ssh/ppl.h @@ -19,6 +19,7 @@ struct PacketProtocolLayerVtable { PacketProtocolLayer *ppl, SessionSpecialCode code, int arg); void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf); size_t (*queued_data_size)(PacketProtocolLayer *ppl); + void (*final_output)(PacketProtocolLayer *ppl); /* Protocol-level name of this layer. */ const char *name; @@ -68,6 +69,8 @@ static inline void ssh_ppl_reconfigure(PacketProtocolLayer *ppl, Conf *conf) { ppl->vt->reconfigure(ppl, conf); } static inline size_t ssh_ppl_queued_data_size(PacketProtocolLayer *ppl) { return ppl->vt->queued_data_size(ppl); } +static inline void ssh_ppl_final_output(PacketProtocolLayer *ppl) +{ ppl->vt->final_output(ppl); } static inline InteractionReadySeat ppl_get_iseat(PacketProtocolLayer *ppl) { return interactor_announce(ppl->interactor); } @@ -93,6 +96,9 @@ void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new); * has other things to take into account as well. */ size_t ssh_ppl_default_queued_data_size(PacketProtocolLayer *ppl); +/* Default implementation of final_output which outputs nothing. */ +void ssh_ppl_default_final_output(PacketProtocolLayer *ppl); + PacketProtocolLayer *ssh1_login_new( Conf *conf, const char *host, int port, PacketProtocolLayer *successor_layer); diff --git a/ssh/ssh.c b/ssh/ssh.c index 6944e4c2..0af5668c 100644 --- a/ssh/ssh.c +++ b/ssh/ssh.c @@ -474,6 +474,8 @@ void ssh_remote_error(Ssh *ssh, const char *fmt, ...) if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; + ssh_ppl_final_output(ssh->base_layer); + /* Error messages sent by the remote don't count as clean exits */ ssh->exitcode = 128; @@ -492,6 +494,8 @@ void ssh_remote_eof(Ssh *ssh, const char *fmt, ...) if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; + ssh_ppl_final_output(ssh->base_layer); + /* EOF from the remote, if we were expecting it, does count as * a clean exit */ ssh->exitcode = 0; @@ -515,6 +519,8 @@ void ssh_proto_error(Ssh *ssh, const char *fmt, ...) if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; + ssh_ppl_final_output(ssh->base_layer); + ssh->exitcode = 128; ssh_bpp_queue_disconnect(ssh->bpp, msg, @@ -532,6 +538,8 @@ void ssh_sw_abort(Ssh *ssh, const char *fmt, ...) if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; + ssh_ppl_final_output(ssh->base_layer); + ssh->exitcode = 128; ssh_initiate_connection_close(ssh); @@ -549,6 +557,8 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...) if (ssh->base_layer || !ssh->session_started) { GET_FORMATTED_MSG; + ssh_ppl_final_output(ssh->base_layer); + /* Closing the connection due to user action, even if the * action is the user aborting during authentication prompts, * does count as a clean exit - except that this is also how diff --git a/ssh/transport2.c b/ssh/transport2.c index 96310e7d..d1c255fc 100644 --- a/ssh/transport2.c +++ b/ssh/transport2.c @@ -80,6 +80,7 @@ static size_t ssh2_transport_queued_data_size(PacketProtocolLayer *ppl); static void ssh2_transport_set_max_data_size(struct ssh2_transport_state *s); static unsigned long sanitise_rekey_time(int rekey_time, unsigned long def); static void ssh2_transport_higher_layer_packet_callback(void *context); +static void ssh2_transport_final_output(PacketProtocolLayer *ppl); static const PacketProtocolLayerVtable ssh2_transport_vtable = { .free = ssh2_transport_free, @@ -88,6 +89,7 @@ static const PacketProtocolLayerVtable ssh2_transport_vtable = { .special_cmd = ssh2_transport_special_cmd, .reconfigure = ssh2_transport_reconfigure, .queued_data_size = ssh2_transport_queued_data_size, + .final_output = ssh2_transport_final_output, .name = NULL, /* no protocol name for this layer */ }; @@ -2406,3 +2408,11 @@ static size_t ssh2_transport_queued_data_size(PacketProtocolLayer *ppl) return (ssh_ppl_default_queued_data_size(ppl) + ssh_ppl_queued_data_size(s->higher_layer)); } + +static void ssh2_transport_final_output(PacketProtocolLayer *ppl) +{ + struct ssh2_transport_state *s = + container_of(ppl, struct ssh2_transport_state, ppl); + + ssh_ppl_final_output(s->higher_layer); +} diff --git a/ssh/userauth2-client.c b/ssh/userauth2-client.c index b7e36371..9b10a85b 100644 --- a/ssh/userauth2-client.c +++ b/ssh/userauth2-client.c @@ -140,6 +140,7 @@ static const PacketProtocolLayerVtable ssh2_userauth_vtable = { .special_cmd = ssh2_userauth_special_cmd, .reconfigure = ssh2_userauth_reconfigure, .queued_data_size = ssh_ppl_default_queued_data_size, + .final_output = ssh_ppl_default_final_output, .name = "ssh-userauth", }; diff --git a/ssh/userauth2-server.c b/ssh/userauth2-server.c index bfe258ce..7e231a8e 100644 --- a/ssh/userauth2-server.c +++ b/ssh/userauth2-server.c @@ -42,6 +42,7 @@ static const PacketProtocolLayerVtable ssh2_userauth_server_vtable = { .free = ssh2_userauth_server_free, .process_queue = ssh2_userauth_server_process_queue, .queued_data_size = ssh_ppl_default_queued_data_size, + .final_output = ssh_ppl_default_final_output, .name = "ssh-userauth", /* other methods are NULL */ };