浏览代码

Merge branch 'thirdparty_dev' into dev

# Conflicts:

#	source/putty/ssh/connection2.c
#	source/putty/ssh/ppl.h
#	source/putty/ssh/transport2.c
#	source/putty/ssh/userauth2-client.c

Source commit: 84a1449cae5af55c4a6671f80e82114fc0adc781
Martin Prikryl 2 年之前
父节点
当前提交
281f907939

+ 16 - 0
source/putty/crypto/hmac.c

@@ -167,6 +167,22 @@ static const char *hmac_text_name(ssh2_mac *mac)
     return ctx->text_name->s;
     return ctx->text_name->s;
 }
 }
 
 
+static const struct hmac_extra ssh_hmac_sha512_extra = { &ssh_sha512, "" };
+const ssh2_macalg ssh_hmac_sha512 = {
+    .new = hmac_new,
+    .free = hmac_free,
+    .setkey = hmac_key,
+    .start = hmac_start,
+    .genresult = hmac_genresult,
+    .next_message = nullmac_next_message,
+    .text_name = hmac_text_name,
+    .name = "hmac-sha2-512",
+    .etm_name = "[email protected]",
+    .len = 64,
+    .keylen = 64,
+    .extra = &ssh_hmac_sha512_extra,
+};
+
 static const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, "" };
 static const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, "" };
 const ssh2_macalg ssh_hmac_sha256 = {
 const ssh2_macalg ssh_hmac_sha256 = {
     // WINSCP
     // WINSCP

+ 4 - 2
source/putty/crypto/openssh-certs.c

@@ -1094,12 +1094,14 @@ static bool opensshcert_check_cert(
      */
      */
     if (time < ck->valid_after) {
     if (time < ck->valid_after) {
         put_fmt(error, "Certificate is not valid until ");
         put_fmt(error, "Certificate is not valid until ");
-        opensshcert_time_to_iso8601(BinarySink_UPCAST(error), time);
+        opensshcert_time_to_iso8601(BinarySink_UPCAST(error),
+                                    ck->valid_after);
         goto out;
         goto out;
     }
     }
     if (time >= ck->valid_before) {
     if (time >= ck->valid_before) {
         put_fmt(error, "Certificate expired at ");
         put_fmt(error, "Certificate expired at ");
-        opensshcert_time_to_iso8601(BinarySink_UPCAST(error), time);
+        opensshcert_time_to_iso8601(BinarySink_UPCAST(error),
+                                    ck->valid_before);
         goto out;
         goto out;
     }
     }
 
 

+ 3 - 2
source/putty/putty.h

@@ -363,11 +363,12 @@ typedef enum {
     MBT_NOTHING,
     MBT_NOTHING,
     MBT_LEFT, MBT_MIDDLE, MBT_RIGHT,   /* `raw' button designations */
     MBT_LEFT, MBT_MIDDLE, MBT_RIGHT,   /* `raw' button designations */
     MBT_SELECT, MBT_EXTEND, MBT_PASTE, /* `cooked' button designations */
     MBT_SELECT, MBT_EXTEND, MBT_PASTE, /* `cooked' button designations */
-    MBT_WHEEL_UP, MBT_WHEEL_DOWN       /* mouse wheel */
+    MBT_WHEEL_UP, MBT_WHEEL_DOWN,      /* vertical mouse wheel */
+    MBT_WHEEL_LEFT, MBT_WHEEL_RIGHT    /* horizontal mouse wheel */
 } Mouse_Button;
 } Mouse_Button;
 
 
 typedef enum {
 typedef enum {
-    MA_NOTHING, MA_CLICK, MA_2CLK, MA_3CLK, MA_DRAG, MA_RELEASE
+    MA_NOTHING, MA_CLICK, MA_2CLK, MA_3CLK, MA_DRAG, MA_RELEASE, MA_MOVE
 } Mouse_Action;
 } Mouse_Action;
 
 
 /* Keyboard modifiers -- keys the user is actually holding down */
 /* Keyboard modifiers -- keys the user is actually holding down */

+ 6 - 6
source/putty/settings.c

@@ -686,12 +686,12 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
     write_setting_b(sesskey, "BellOverload", conf_get_bool(conf, CONF_bellovl));
     write_setting_b(sesskey, "BellOverload", conf_get_bool(conf, CONF_bellovl));
     write_setting_i(sesskey, "BellOverloadN", conf_get_int(conf, CONF_bellovl_n));
     write_setting_i(sesskey, "BellOverloadN", conf_get_int(conf, CONF_bellovl_n));
     write_setting_i(sesskey, "BellOverloadT", conf_get_int(conf, CONF_bellovl_t)
     write_setting_i(sesskey, "BellOverloadT", conf_get_int(conf, CONF_bellovl_t)
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                     * 1000
                     * 1000
 #endif
 #endif
                     );
                     );
     write_setting_i(sesskey, "BellOverloadS", conf_get_int(conf, CONF_bellovl_s)
     write_setting_i(sesskey, "BellOverloadS", conf_get_int(conf, CONF_bellovl_s)
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                     * 1000
                     * 1000
 #endif
 #endif
                     );
                     );
@@ -1122,22 +1122,22 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
     gppb(sesskey, "BellOverload", true, conf, CONF_bellovl);
     gppb(sesskey, "BellOverload", true, conf, CONF_bellovl);
     gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n);
     gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n);
     i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC
     i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                                    *1000
                                    *1000
 #endif
 #endif
                                    );
                                    );
     conf_set_int(conf, CONF_bellovl_t, i
     conf_set_int(conf, CONF_bellovl_t, i
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                  / 1000
                  / 1000
 #endif
 #endif
                  );
                  );
     i = gppi_raw(sesskey, "BellOverloadS", 5*TICKSPERSEC
     i = gppi_raw(sesskey, "BellOverloadS", 5*TICKSPERSEC
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                                    *1000
                                    *1000
 #endif
 #endif
                                    );
                                    );
     conf_set_int(conf, CONF_bellovl_s, i
     conf_set_int(conf, CONF_bellovl_s, i
-#ifdef PUTTY_UNIX_H
+#ifdef PUTTY_UNIX_PLATFORM_H
                  / 1000
                  / 1000
 #endif
 #endif
                  );
                  );

+ 1 - 0
source/putty/ssh.h

@@ -1241,6 +1241,7 @@ extern const ssh2_macalg ssh_hmac_sha1_buggy;
 extern const ssh2_macalg ssh_hmac_sha1_96;
 extern const ssh2_macalg ssh_hmac_sha1_96;
 extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
 extern const ssh2_macalg ssh_hmac_sha1_96_buggy;
 extern const ssh2_macalg ssh_hmac_sha256;
 extern const ssh2_macalg ssh_hmac_sha256;
+extern const ssh2_macalg ssh_hmac_sha512;
 extern const ssh2_macalg ssh2_poly1305;
 extern const ssh2_macalg ssh2_poly1305;
 #endif
 #endif
 extern const ssh2_macalg ssh2_aesgcm_mac;
 extern const ssh2_macalg ssh2_aesgcm_mac;

+ 10 - 0
source/putty/ssh/common_p.c

@@ -769,6 +769,10 @@ size_t ssh_ppl_default_queued_data_size(PacketProtocolLayer *ppl)
     return ppl->out_pq->pqb.total_size;
     return ppl->out_pq->pqb.total_size;
 }
 }
 
 
+void ssh_ppl_default_final_output(PacketProtocolLayer *ppl)
+{
+}
+
 static void ssh_ppl_prompts_callback(void *ctx)
 static void ssh_ppl_prompts_callback(void *ctx)
 {
 {
     ssh_ppl_process_queue((PacketProtocolLayer *)ctx);
     ssh_ppl_process_queue((PacketProtocolLayer *)ctx);
@@ -1062,6 +1066,12 @@ SeatPromptResult verify_ssh_host_key(
             text, SDT_PARA, "If you trust this host, %s to add the key to "
             text, SDT_PARA, "If you trust this host, %s to add the key to "
             "%s's cache and carry on connecting.",
             "%s's cache and carry on connecting.",
             pds->hk_accept_action, appname);
             pds->hk_accept_action, appname);
+        if (key && ssh_key_alg(key)->is_certificate) {
+            seat_dialog_text_append(
+                text, SDT_PARA, "(Storing this certified key in the cache "
+                "will NOT cause its certification authority to be trusted "
+                "for any other key or host.)");
+        }
         seat_dialog_text_append(
         seat_dialog_text_append(
             text, SDT_PARA, "If you want to carry on connecting just once, "
             text, SDT_PARA, "If you want to carry on connecting just once, "
             "without adding the key to the cache, %s.",
             "without adding the key to the cache, %s.",

+ 1 - 0
source/putty/ssh/connection2.c

@@ -31,6 +31,7 @@ static const PacketProtocolLayerVtable ssh2_connection_vtable = {
     /*.special_cmd =*/ ssh2_connection_special_cmd,
     /*.special_cmd =*/ ssh2_connection_special_cmd,
     /*.reconfigure =*/ ssh2_connection_reconfigure,
     /*.reconfigure =*/ ssh2_connection_reconfigure,
     /*.queued_data_size =*/ ssh_ppl_default_queued_data_size,
     /*.queued_data_size =*/ ssh_ppl_default_queued_data_size,
+    /*.final_output =*/ ssh_ppl_default_final_output,
     /*.name =*/ "ssh-connection",
     /*.name =*/ "ssh-connection",
     ssh2_connection_winscp_query,
     ssh2_connection_winscp_query,
 };
 };

+ 6 - 0
source/putty/ssh/ppl.h

@@ -19,6 +19,7 @@ struct PacketProtocolLayerVtable {
         PacketProtocolLayer *ppl, SessionSpecialCode code, int arg);
         PacketProtocolLayer *ppl, SessionSpecialCode code, int arg);
     void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf);
     void (*reconfigure)(PacketProtocolLayer *ppl, Conf *conf);
     size_t (*queued_data_size)(PacketProtocolLayer *ppl);
     size_t (*queued_data_size)(PacketProtocolLayer *ppl);
+    void (*final_output)(PacketProtocolLayer *ppl);
 
 
     /* Protocol-level name of this layer. */
     /* Protocol-level name of this layer. */
     const char *name;
     const char *name;
@@ -70,6 +71,8 @@ static inline void ssh_ppl_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
 { ppl->vt->reconfigure(ppl, conf); }
 { ppl->vt->reconfigure(ppl, conf); }
 static inline size_t ssh_ppl_queued_data_size(PacketProtocolLayer *ppl)
 static inline size_t ssh_ppl_queued_data_size(PacketProtocolLayer *ppl)
 { return ppl->vt->queued_data_size(ppl); }
 { return ppl->vt->queued_data_size(ppl); }
+static inline void ssh_ppl_final_output(PacketProtocolLayer *ppl)
+{ ppl->vt->final_output(ppl); }
 static inline unsigned int ssh_ppl_winscp_query(PacketProtocolLayer *ppl, int query)
 static inline unsigned int ssh_ppl_winscp_query(PacketProtocolLayer *ppl, int query)
 { return ppl->vt->winscp_query(ppl, query); }
 { return ppl->vt->winscp_query(ppl, query); }
 
 
@@ -97,6 +100,9 @@ void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new);
  * has other things to take into account as well. */
  * has other things to take into account as well. */
 size_t ssh_ppl_default_queued_data_size(PacketProtocolLayer *ppl);
 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(
 PacketProtocolLayer *ssh1_login_new(
     Conf *conf, const char *host, int port,
     Conf *conf, const char *host, int port,
     PacketProtocolLayer *successor_layer);
     PacketProtocolLayer *successor_layer);

+ 17 - 1
source/putty/ssh/ssh.c

@@ -468,6 +468,9 @@ void ssh_remote_error(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
         GET_FORMATTED_MSG;
 
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         /* Error messages sent by the remote don't count as clean exits */
         /* Error messages sent by the remote don't count as clean exits */
         ssh->exitcode = 128;
         ssh->exitcode = 128;
 
 
@@ -486,6 +489,9 @@ void ssh_remote_eof(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
         GET_FORMATTED_MSG;
 
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         /* EOF from the remote, if we were expecting it, does count as
         /* EOF from the remote, if we were expecting it, does count as
          * a clean exit */
          * a clean exit */
         ssh->exitcode = 0;
         ssh->exitcode = 0;
@@ -509,6 +515,9 @@ void ssh_proto_error(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
         GET_FORMATTED_MSG;
 
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         ssh->exitcode = 128;
         ssh->exitcode = 128;
 
 
         ssh_bpp_queue_disconnect(ssh->bpp, msg,
         ssh_bpp_queue_disconnect(ssh->bpp, msg,
@@ -526,6 +535,9 @@ void ssh_sw_abort(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
         GET_FORMATTED_MSG;
 
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         ssh->exitcode = 128;
         ssh->exitcode = 128;
 
 
         ssh_initiate_connection_close(ssh);
         ssh_initiate_connection_close(ssh);
@@ -543,6 +555,9 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...)
     if (ssh->base_layer || !ssh->session_started) {
     if (ssh->base_layer || !ssh->session_started) {
         GET_FORMATTED_MSG;
         GET_FORMATTED_MSG;
 
 
+        if (ssh->base_layer)
+            ssh_ppl_final_output(ssh->base_layer);
+
         /* Closing the connection due to user action, even if the
         /* Closing the connection due to user action, even if the
          * action is the user aborting during authentication prompts,
          * action is the user aborting during authentication prompts,
          * does count as a clean exit - except that this is also how
          * does count as a clean exit - except that this is also how
@@ -1049,7 +1064,8 @@ static void ssh_reconfig(Backend *be, Conf *conf)
     if (ssh->pinger)
     if (ssh->pinger)
         pinger_reconfig(ssh->pinger, ssh->conf, conf);
         pinger_reconfig(ssh->pinger, ssh->conf, conf);
 
 
-    ssh_ppl_reconfigure(ssh->base_layer, conf);
+    if (ssh->base_layer)
+        ssh_ppl_reconfigure(ssh->base_layer, conf);
 
 
     conf_free(ssh->conf);
     conf_free(ssh->conf);
     ssh->conf = conf_copy(conf);
     ssh->conf = conf_copy(conf);

+ 12 - 1
source/putty/ssh/transport2.c

@@ -22,7 +22,8 @@ const struct ssh_signkey_with_user_pref_id ssh2_hostkey_algs[] = {
 };
 };
 
 
 const static ssh2_macalg *const macs[] = {
 const static ssh2_macalg *const macs[] = {
-    &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
+    &ssh_hmac_sha256, &ssh_hmac_sha512,
+    &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
 };
 };
 const static ssh2_macalg *const buggymacs[] = {
 const static ssh2_macalg *const buggymacs[] = {
     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
     &ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
@@ -82,6 +83,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 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 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_higher_layer_packet_callback(void *context);
+static void ssh2_transport_final_output(PacketProtocolLayer *ppl);
 static unsigned int ssh2_transport_winscp_query(PacketProtocolLayer *ppl, int query);
 static unsigned int ssh2_transport_winscp_query(PacketProtocolLayer *ppl, int query);
 
 
 static const PacketProtocolLayerVtable ssh2_transport_vtable = {
 static const PacketProtocolLayerVtable ssh2_transport_vtable = {
@@ -92,6 +94,7 @@ static const PacketProtocolLayerVtable ssh2_transport_vtable = {
     /*.special_cmd =*/ ssh2_transport_special_cmd,
     /*.special_cmd =*/ ssh2_transport_special_cmd,
     /*.reconfigure =*/ ssh2_transport_reconfigure,
     /*.reconfigure =*/ ssh2_transport_reconfigure,
     /*.queued_data_size =*/ ssh2_transport_queued_data_size,
     /*.queued_data_size =*/ ssh2_transport_queued_data_size,
+    /*.final_output =*/ ssh2_transport_final_output,
     /*.name =*/ NULL, /* no protocol name for this layer */
     /*.name =*/ NULL, /* no protocol name for this layer */
     ssh2_transport_winscp_query,
     ssh2_transport_winscp_query,
 };
 };
@@ -2450,6 +2453,14 @@ static size_t ssh2_transport_queued_data_size(PacketProtocolLayer *ppl)
             ssh_ppl_queued_data_size(s->higher_layer));
             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);
+}
+
 #include "puttyexp.h"
 #include "puttyexp.h"
 
 
 static unsigned int ssh2_transport_winscp_query(PacketProtocolLayer *ppl, int query)
 static unsigned int ssh2_transport_winscp_query(PacketProtocolLayer *ppl, int query)

+ 83 - 50
source/putty/ssh/userauth2-client.c

@@ -136,7 +136,9 @@ static bool ssh2_userauth_ki_setup_prompts(
 static bool ssh2_userauth_ki_run_prompts(struct ssh2_userauth_state *s);
 static bool ssh2_userauth_ki_run_prompts(struct ssh2_userauth_state *s);
 static void ssh2_userauth_ki_write_responses(
 static void ssh2_userauth_ki_write_responses(
     struct ssh2_userauth_state *s, BinarySink *bs);
     struct ssh2_userauth_state *s, BinarySink *bs);
+static void ssh2_userauth_final_output(PacketProtocolLayer *ppl);
 
 
+static void ssh2_userauth_print_banner(struct ssh2_userauth_state *s);
 static ptrlen workaround_rsa_sha2_cert_userauth(
 static ptrlen workaround_rsa_sha2_cert_userauth(
     struct ssh2_userauth_state *s, ptrlen id);
     struct ssh2_userauth_state *s, ptrlen id);
 
 
@@ -148,6 +150,7 @@ static const PacketProtocolLayerVtable ssh2_userauth_vtable = {
     /*.special_cmd =*/ ssh2_userauth_special_cmd,
     /*.special_cmd =*/ ssh2_userauth_special_cmd,
     /*.reconfigure =*/ ssh2_userauth_reconfigure,
     /*.reconfigure =*/ ssh2_userauth_reconfigure,
     /*.queued_data_size =*/ ssh_ppl_default_queued_data_size,
     /*.queued_data_size =*/ ssh_ppl_default_queued_data_size,
+    /*.final_output =*/ ssh2_userauth_final_output,
     /*.name =*/ "ssh-userauth",
     /*.name =*/ "ssh-userauth",
     NULL, // WINSCP
     NULL, // WINSCP
 };
 };
@@ -255,33 +258,38 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
     sfree(s);
     sfree(s);
 }
 }
 
 
+static void ssh2_userauth_handle_banner_packet(struct ssh2_userauth_state *s,
+                                               PktIn *pktin)
+{
+    if (!s->show_banner)
+        return;
+
+    ptrlen string = get_string(pktin);
+    if (string.len > BANNER_LIMIT - bufchain_size(&s->banner))
+        string.len = BANNER_LIMIT - bufchain_size(&s->banner);
+
+    if (!s->banner_scc_initialised) {
+        s->banner_scc = seat_stripctrl_new(
+            s->ppl.seat, BinarySink_UPCAST(&s->banner_bs), SIC_BANNER);
+        if (s->banner_scc)
+            stripctrl_enable_line_limiting(s->banner_scc);
+        s->banner_scc_initialised = true;
+    }
+
+    if (s->banner_scc)
+        put_datapl(s->banner_scc, string);
+    else
+        put_datapl(&s->banner_bs, string);
+}
+
 static void ssh2_userauth_filter_queue(struct ssh2_userauth_state *s)
 static void ssh2_userauth_filter_queue(struct ssh2_userauth_state *s)
 {
 {
     PktIn *pktin;
     PktIn *pktin;
-    ptrlen string;
 
 
     while ((pktin = pq_peek(s->ppl.in_pq)) != NULL) {
     while ((pktin = pq_peek(s->ppl.in_pq)) != NULL) {
         switch (pktin->type) {
         switch (pktin->type) {
           case SSH2_MSG_USERAUTH_BANNER:
           case SSH2_MSG_USERAUTH_BANNER:
-            if (!s->show_banner) {
-                pq_pop(s->ppl.in_pq);
-                break;
-            }
-
-            string = get_string(pktin);
-            if (string.len > BANNER_LIMIT - bufchain_size(&s->banner))
-                string.len = BANNER_LIMIT - bufchain_size(&s->banner);
-            if (!s->banner_scc_initialised) {
-                s->banner_scc = seat_stripctrl_new(
-                    s->ppl.seat, BinarySink_UPCAST(&s->banner_bs), SIC_BANNER);
-                if (s->banner_scc)
-                    stripctrl_enable_line_limiting(s->banner_scc);
-                s->banner_scc_initialised = true;
-            }
-            if (s->banner_scc)
-                put_datapl(s->banner_scc, string);
-            else
-                put_datapl(&s->banner_bs, string);
+            ssh2_userauth_handle_banner_packet(s, pktin);
             pq_pop(s->ppl.in_pq);
             pq_pop(s->ppl.in_pq);
             break;
             break;
 
 
@@ -875,37 +883,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
              * point, but we still need to precede and follow it with
              * point, but we still need to precede and follow it with
              * anti-spoofing header lines.
              * anti-spoofing header lines.
              */
              */
-            if (bufchain_size(&s->banner) &&
-                (seat_verbose(s->ppl.seat) || seat_interactive(s->ppl.seat))) {
-                if (s->banner_scc) {
-                    seat_antispoof_msg(
-                        ppl_get_iseat(&s->ppl),
-                        "Pre-authentication banner message from server:");
-                    seat_set_trust_status(s->ppl.seat, false);
-                }
-
+            ssh2_userauth_print_banner(s);
                 { // WINSCP
                 { // WINSCP
-                bool mid_line = false;
-                while (bufchain_size(&s->banner) > 0) {
-                    ptrlen data = bufchain_prefix(&s->banner);
-                    seat_banner_pl(ppl_get_iseat(&s->ppl), data);
-                    mid_line =
-                        (((const char *)data.ptr)[data.len-1] != '\n');
-                    bufchain_consume(&s->banner, data.len);
-                }
-                bufchain_clear(&s->banner);
-
-                if (mid_line)
-                    seat_banner_pl(ppl_get_iseat(&s->ppl),
-                                   PTRLEN_LITERAL("\r\n"));
-
-                if (s->banner_scc) {
-                    seat_set_trust_status(s->ppl.seat, true);
-                    seat_antispoof_msg(ppl_get_iseat(&s->ppl),
-                                       "End of banner message from server");
-                }
                 } // WINSCP
                 } // WINSCP
-            }
 
 
             if (pktin && pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
             if (pktin && pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {
                 ppl_logevent("Access granted");
                 ppl_logevent("Access granted");
@@ -2169,6 +2149,39 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
     crFinishV;
     crFinishV;
 }
 }
 
 
+static void ssh2_userauth_print_banner(struct ssh2_userauth_state *s)
+{
+    if (bufchain_size(&s->banner) &&
+        (seat_verbose(s->ppl.seat) || seat_interactive(s->ppl.seat))) {
+        if (s->banner_scc) {
+            seat_antispoof_msg(
+                ppl_get_iseat(&s->ppl),
+                "Pre-authentication banner message from server:");
+            seat_set_trust_status(s->ppl.seat, false);
+        }
+
+        bool mid_line = false;
+        while (bufchain_size(&s->banner) > 0) {
+            ptrlen data = bufchain_prefix(&s->banner);
+            seat_banner_pl(ppl_get_iseat(&s->ppl), data);
+            mid_line =
+                (((const char *)data.ptr)[data.len-1] != '\n');
+            bufchain_consume(&s->banner, data.len);
+        }
+        bufchain_clear(&s->banner);
+
+        if (mid_line)
+            seat_banner_pl(ppl_get_iseat(&s->ppl),
+                           PTRLEN_LITERAL("\r\n"));
+
+        if (s->banner_scc) {
+            seat_set_trust_status(s->ppl.seat, true);
+            seat_antispoof_msg(ppl_get_iseat(&s->ppl),
+                               "End of banner message from server");
+        }
+    }
+}
+
 static bool ssh2_userauth_ki_setup_prompts(
 static bool ssh2_userauth_ki_setup_prompts(
     struct ssh2_userauth_state *s, BinarySource *src, bool plugin)
     struct ssh2_userauth_state *s, BinarySource *src, bool plugin)
 {
 {
@@ -2537,7 +2550,7 @@ static ptrlen workaround_rsa_sha2_cert_userauth(
 {
 {
     if (!(s->ppl.remote_bugs & BUG_RSA_SHA2_CERT_USERAUTH))
     if (!(s->ppl.remote_bugs & BUG_RSA_SHA2_CERT_USERAUTH))
         return id;
         return id;
-/*
+    /*
      * No need to try to do this in a general way based on the
      * No need to try to do this in a general way based on the
      * relations between ssh_keyalgs; we know there are a limited
      * relations between ssh_keyalgs; we know there are a limited
      * number of affected versions of OpenSSH, so this doesn't have to
      * number of affected versions of OpenSSH, so this doesn't have to
@@ -2677,3 +2690,23 @@ static void ssh2_userauth_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
         container_of(ppl, struct ssh2_userauth_state, ppl);
         container_of(ppl, struct ssh2_userauth_state, ppl);
     ssh_ppl_reconfigure(s->successor_layer, conf);
     ssh_ppl_reconfigure(s->successor_layer, conf);
 }
 }
+
+static void ssh2_userauth_final_output(PacketProtocolLayer *ppl)
+{
+    struct ssh2_userauth_state *s =
+        container_of(ppl, struct ssh2_userauth_state, ppl);
+
+    /*
+     * Check for any unconsumed banner packets that might have landed
+     * in our queue just before the server closed the connection, and
+     * add them to our banner buffer.
+     */
+    for (PktIn *pktin = pq_first(s->ppl.in_pq); pktin != NULL;
+         pktin = pq_next(s->ppl.in_pq, pktin)) {
+        if (pktin->type == SSH2_MSG_USERAUTH_BANNER)
+            ssh2_userauth_handle_banner_packet(s, pktin);
+    }
+
+    /* And now make sure we've shown the banner, before exiting */
+    ssh2_userauth_print_banner(s);
+}

+ 1 - 9
source/putty/sshpubk.c

@@ -566,24 +566,18 @@ static char *read_body(BinarySource *src)
 
 
 static bool read_blob(BinarySource *src, int nlines, BinarySink *bs)
 static bool read_blob(BinarySource *src, int nlines, BinarySink *bs)
 {
 {
-    unsigned char *blob;
     char *line;
     char *line;
     int linelen;
     int linelen;
     int i, j, k;
     int i, j, k;
 
 
     /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
     /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
-    assert(nlines < MAX_KEY_BLOB_LINES);
-    blob = snewn(48 * nlines, unsigned char);
 
 
     for (i = 0; i < nlines; i++) {
     for (i = 0; i < nlines; i++) {
         line = read_body(src);
         line = read_body(src);
-        if (!line) {
-            sfree(blob);
+        if (!line)
             return false;
             return false;
-        }
         linelen = strlen(line);
         linelen = strlen(line);
         if (linelen % 4 != 0 || linelen > 64) {
         if (linelen % 4 != 0 || linelen > 64) {
-            sfree(blob);
             sfree(line);
             sfree(line);
             return false;
             return false;
         }
         }
@@ -592,14 +586,12 @@ static bool read_blob(BinarySource *src, int nlines, BinarySink *bs)
             k = base64_decode_atom(line + j, decoded);
             k = base64_decode_atom(line + j, decoded);
             if (!k) {
             if (!k) {
                 sfree(line);
                 sfree(line);
-                sfree(blob);
                 return false;
                 return false;
             }
             }
             put_data(bs, decoded, k);
             put_data(bs, decoded, k);
         }
         }
         sfree(line);
         sfree(line);
     }
     }
-    sfree(blob);
     return true;
     return true;
 }
 }
 
 

+ 4 - 4
source/putty/version.h

@@ -1,5 +1,5 @@
 /* Generated by automated build script */
 /* Generated by automated build script */
-#define RELEASE 0.78
-#define TEXTVER "Release 0.78"
-#define SSHVER "-Release-0.78"
-#define BINARY_VERSION 0,78,0,0
+#define PRERELEASE 0.79
+#define TEXTVER "Pre-release 0.79:2023-05-22.56b16bd"
+#define SSHVER "-Prerelease-0.79:20230522.56b16bd"
+#define BINARY_VERSION 0,78,33974,0

+ 6 - 4
source/putty/windows/unicode.c

@@ -1074,9 +1074,11 @@ static int check_compose_internal(int first, int second, int recurse)
     if (recurse == 0) {
     if (recurse == 0) {
         nc = check_compose_internal(second, first, 1);
         nc = check_compose_internal(second, first, 1);
         if (nc == -1)
         if (nc == -1)
-            nc = check_compose_internal(toupper(first), toupper(second), 1);
+            nc = check_compose_internal(toupper((unsigned char)first),
+                                        toupper((unsigned char)second), 1);
         if (nc == -1)
         if (nc == -1)
-            nc = check_compose_internal(toupper(second), toupper(first), 1);
+            nc = check_compose_internal(toupper((unsigned char)second),
+                                        toupper((unsigned char)first), 1);
     }
     }
     return nc;
     return nc;
 }
 }
@@ -1100,9 +1102,9 @@ int decode_codepage(const char *cp_name)
         s = cp_name;
         s = cp_name;
         d = cpi->name;
         d = cpi->name;
         for (;;) {
         for (;;) {
-            while (*s && !isalnum(*s) && *s != ':')
+            while (*s && !isalnum((unsigned char)*s) && *s != ':')
                 s++;
                 s++;
-            while (*d && !isalnum(*d) && *d != ':')
+            while (*d && !isalnum((unsigned char)*d) && *d != ':')
                 d++;
                 d++;
             if (*s == 0) {
             if (*s == 0) {
                 codepage = cpi->codepage;
                 codepage = cpi->codepage;