浏览代码

Updating code to PuTTY 2ca0070f (+ d624ae2a and fb07fccf)

Includes two additional later commits that are necessary for at least basic operation:
d624ae2a - Fix double-free bug in (non-EC) Diffie-Hellman
fb07fccf - Fix failure to handle SSH_MSG_EXTENDED_DATA

Source commit: 6713f7869e31b2cb3921400442300befebd3881a
Martin Prikryl 6 年之前
父节点
当前提交
a029c98fdf

+ 15 - 0
source/Putty.cbproj

@@ -162,6 +162,12 @@
 		<CppCompile Include="putty\ssh1censor.c">
 		<CppCompile Include="putty\ssh1censor.c">
 			<BuildOrder>57</BuildOrder>
 			<BuildOrder>57</BuildOrder>
 		</CppCompile>
 		</CppCompile>
+		<CppCompile Include="putty\ssh1connection.c">
+			<BuildOrder>64</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\ssh1login.c">
+			<BuildOrder>65</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\ssh2bpp.c">
 		<CppCompile Include="putty\ssh2bpp.c">
 			<BuildOrder>54</BuildOrder>
 			<BuildOrder>54</BuildOrder>
 		</CppCompile>
 		</CppCompile>
@@ -171,6 +177,15 @@
 		<CppCompile Include="putty\ssh2censor.c">
 		<CppCompile Include="putty\ssh2censor.c">
 			<BuildOrder>58</BuildOrder>
 			<BuildOrder>58</BuildOrder>
 		</CppCompile>
 		</CppCompile>
+		<CppCompile Include="putty\ssh2connection.c">
+			<BuildOrder>66</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\ssh2transport.c">
+			<BuildOrder>67</BuildOrder>
+		</CppCompile>
+		<CppCompile Include="putty\ssh2userauth.c">
+			<BuildOrder>68</BuildOrder>
+		</CppCompile>
 		<CppCompile Include="putty\sshaes.c">
 		<CppCompile Include="putty\sshaes.c">
 			<BuildOrder>26</BuildOrder>
 			<BuildOrder>26</BuildOrder>
 			<BuildOrder>22</BuildOrder>
 			<BuildOrder>22</BuildOrder>

+ 14 - 19
source/core/SecureShell.cpp

@@ -89,7 +89,6 @@ void __fastcall TSecureShell::ResetConnection()
 void __fastcall TSecureShell::ResetSessionInfo()
 void __fastcall TSecureShell::ResetSessionInfo()
 {
 {
   FSessionInfoValid = false;
   FSessionInfoValid = false;
-  FMaxPacketSize = NULL;
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 inline void __fastcall TSecureShell::UpdateSessionInfo()
 inline void __fastcall TSecureShell::UpdateSessionInfo()
@@ -571,7 +570,7 @@ void __fastcall TSecureShell::Init()
       // (see comment in putty revision 8110)
       // (see comment in putty revision 8110)
       // It seems that we do not need to do it.
       // It seems that we do not need to do it.
 
 
-      while (!get_ssh_state_session(FBackendHandle))
+      while (!winscp_query(FBackendHandle, WINSCP_QUERY_MAIN_CHANNEL))
       {
       {
         if (Configuration->ActualLogProtocol >= 1)
         if (Configuration->ActualLogProtocol >= 1)
         {
         {
@@ -579,9 +578,6 @@ void __fastcall TSecureShell::Init()
         }
         }
         WaitForData();
         WaitForData();
       }
       }
-
-      // unless this is tunnel session, it must be safe to send now
-      DebugAssert(FBackend->sendok(FBackendHandle) || !FSessionData->TunnelPortFwd.IsEmpty());
     }
     }
     catch(Exception & E)
     catch(Exception & E)
     {
     {
@@ -615,9 +611,9 @@ struct callback_set * TSecureShell::GetCallbackSet()
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TSecureShell::ConvertFromPutty(const char * Str, int Length)
 UnicodeString __fastcall TSecureShell::ConvertFromPutty(const char * Str, int Length)
 {
 {
-  int BomLength = strlen(MPEXT_BOM);
+  int BomLength = strlen(WINSCP_BOM);
   if ((Length >= BomLength) &&
   if ((Length >= BomLength) &&
-      (strncmp(Str, MPEXT_BOM, BomLength) == 0))
+      (strncmp(Str, WINSCP_BOM, BomLength) == 0))
   {
   {
     return UTF8ToString(Str + BomLength, Length - BomLength);
     return UTF8ToString(Str + BomLength, Length - BomLength);
   }
   }
@@ -1653,9 +1649,12 @@ void __fastcall TSecureShell::Close()
   LogEvent(L"Closing connection.");
   LogEvent(L"Closing connection.");
   DebugAssert(FActive);
   DebugAssert(FActive);
 
 
-  // this is particularly necessary when using local proxy command
-  // (e.g. plink), otherwise it hangs in sk_localproxy_close
-  SendEOF();
+  if (FBackend->exitcode(FBackendHandle) < 0)
+  {
+    // this is particularly necessary when using local proxy command
+    // (e.g. plink), otherwise it hangs in sk_localproxy_close
+    SendEOF();
+  }
 
 
   FreeBackend();
   FreeBackend();
 
 
@@ -1664,7 +1663,7 @@ void __fastcall TSecureShell::Close()
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void inline __fastcall TSecureShell::CheckConnection(int Message)
 void inline __fastcall TSecureShell::CheckConnection(int Message)
 {
 {
-  if (!FActive || get_ssh_state_closed(FBackendHandle))
+  if (!FActive || (FBackend->exitcode(FBackendHandle) >= 0))
   {
   {
     UnicodeString Str;
     UnicodeString Str;
     UnicodeString HelpKeyword;
     UnicodeString HelpKeyword;
@@ -1927,10 +1926,10 @@ bool __fastcall TSecureShell::EventSelectLoop(unsigned int MSec, bool ReadEventR
         // 1) Check for changes in our pending buffer - wait criteria in Receive()
         // 1) Check for changes in our pending buffer - wait criteria in Receive()
         int PrevDataLen = (-static_cast<int>(OutLen) + static_cast<int>(PendLen));
         int PrevDataLen = (-static_cast<int>(OutLen) + static_cast<int>(PendLen));
         // 2) Changes in session state - wait criteria in Init()
         // 2) Changes in session state - wait criteria in Init()
-        bool PrevSessionState = get_ssh_state_session(FBackendHandle);
+        unsigned int HadMainChannel = winscp_query(FBackendHandle, WINSCP_QUERY_MAIN_CHANNEL);
         if (run_toplevel_callbacks(GetCallbackSet()) &&
         if (run_toplevel_callbacks(GetCallbackSet()) &&
             (((-static_cast<int>(OutLen) + static_cast<int>(PendLen)) > PrevDataLen) ||
             (((-static_cast<int>(OutLen) + static_cast<int>(PendLen)) > PrevDataLen) ||
-             (PrevSessionState != get_ssh_state_session(FBackendHandle))))
+             (HadMainChannel != winscp_query(FBackendHandle, WINSCP_QUERY_MAIN_CHANNEL))))
         {
         {
           // Note that we still may process new network event now
           // Note that we still may process new network event now
           Result = true;
           Result = true;
@@ -2041,7 +2040,7 @@ void __fastcall TSecureShell::Idle(unsigned int MSec)
 {
 {
   noise_regular();
   noise_regular();
 
 
-  call_ssh_timer(FBackendHandle);
+  winscp_query(FBackendHandle, WINSCP_QUERY_TIMER);
 
 
   // if we are actively waiting for data in WaitForData,
   // if we are actively waiting for data in WaitForData,
   // do not read here, otherwise we swallow read event and never wake
   // do not read here, otherwise we swallow read event and never wake
@@ -2078,11 +2077,7 @@ unsigned long __fastcall TSecureShell::MaxPacketSize()
   }
   }
   else
   else
   {
   {
-    if (FMaxPacketSize == NULL)
-    {
-      FMaxPacketSize = ssh2_remmaxpkt(FBackendHandle);
-    }
-    return *FMaxPacketSize;
+    return winscp_query(FBackendHandle, WINSCP_QUERY_REMMAXPKT);
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------

+ 0 - 1
source/core/SecureShell.h

@@ -37,7 +37,6 @@ private:
   TDateTime FLastDataSent;
   TDateTime FLastDataSent;
   const Backend_vtable * FBackend;
   const Backend_vtable * FBackend;
   Backend * FBackendHandle;
   Backend * FBackendHandle;
-  const unsigned int * FMaxPacketSize;
   TNotifyEvent FOnReceive;
   TNotifyEvent FOnReceive;
   bool FFrozen;
   bool FFrozen;
   bool FDataWhileFrozen;
   bool FDataWhileFrozen;

+ 1 - 1
source/putty/logging.c

@@ -111,7 +111,7 @@ static void logfopen_callback(void *vctx, int mode)
 		  " =~=~=~=~=~=~=~=~=~=~=~=\r\n", buf);
 		  " =~=~=~=~=~=~=~=~=~=~=~=\r\n", buf);
     }
     }
 
 
-    event = dupprintf(MPEXT_BOM "%s session log (%s mode) to file: %s",
+    event = dupprintf(WINSCP_BOM "%s session log (%s mode) to file: %s",
 		      ctx->state == L_ERROR ?
 		      ctx->state == L_ERROR ?
 		      (mode == 0 ? "Disabled writing" : "Error writing") :
 		      (mode == 0 ? "Disabled writing" : "Error writing") :
 		      (mode == 1 ? "Appending" : "Writing new"),
 		      (mode == 1 ? "Appending" : "Writing new"),

+ 9 - 0
source/putty/misc.c

@@ -446,7 +446,16 @@ static char *dupvprintf_inner(char *buf, int oldlen, int *oldsize,
 	 * (indeed, it has been observed to).
 	 * (indeed, it has been observed to).
 	 * XXX the autoconf manual suggests that using memcpy() will give
 	 * XXX the autoconf manual suggests that using memcpy() will give
 	 *     "maximum portability". */
 	 *     "maximum portability". */
+#if defined _DEBUG && defined IDE
+// CodeGuard hangs in v*printf functions. But while it's possible to disable CodeGuard in vsprintf, it's not possible for vsnprintf.
+// We never want to distribute this version of the code, hence the IDE condition.
+// Put this into WinSCP.cgi along with WinSCP.exe
+// [vsprintf]
+// Disable=yes
+	len = vsprintf(buf + oldlen, fmt, ap);
+#else
 	len = vsnprintf(buf + oldlen, size, fmt, ap);
 	len = vsnprintf(buf + oldlen, size, fmt, ap);
+#endif
 #endif
 #endif
 	if (len >= 0 && len < size) {
 	if (len >= 0 && len < size) {
 	    /* This is the C99-specified criterion for snprintf to have
 	    /* This is the C99-specified criterion for snprintf to have

+ 1 - 1
source/putty/putty.h

@@ -1749,7 +1749,7 @@ void pktin_free_queue_callback(void *vctx);
 // To mark carefully selected messages from PuTTY code as UTF-8.
 // To mark carefully selected messages from PuTTY code as UTF-8.
 // Only for messages that are certain not to ever get ansi-encoded component,
 // Only for messages that are certain not to ever get ansi-encoded component,
 // but known to get UTF-8 encoded component (currently private key path only)
 // but known to get UTF-8 encoded component (currently private key path only)
-#define MPEXT_BOM "\xEF\xBB\xBF"
+#define WINSCP_BOM "\xEF\xBB\xBF"
 #endif
 #endif
 
 
 #ifdef MPEXT
 #ifdef MPEXT

+ 4 - 5
source/putty/puttyexp.h

@@ -11,7 +11,6 @@ struct ssh2_cipheralg;
 typedef const struct ssh2_cipheralg *ssh2_cipher;
 typedef const struct ssh2_cipheralg *ssh2_cipher;
 
 
 int is_ssh(Plug plug);
 int is_ssh(Plug plug);
-void call_ssh_timer(Backend * be);
 int get_ssh_version(Backend * be);
 int get_ssh_version(Backend * be);
 void * get_ssh_frontend(Plug plug);
 void * get_ssh_frontend(Plug plug);
 const ssh1_cipher * get_cipher(Backend * be);
 const ssh1_cipher * get_cipher(Backend * be);
@@ -19,10 +18,10 @@ const ssh2_cipher * get_cscipher(Backend * be);
 const ssh2_cipher * get_sccipher(Backend * be);
 const ssh2_cipher * get_sccipher(Backend * be);
 const struct ssh_compressor * get_cscomp(Backend * be);
 const struct ssh_compressor * get_cscomp(Backend * be);
 const struct ssh_decompressor * get_sccomp(Backend * be);
 const struct ssh_decompressor * get_sccomp(Backend * be);
-int get_ssh_state_closed(Backend * be);
-int get_ssh_state_session(Backend * be);
-const unsigned int * ssh2_remmaxpkt(Backend * be);
-const unsigned int * ssh2_remwindow(Backend * be);
+#define WINSCP_QUERY_REMMAXPKT 1
+#define WINSCP_QUERY_MAIN_CHANNEL 2
+#define WINSCP_QUERY_TIMER 3
+unsigned int winscp_query(Backend * be, int query);
 void md5checksum(const char * buffer, int len, unsigned char output[16]);
 void md5checksum(const char * buffer, int len, unsigned char output[16]);
 typedef const struct ssh_keyalg * cp_ssh_keyalg;
 typedef const struct ssh_keyalg * cp_ssh_keyalg;
 void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys);
 void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys);

+ 17 - 51
source/putty/ssh.c

@@ -172,14 +172,14 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
             int is_simple =
             int is_simple =
                 (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare);
                 (conf_get_int(ssh->conf, CONF_ssh_simple) && !ssh->connshare);
 
 
-            ssh->bpp = ssh2_bpp_new(&ssh->stats);
+            ssh->bpp = ssh2_bpp_new(ssh->frontend, &ssh->stats);
             ssh_connect_bpp(ssh);
             ssh_connect_bpp(ssh);
 
 
 #ifndef NO_GSSAPI
 #ifndef NO_GSSAPI
             /* Load and pick the highest GSS library on the preference
             /* Load and pick the highest GSS library on the preference
              * list. */
              * list. */
             if (!ssh->gss_state.libs)
             if (!ssh->gss_state.libs)
-                ssh->gss_state.libs = ssh_gss_setup(ssh->conf);
+                ssh->gss_state.libs = ssh_gss_setup(ssh->conf, ssh->frontend); // WINSCP
             ssh->gss_state.lib = NULL;
             ssh->gss_state.lib = NULL;
             if (ssh->gss_state.libs->nlibraries > 0) {
             if (ssh->gss_state.libs->nlibraries > 0) {
                 int i, j;
                 int i, j;
@@ -225,7 +225,9 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
                     conf_get_int(ssh->conf, CONF_try_gssapi_auth),
                     conf_get_int(ssh->conf, CONF_try_gssapi_auth),
                     conf_get_int(ssh->conf, CONF_try_gssapi_kex),
                     conf_get_int(ssh->conf, CONF_try_gssapi_kex),
                     conf_get_int(ssh->conf, CONF_gssapifwd),
                     conf_get_int(ssh->conf, CONF_gssapifwd),
-                    &ssh->gss_state);
+                    &ssh->gss_state,
+                    conf_get_str(ssh->conf, CONF_loghost),
+                    conf_get_int(ssh->conf, CONF_change_password)); // WINSCP
                 ssh_connect_ppl(ssh, userauth_layer);
                 ssh_connect_ppl(ssh, userauth_layer);
                 transport_child_layer = userauth_layer;
                 transport_child_layer = userauth_layer;
 
 
@@ -247,7 +249,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
 
 
         } else {
         } else {
 
 
-            ssh->bpp = ssh1_bpp_new();
+            ssh->bpp = ssh1_bpp_new(ssh->frontend);
             ssh_connect_bpp(ssh);
             ssh_connect_bpp(ssh);
 
 
             connection_layer = ssh1_connection_new(ssh, ssh->conf, &ssh->cl);
             connection_layer = ssh1_connection_new(ssh, ssh->conf, &ssh->cl);
@@ -260,7 +262,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
         }
         }
 
 
     } else {
     } else {
-        ssh->bpp = ssh2_bare_bpp_new();
+        ssh->bpp = ssh2_bare_bpp_new(ssh->frontend);
         ssh_connect_bpp(ssh);
         ssh_connect_bpp(ssh);
 
 
         connection_layer = ssh2_connection_new(
         connection_layer = ssh2_connection_new(
@@ -800,6 +802,7 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle,
     bufchain_init(&ssh->user_input);
     bufchain_init(&ssh->user_input);
     ssh->ic_out_raw.fn = ssh_bpp_output_raw_data_callback;
     ssh->ic_out_raw.fn = ssh_bpp_output_raw_data_callback;
     ssh->ic_out_raw.ctx = ssh;
     ssh->ic_out_raw.ctx = ssh;
+    ssh->ic_out_raw.set = get_frontend_callback_set(frontend);
 
 
     ssh->backend.vt = &ssh_backend;
     ssh->backend.vt = &ssh_backend;
     *backend_handle = &ssh->backend;
     *backend_handle = &ssh->backend;
@@ -1122,15 +1125,6 @@ int is_ssh(Plug plug)
   return (*plug)->closing == ssh_closing;
   return (*plug)->closing == ssh_closing;
 }
 }
 
 
-void call_ssh_timer(Backend * be)
-{
-  Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
-  if (ssh->version == 2)
-  {
-    ssh2_timer(ssh, GETTICKCOUNT());
-  }
-}
-
 int get_ssh_version(Backend * be)
 int get_ssh_version(Backend * be)
 {
 {
   Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
   Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
@@ -1172,49 +1166,21 @@ const struct ssh_decompressor * get_sccomp(Backend * be)
   return ssh2_bpp_get_sccomp(ssh->bpp);
   return ssh2_bpp_get_sccomp(ssh->bpp);
 }
 }
 
 
-int get_ssh_state_closed(Backend * be)
-{
-  Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
-  return ssh->state == SSH_STATE_CLOSED;
-}
-
-int get_ssh_state_session(Backend * be)
-{
-  Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
-  return ssh->state == SSH_STATE_SESSION;
-}
-
-const unsigned int * ssh2_remmaxpkt(Backend * be)
-{
-  Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
-  return &ssh->mainchan->v.v2.remmaxpkt;
-}
-
-const unsigned int * ssh2_remwindow(Backend * be)
+unsigned int winscp_query(Backend * be, int query)
 {
 {
   Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
   Ssh ssh = FROMFIELD(be, struct ssh_tag, backend);
-  return &ssh->mainchan->v.v2.remwindow;
-}
-
-void md5checksum(const char * buffer, int len, unsigned char output[16])
-{
-  MD5Simple(buffer, len, output);
-}
-
-void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys)
-{
-  int i;
-  assert(lenof(hostkey_algs) <= *count);
-  *count = lenof(hostkey_algs);
-  for (i = 0; i < *count; i++)
+  if ((ssh->base_layer != NULL) && (ssh->base_layer->vt->winscp_query != NULL))
   {
   {
-    *(SignKeys + i) = hostkey_algs[i].alg;
+    return ssh_ppl_winscp_query(ssh->base_layer, query);
+  }
+  else
+  {
+    return 0;
   }
   }
 }
 }
 
 
-void get_macs(int * count, const struct ssh2_macalg *** amacs)
+void md5checksum(const char * buffer, int len, unsigned char output[16])
 {
 {
-  *amacs = macs;
-  *count = lenof(macs);
+  MD5Simple(buffer, len, output);
 }
 }
 #endif
 #endif

+ 7 - 3
source/putty/ssh1connection.c

@@ -302,7 +302,7 @@ static void ssh1_connection_free(PacketProtocolLayer *ppl)
 
 
 void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags)
 void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags)
 {
 {
-    assert(ppl->vt == &ssh1_connection_vtable);
+    pinitassert(ppl->vt == &ssh1_connection_vtable);
     struct ssh1_connection_state *s =
     struct ssh1_connection_state *s =
         FROMFIELD(ppl, struct ssh1_connection_state, ppl);
         FROMFIELD(ppl, struct ssh1_connection_state, ppl);
     s->local_protoflags = flags;
     s->local_protoflags = flags;
@@ -900,7 +900,7 @@ static void ssh1_channel_destroy(struct ssh1_channel *c)
      * toplevel callback, just in case anything on the current call
      * toplevel callback, just in case anything on the current call
      * stack objects to this entire PPL being freed.
      * stack objects to this entire PPL being freed.
      */
      */
-    queue_toplevel_callback(ssh1_check_termination_callback, s);
+    queue_toplevel_callback(s->cl.frontend, ssh1_check_termination_callback, s); // WINSCP
 }
 }
 
 
 static int ssh1_check_termination(struct ssh1_connection_state *s)
 static int ssh1_check_termination(struct ssh1_connection_state *s)
@@ -985,7 +985,7 @@ static int ssh1channel_write(SshChannel *sc, const void *buf, int len)
     struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc);
     struct ssh1_channel *c = FROMFIELD(sc, struct ssh1_channel, sc);
     struct ssh1_connection_state *s = c->connlayer;
     struct ssh1_connection_state *s = c->connlayer;
 
 
-    assert(!(c->closes & CLOSES_SENT_CLOSE));
+    pinitassert(!(c->closes & CLOSES_SENT_CLOSE));
 
 
     PktOut *pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_DATA);
     PktOut *pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_DATA);
     put_uint32(pktout, c->remoteid);
     put_uint32(pktout, c->remoteid);
@@ -1043,10 +1043,12 @@ static void ssh1_rportfwd_response(struct ssh1_connection_state *s,
 	ppl_logevent(("Remote port forwarding from %s refused",
 	ppl_logevent(("Remote port forwarding from %s refused",
                       rpf->log_description));
                       rpf->log_description));
 
 
+	{ // WINSCP
 	struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
 	struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
 	assert(realpf == rpf);
 	assert(realpf == rpf);
         portfwdmgr_close(s->portfwdmgr, rpf->pfr);
         portfwdmgr_close(s->portfwdmgr, rpf->pfr);
 	free_rportfwd(rpf);
 	free_rportfwd(rpf);
+	} // WINSCP
     }
     }
 }
 }
 
 
@@ -1073,12 +1075,14 @@ static struct ssh_rportfwd *ssh1_rportfwd_alloc(
         return NULL;
         return NULL;
     }
     }
 
 
+    { // WINSCP
     PktOut *pktout = ssh_bpp_new_pktout(
     PktOut *pktout = ssh_bpp_new_pktout(
         s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
         s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
     put_uint32(pktout, rpf->sport);
     put_uint32(pktout, rpf->sport);
     put_stringz(pktout, rpf->dhost);
     put_stringz(pktout, rpf->dhost);
     put_uint32(pktout, rpf->dport);
     put_uint32(pktout, rpf->dport);
     pq_push(s->ppl.out_pq, pktout);
     pq_push(s->ppl.out_pq, pktout);
+    } // WINSCP
 
 
     ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf);
     ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf);
 
 

+ 6 - 6
source/putty/ssh1login.c

@@ -467,7 +467,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
     put_stringz(pkt, s->username);
     put_stringz(pkt, s->username);
     pq_push(s->ppl.out_pq, pkt);
     pq_push(s->ppl.out_pq, pkt);
 
 
-    ppl_logevent(("Sent username \"%s\"", s->username));
+    ppl_logevent((WINSCP_BOM "Sent username \"%s\"", s->username));
     if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE))
     if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE))
         ppl_printf(("Sent username \"%s\"\r\n", s->username));
         ppl_printf(("Sent username \"%s\"\r\n", s->username));
 
 
@@ -487,7 +487,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
     s->keyfile = conf_get_filename(s->conf, CONF_keyfile);
     s->keyfile = conf_get_filename(s->conf, CONF_keyfile);
     if (!filename_is_null(s->keyfile)) {
     if (!filename_is_null(s->keyfile)) {
         int keytype;
         int keytype;
-        ppl_logevent(("Reading key file \"%.150s\"",
+        ppl_logevent((WINSCP_BOM "Reading key file \"%.150s\"",
                       filename_to_str(s->keyfile)));
                       filename_to_str(s->keyfile)));
         keytype = key_type(s->keyfile);
         keytype = key_type(s->keyfile);
         if (keytype == SSH_KEYTYPE_SSH1 ||
         if (keytype == SSH_KEYTYPE_SSH1 ||
@@ -503,7 +503,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
                 s->privatekey_encrypted = rsa_ssh1_encrypted(s->keyfile, NULL);
                 s->privatekey_encrypted = rsa_ssh1_encrypted(s->keyfile, NULL);
             } else {
             } else {
                 ppl_logevent(("Unable to load key (%s)", error));
                 ppl_logevent(("Unable to load key (%s)", error));
-                ppl_printf(("Unable to load key file \"%s\" (%s)\r\n",
+                ppl_printf((WINSCP_BOM "Unable to load key file \"%s\" (%s)\r\n",
                             filename_to_str(s->keyfile), error));
                             filename_to_str(s->keyfile), error));
 
 
                 strbuf_free(s->publickey_blob);
                 strbuf_free(s->publickey_blob);
@@ -512,7 +512,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
         } else {
         } else {
             ppl_logevent(("Unable to use this key file (%s)",
             ppl_logevent(("Unable to use this key file (%s)",
                           key_type_to_str(keytype)));
                           key_type_to_str(keytype)));
-            ppl_printf(("Unable to use key file \"%s\" (%s)\r\n",
+            ppl_printf((WINSCP_BOM "Unable to use key file \"%s\" (%s)\r\n",
                         filename_to_str(s->keyfile),
                         filename_to_str(s->keyfile),
                         key_type_to_str(keytype)));
                         key_type_to_str(keytype)));
         }
         }
@@ -673,7 +673,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
              */
              */
             int got_passphrase; /* need not be kept over crReturn */
             int got_passphrase; /* need not be kept over crReturn */
             if (flags & FLAG_VERBOSE)
             if (flags & FLAG_VERBOSE)
-                ppl_printf(("Trying public key authentication.\r\n"));
+                ppl_printf((WINSCP_BOM "Trying public key authentication.\r\n"));
             ppl_logevent(("Trying public key \"%s\"",
             ppl_logevent(("Trying public key \"%s\"",
                           filename_to_str(s->keyfile)));
                           filename_to_str(s->keyfile)));
             s->tried_publickey = 1;
             s->tried_publickey = 1;
@@ -732,7 +732,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
                     /* Correct passphrase. */
                     /* Correct passphrase. */
                     got_passphrase = TRUE;
                     got_passphrase = TRUE;
                 } else if (retd == 0) {
                 } else if (retd == 0) {
-                    ppl_printf(("Couldn't load private key from %s (%s).\r\n",
+                    ppl_printf((WINSCP_BOM "Couldn't load private key from %s (%s).\r\n",
                                 filename_to_str(s->keyfile), error));
                                 filename_to_str(s->keyfile), error));
                     got_passphrase = FALSE;
                     got_passphrase = FALSE;
                     break;             /* go and try something else */
                     break;             /* go and try something else */

+ 36 - 7
source/putty/ssh2connection.c

@@ -91,6 +91,7 @@ static void ssh2_connection_special_cmd(PacketProtocolLayer *ppl,
 static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl);
 static int ssh2_connection_want_user_input(PacketProtocolLayer *ppl);
 static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl);
 static void ssh2_connection_got_user_input(PacketProtocolLayer *ppl);
 static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf);
 static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf);
+static unsigned int ssh2_connection_winscp_query(PacketProtocolLayer *ppl, int query);
 
 
 static const struct PacketProtocolLayerVtable ssh2_connection_vtable = {
 static const struct PacketProtocolLayerVtable ssh2_connection_vtable = {
     ssh2_connection_free,
     ssh2_connection_free,
@@ -101,6 +102,7 @@ static const struct PacketProtocolLayerVtable ssh2_connection_vtable = {
     ssh2_connection_got_user_input,
     ssh2_connection_got_user_input,
     ssh2_connection_reconfigure,
     ssh2_connection_reconfigure,
     "ssh-connection",
     "ssh-connection",
+    ssh2_connection_winscp_query,
 };
 };
 
 
 static struct ssh_rportfwd *ssh2_rportfwd_alloc(
 static struct ssh_rportfwd *ssh2_rportfwd_alloc(
@@ -624,6 +626,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s)
             break;
             break;
 
 
           case SSH2_MSG_CHANNEL_DATA:
           case SSH2_MSG_CHANNEL_DATA:
+          case SSH2_MSG_CHANNEL_EXTENDED_DATA:
           case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
           case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
           case SSH2_MSG_CHANNEL_REQUEST:
           case SSH2_MSG_CHANNEL_REQUEST:
           case SSH2_MSG_CHANNEL_EOF:
           case SSH2_MSG_CHANNEL_EOF:
@@ -1288,7 +1291,7 @@ static void ssh2_connection_process_queue(PacketProtocolLayer *ppl)
 	    } else {
 	    } else {
 		subsys = conf_get_int(s->conf, CONF_ssh_subsys2);
 		subsys = conf_get_int(s->conf, CONF_ssh_subsys2);
 		cmd = conf_get_str(s->conf, CONF_remote_cmd2);
 		cmd = conf_get_str(s->conf, CONF_remote_cmd2);
-                if (!*cmd)
+                if (!*cmd && !conf_get_int(s->conf, CONF_force_remote_cmd2)) // WINSCP
                     break;
                     break;
                 ppl_logevent(("Primary command failed; attempting fallback"));
                 ppl_logevent(("Primary command failed; attempting fallback"));
 	    }
 	    }
@@ -1550,7 +1553,7 @@ static void ssh2_channel_destroy(struct ssh2_channel *c)
      * toplevel callback, just in case anything on the current call
      * toplevel callback, just in case anything on the current call
      * stack objects to this entire PPL being freed.
      * stack objects to this entire PPL being freed.
      */
      */
-    queue_toplevel_callback(ssh2_check_termination_callback, s);
+    queue_toplevel_callback(s->cl.frontend, ssh2_check_termination_callback, s); // WINSCP
 }
 }
 
 
 static void ssh2_check_termination(struct ssh2_connection_state *s)
 static void ssh2_check_termination(struct ssh2_connection_state *s)
@@ -2003,8 +2006,10 @@ static void ssh2_rportfwd_globreq_response(struct ssh2_connection_state *s,
 	ppl_logevent(("Remote port forwarding from %s refused",
 	ppl_logevent(("Remote port forwarding from %s refused",
                       rpf->log_description));
                       rpf->log_description));
 
 
+	{ // WINSCP
 	struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
 	struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
 	assert(realpf == rpf);
 	assert(realpf == rpf);
+	} // WINSCP
         portfwdmgr_close(s->portfwdmgr, rpf->pfr);
         portfwdmgr_close(s->portfwdmgr, rpf->pfr);
 	free_rportfwd(rpf);
 	free_rportfwd(rpf);
     }
     }
@@ -2072,8 +2077,10 @@ static void ssh2_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf)
         pq_push(s->ppl.out_pq, pktout);
         pq_push(s->ppl.out_pq, pktout);
     }
     }
 
 
+    { // WINSCP
     struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
     struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
     assert(realpf == rpf);
     assert(realpf == rpf);
+    } // WINSCP
     free_rportfwd(rpf);
     free_rportfwd(rpf);
 }
 }
 
 
@@ -2197,7 +2204,7 @@ static mainchan *mainchan_new(struct ssh2_connection_state *s)
 
 
 static void mainchan_free(Channel *chan)
 static void mainchan_free(Channel *chan)
 {
 {
-    assert(chan->vt == &mainchan_channelvt);
+    pinitassert(chan->vt == &mainchan_channelvt);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     struct ssh2_connection_state *s = mc->connlayer;
     struct ssh2_connection_state *s = mc->connlayer;
     s->mainchan = NULL;
     s->mainchan = NULL;
@@ -2216,7 +2223,7 @@ static void mainchan_open_confirmation(Channel *chan)
 
 
 static void mainchan_open_failure(Channel *chan, const char *errtext)
 static void mainchan_open_failure(Channel *chan, const char *errtext)
 {
 {
-    assert(chan->vt == &mainchan_channelvt);
+    pinitassert(chan->vt == &mainchan_channelvt);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     struct ssh2_connection_state *s = mc->connlayer;
     struct ssh2_connection_state *s = mc->connlayer;
 
 
@@ -2231,7 +2238,7 @@ static void mainchan_open_failure(Channel *chan, const char *errtext)
 static int mainchan_send(Channel *chan, int is_stderr,
 static int mainchan_send(Channel *chan, int is_stderr,
                          const void *data, int length)
                          const void *data, int length)
 {
 {
-    assert(chan->vt == &mainchan_channelvt);
+    pinitassert(chan->vt == &mainchan_channelvt);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     struct ssh2_connection_state *s = mc->connlayer;
     struct ssh2_connection_state *s = mc->connlayer;
     return from_backend(s->ppl.frontend, is_stderr, data, length);
     return from_backend(s->ppl.frontend, is_stderr, data, length);
@@ -2239,7 +2246,7 @@ static int mainchan_send(Channel *chan, int is_stderr,
 
 
 static void mainchan_send_eof(Channel *chan)
 static void mainchan_send_eof(Channel *chan)
 {
 {
-    assert(chan->vt == &mainchan_channelvt);
+    pinitassert(chan->vt == &mainchan_channelvt);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     struct ssh2_connection_state *s = mc->connlayer;
     struct ssh2_connection_state *s = mc->connlayer;
     PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
     PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
@@ -2262,7 +2269,7 @@ static void mainchan_send_eof(Channel *chan)
 
 
 static void mainchan_set_input_wanted(Channel *chan, int wanted)
 static void mainchan_set_input_wanted(Channel *chan, int wanted)
 {
 {
-    assert(chan->vt == &mainchan_channelvt);
+    pinitassert(chan->vt == &mainchan_channelvt);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     mainchan *mc = FROMFIELD(chan, mainchan, chan);
     struct ssh2_connection_state *s = mc->connlayer;
     struct ssh2_connection_state *s = mc->connlayer;
 
 
@@ -2499,3 +2506,25 @@ static void ssh2_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
     if (s->portfwdmgr_configured)
     if (s->portfwdmgr_configured)
         portfwdmgr_config(s->portfwdmgr, s->conf);
         portfwdmgr_config(s->portfwdmgr, s->conf);
 }
 }
+
+#include <puttyexp.h>
+
+static unsigned int ssh2_connection_winscp_query(PacketProtocolLayer *ppl, int query)
+{
+    struct ssh2_connection_state *s =
+        FROMFIELD(ppl, struct ssh2_connection_state, ppl);
+
+    if (query == WINSCP_QUERY_REMMAXPKT)
+    {
+        return s->mainchan != NULL ? s->mainchan->remmaxpkt : 0;
+    }
+    else if (query == WINSCP_QUERY_MAIN_CHANNEL)
+    {
+        return s->mainchan_ready;
+    }
+    else
+    {
+        assert(0);
+        return 0;
+    }
+}

+ 63 - 9
source/putty/ssh2transport.c

@@ -62,8 +62,9 @@ const static struct ssh_signkey_with_user_pref_id hostkey_algs[] = {
     { &ssh_ecdsa_nistp256, HK_ECDSA },
     { &ssh_ecdsa_nistp256, HK_ECDSA },
     { &ssh_ecdsa_nistp384, HK_ECDSA },
     { &ssh_ecdsa_nistp384, HK_ECDSA },
     { &ssh_ecdsa_nistp521, HK_ECDSA },
     { &ssh_ecdsa_nistp521, HK_ECDSA },
-    { &ssh_dss, HK_DSA },
+    /* Changed order to match WinSCP default preference list for SshHostKeyList() */
     { &ssh_rsa, HK_RSA },
     { &ssh_rsa, HK_RSA },
+    { &ssh_dss, HK_DSA },
 };
 };
 
 
 const static struct ssh2_macalg *const macs[] = {
 const static struct ssh2_macalg *const macs[] = {
@@ -270,6 +271,7 @@ static void ssh2_transport_dialog_callback(void *, int);
 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 unsigned int ssh2_transport_winscp_query(PacketProtocolLayer *ppl, int query);
 
 
 static const struct PacketProtocolLayerVtable ssh2_transport_vtable = {
 static const struct PacketProtocolLayerVtable ssh2_transport_vtable = {
     ssh2_transport_free,
     ssh2_transport_free,
@@ -280,6 +282,7 @@ static const struct PacketProtocolLayerVtable ssh2_transport_vtable = {
     ssh2_transport_got_user_input,
     ssh2_transport_got_user_input,
     ssh2_transport_reconfigure,
     ssh2_transport_reconfigure,
     NULL, /* no protocol name for this layer */
     NULL, /* no protocol name for this layer */
+    ssh2_transport_winscp_query,
 };
 };
 
 
 #ifndef NO_GSSAPI
 #ifndef NO_GSSAPI
@@ -331,11 +334,12 @@ PacketProtocolLayer *ssh2_transport_new(
     s->server_greeting = dupstr(server_greeting);
     s->server_greeting = dupstr(server_greeting);
     s->stats = stats;
     s->stats = stats;
 
 
-    pq_in_init(&s->pq_in_higher);
-    pq_out_init(&s->pq_out_higher);
+    pq_in_init(&s->pq_in_higher, higher_layer->frontend); // WINSCP
+    pq_out_init(&s->pq_out_higher, higher_layer->frontend); // WINSCP
     s->pq_out_higher.pqb.ic = &s->ic_pq_out_higher;
     s->pq_out_higher.pqb.ic = &s->ic_pq_out_higher;
     s->ic_pq_out_higher.fn = ssh2_transport_higher_layer_packet_callback;
     s->ic_pq_out_higher.fn = ssh2_transport_higher_layer_packet_callback;
     s->ic_pq_out_higher.ctx = &s->ppl;
     s->ic_pq_out_higher.ctx = &s->ppl;
+    s->ic_pq_out_higher.set = get_frontend_callback_set(higher_layer->frontend);
 
 
     s->higher_layer = higher_layer;
     s->higher_layer = higher_layer;
     s->higher_layer->selfptr = &s->higher_layer;
     s->higher_layer->selfptr = &s->higher_layer;
@@ -393,7 +397,6 @@ static void ssh2_transport_free(PacketProtocolLayer *ppl)
         ssh_key_free(s->hkey);
         ssh_key_free(s->hkey);
         s->hkey = NULL;
         s->hkey = NULL;
     }
     }
-    if (s->e) freebn(s->e);
     if (s->f) freebn(s->f);
     if (s->f) freebn(s->f);
     if (s->p) freebn(s->p);
     if (s->p) freebn(s->p);
     if (s->g) freebn(s->g);
     if (s->g) freebn(s->g);
@@ -462,8 +465,10 @@ static void ssh2_mkkey(
 
 
         for (offset = hlen; offset < keylen_padded; offset += hlen) {
         for (offset = hlen; offset < keylen_padded; offset += hlen) {
             put_data(h, key + offset - hlen, hlen);
             put_data(h, key + offset - hlen, hlen);
+            { // WINSCP
             ssh_hash *h2 = ssh_hash_copy(h);
             ssh_hash *h2 = ssh_hash_copy(h);
             ssh_hash_final(h2, key + offset);
             ssh_hash_final(h2, key + offset);
+            } // WINSCP
         }
         }
 
 
         ssh_hash_free(h);
         ssh_hash_free(h);
@@ -817,7 +822,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
                 for (j = 0; j < lenof(hostkey_algs); j++) {
                 for (j = 0; j < lenof(hostkey_algs); j++) {
                     if (hostkey_algs[j].id != s->preferred_hk[i])
                     if (hostkey_algs[j].id != s->preferred_hk[i])
                         continue;
                         continue;
-                    if (have_ssh_host_key(s->savedhost, s->savedport,
+                    if (have_ssh_host_key(
+                                          s->ppl.frontend, // WINSCP
+                                          s->savedhost, s->savedport,
                                           hostkey_algs[j].alg->cache_id)) {
                                           hostkey_algs[j].alg->cache_id)) {
                         alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY],
                         alg = ssh2_kexinit_addalg(s->kexlists[KEXLIST_HOSTKEY],
                                                   hostkey_algs[j].alg->ssh_id);
                                                   hostkey_algs[j].alg->ssh_id);
@@ -1119,7 +1126,9 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
                     if (hostkey_algs[j].alg != s->hostkey_alg &&
                     if (hostkey_algs[j].alg != s->hostkey_alg &&
                         in_commasep_string(hostkey_algs[j].alg->ssh_id,
                         in_commasep_string(hostkey_algs[j].alg->ssh_id,
                                            str.ptr, str.len) &&
                                            str.ptr, str.len) &&
-                        !have_ssh_host_key(s->savedhost, s->savedport,
+                        !have_ssh_host_key(
+                                           s->ppl.frontend, // WINSCP
+                                           s->savedhost, s->savedport,
                                            hostkey_algs[j].alg->cache_id)) {
                                            hostkey_algs[j].alg->cache_id)) {
                         s->uncert_hostkeys[s->n_uncert_hostkeys++] = j;
                         s->uncert_hostkeys[s->n_uncert_hostkeys++] = j;
                     }
                     }
@@ -1377,7 +1386,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
         dh_cleanup(s->dh_ctx);
         dh_cleanup(s->dh_ctx);
         s->dh_ctx = NULL;
         s->dh_ctx = NULL;
         freebn(s->f); s->f = NULL;
         freebn(s->f); s->f = NULL;
-        freebn(s->e); s->e = NULL;
         if (dh_is_gex(s->kex_alg)) {
         if (dh_is_gex(s->kex_alg)) {
             freebn(s->g); s->g = NULL;
             freebn(s->g); s->g = NULL;
             freebn(s->p); s->p = NULL;
             freebn(s->p); s->p = NULL;
@@ -1699,7 +1707,6 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl)
         dh_cleanup(s->dh_ctx);
         dh_cleanup(s->dh_ctx);
         s->dh_ctx = NULL;
         s->dh_ctx = NULL;
         freebn(s->f); s->f = NULL;
         freebn(s->f); s->f = NULL;
-        freebn(s->e); s->e = NULL;
         if (dh_is_gex(s->kex_alg)) {
         if (dh_is_gex(s->kex_alg)) {
             freebn(s->g); s->g = NULL;
             freebn(s->g); s->g = NULL;
             freebn(s->p); s->p = NULL;
             freebn(s->p); s->p = NULL;
@@ -2412,7 +2419,9 @@ static void ssh2_transport_timer(void *ctx, unsigned long now)
     unsigned long mins;
     unsigned long mins;
     unsigned long ticks;
     unsigned long ticks;
 
 
-    if (s->kex_in_progress || now != s->next_rekey)
+    // WINSCP: our WINSCP_QUERY_TIMER implementation of schedule_timer
+    //  does not guarantee the `now` to be exactly as scheduled
+    if (s->kex_in_progress || now < s->next_rekey)
         return;
         return;
 
 
     mins = sanitise_rekey_time(conf_get_int(s->conf, CONF_ssh_rekey_time), 60);
     mins = sanitise_rekey_time(conf_get_int(s->conf, CONF_ssh_rekey_time), 60);
@@ -2965,3 +2974,48 @@ static void ssh2_transport_got_user_input(PacketProtocolLayer *ppl)
     /* Just delegate this to the higher layer */
     /* Just delegate this to the higher layer */
     ssh_ppl_got_user_input(s->higher_layer);
     ssh_ppl_got_user_input(s->higher_layer);
 }
 }
+
+#include "puttyexp.h"
+
+static unsigned int ssh2_transport_winscp_query(PacketProtocolLayer *ppl, int query)
+{
+    struct ssh2_transport_state *s =
+        FROMFIELD(ppl, struct ssh2_transport_state, ppl);
+    if (query == WINSCP_QUERY_TIMER)
+    {
+        ssh2_transport_timer(s, GETTICKCOUNT());
+        return 1;
+    }
+    else if (s->higher_layer->vt->winscp_query != NULL)
+    {
+        return ssh_ppl_winscp_query(s->higher_layer, query);
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+// WINSCP
+void get_hostkey_algs(int * count, cp_ssh_keyalg * SignKeys)
+{
+    int i;
+    assert(lenof(hostkey_algs) <= *count);
+    *count = lenof(hostkey_algs);
+    for (i = 0; i < *count; i++)
+    {
+        *(SignKeys + i) = hostkey_algs[i].alg;
+    }
+}
+
+// WINSCP
+void get_macs(int * count, const struct ssh2_macalg *** amacs)
+{
+    *amacs = macs;
+    *count = lenof(macs);
+}
+
+void call_ssh_timer(Backend * be)
+{
+    // TODO
+}

+ 39 - 7
source/putty/ssh2userauth.c

@@ -26,6 +26,8 @@ struct ssh2_userauth_state {
     char *hostname, *fullhostname;
     char *hostname, *fullhostname;
     char *default_username;
     char *default_username;
     int try_ki_auth, try_gssapi_auth, try_gssapi_kex_auth, gssapi_fwd;
     int try_ki_auth, try_gssapi_auth, try_gssapi_kex_auth, gssapi_fwd;
+    char *loghost; // WINSCP
+    int change_password; // WINSCP
 
 
     ptrlen session_id;
     ptrlen session_id;
     enum {
     enum {
@@ -118,7 +120,8 @@ PacketProtocolLayer *ssh2_userauth_new(
     const char *default_username, int change_username,
     const char *default_username, int change_username,
     int try_ki_auth,
     int try_ki_auth,
     int try_gssapi_auth, int try_gssapi_kex_auth,
     int try_gssapi_auth, int try_gssapi_kex_auth,
-    int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss)
+    int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss,
+    const char * loghost, int change_password) // WINSCP
 {
 {
     struct ssh2_userauth_state *s = snew(struct ssh2_userauth_state);
     struct ssh2_userauth_state *s = snew(struct ssh2_userauth_state);
     memset(s, 0, sizeof(*s));
     memset(s, 0, sizeof(*s));
@@ -136,6 +139,8 @@ PacketProtocolLayer *ssh2_userauth_new(
     s->try_gssapi_kex_auth = try_gssapi_kex_auth;
     s->try_gssapi_kex_auth = try_gssapi_kex_auth;
     s->gssapi_fwd = gssapi_fwd;
     s->gssapi_fwd = gssapi_fwd;
     s->shgss = shgss;
     s->shgss = shgss;
+    s->loghost = dupstr(loghost); // WINSCP
+    s->change_password = change_password;
     bufchain_init(&s->banner);
     bufchain_init(&s->banner);
 
 
     return &s->ppl;
     return &s->ppl;
@@ -165,6 +170,7 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
     sfree(s->default_username);
     sfree(s->default_username);
     sfree(s->hostname);
     sfree(s->hostname);
     sfree(s->fullhostname);
     sfree(s->fullhostname);
+    sfree(s->loghost);
     sfree(s);
     sfree(s);
 }
 }
 
 
@@ -223,7 +229,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
      */
      */
     if (!filename_is_null(s->keyfile)) {
     if (!filename_is_null(s->keyfile)) {
         int keytype;
         int keytype;
-        ppl_logevent(("Reading key file \"%.150s\"",
+        ppl_logevent((WINSCP_BOM "Reading key file \"%.150s\"",
                       filename_to_str(s->keyfile)));
                       filename_to_str(s->keyfile)));
         keytype = key_type(s->keyfile);
         keytype = key_type(s->keyfile);
         if (keytype == SSH_KEYTYPE_SSH2 ||
         if (keytype == SSH_KEYTYPE_SSH2 ||
@@ -242,7 +248,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     ssh2_userkey_encrypted(s->keyfile, NULL);
                     ssh2_userkey_encrypted(s->keyfile, NULL);
             } else {
             } else {
                 ppl_logevent(("Unable to load key (%s)", error));
                 ppl_logevent(("Unable to load key (%s)", error));
-                ppl_printf(("Unable to load key file \"%s\" (%s)\r\n",
+                ppl_printf((WINSCP_BOM "Unable to load key file \"%s\" (%s)\r\n",
                             filename_to_str(s->keyfile), error));
                             filename_to_str(s->keyfile), error));
                 strbuf_free(s->publickey_blob);
                 strbuf_free(s->publickey_blob);
                 s->publickey_blob = NULL;
                 s->publickey_blob = NULL;
@@ -250,7 +256,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
         } else {
         } else {
             ppl_logevent(("Unable to use this key file (%s)",
             ppl_logevent(("Unable to use this key file (%s)",
                           key_type_to_str(keytype)));
                           key_type_to_str(keytype)));
-            ppl_printf(("Unable to use key file \"%s\" (%s)\r\n",
+            ppl_printf((WINSCP_BOM "Unable to use key file \"%s\" (%s)\r\n",
                         filename_to_str(s->keyfile),
                         filename_to_str(s->keyfile),
                         key_type_to_str(keytype)));
                         key_type_to_str(keytype)));
             s->publickey_blob = NULL;
             s->publickey_blob = NULL;
@@ -395,7 +401,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
             free_prompts(s->cur_prompt);
             free_prompts(s->cur_prompt);
         } else {
         } else {
             if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE))
             if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE))
-                ppl_printf(("Using username \"%s\".\r\n", s->username));
+                ppl_printf((WINSCP_BOM "Using username \"%s\".\r\n", s->username));
         }
         }
         s->got_username = TRUE;
         s->got_username = TRUE;
 
 
@@ -463,6 +469,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                         void *data;
                         void *data;
                         int len;
                         int len;
                         bufchain_prefix(&s->banner, &data, &len);
                         bufchain_prefix(&s->banner, &data, &len);
+                        display_banner(s->ppl.frontend, &s->banner, len); // WINSCP
                         from_backend(s->ppl.frontend, TRUE, data, len);
                         from_backend(s->ppl.frontend, TRUE, data, len);
                         bufchain_consume(&s->banner, len);
                         bufchain_consume(&s->banner, len);
                     }
                     }
@@ -559,6 +566,9 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     ppl_logevent(("Further authentication required"));
                     ppl_logevent(("Further authentication required"));
                 }
                 }
 
 
+#ifdef WINSCP
+                ppl_logevent(("Server offered these authentication methods: %*s", methods.len, methods.ptr));
+#endif
                 s->can_pubkey =
                 s->can_pubkey =
                     in_commasep_string("publickey", methods.ptr, methods.len);
                     in_commasep_string("publickey", methods.ptr, methods.len);
                 s->can_passwd =
                 s->can_passwd =
@@ -946,8 +956,15 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
 
                 /* Import server name if not cached from KEX */
                 /* Import server name if not cached from KEX */
                 if (s->shgss->srv_name == GSS_C_NO_NAME) {
                 if (s->shgss->srv_name == GSS_C_NO_NAME) {
+                    // WINSCP
+                    const char * fullhostname = s->fullhostname;
+                    if (s->loghost[0] != '\0')
+                    {
+                        fullhostname = s->loghost;
+                    }
+                    // /WINSCP
                     s->gss_stat = s->shgss->lib->import_name(
                     s->gss_stat = s->shgss->lib->import_name(
-                        s->shgss->lib, s->fullhostname, &s->shgss->srv_name);
+                        s->shgss->lib, fullhostname, &s->shgss->srv_name); // WINSCP
                     if (s->gss_stat != SSH_GSS_OK) {
                     if (s->gss_stat != SSH_GSS_OK) {
                         if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)
                         if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)
                             ppl_logevent(("GSSAPI import name failed -"
                             ppl_logevent(("GSSAPI import name failed -"
@@ -1220,6 +1237,16 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
 
 
                 s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD;
                 s->ppl.bpp->pls->actx = SSH2_PKTCTX_PASSWORD;
 
 
+                // WINSCP
+                if (s->change_password != 0)
+                {
+                    s->password = dupstr("");
+                    s->type = AUTH_TYPE_PASSWORD;
+                }
+                else
+                {
+                // no indentation to ease merges
+                // /WINSCP
                 s->cur_prompt = new_prompts(s->ppl.frontend);
                 s->cur_prompt = new_prompts(s->ppl.frontend);
                 s->cur_prompt->to_server = TRUE;
                 s->cur_prompt->to_server = TRUE;
                 s->cur_prompt->name = dupstr("SSH password");
                 s->cur_prompt->name = dupstr("SSH password");
@@ -1289,9 +1316,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                  * request.
                  * request.
                  */
                  */
                 crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
                 crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
+                } // WINSCP
                 changereq_first_time = TRUE;
                 changereq_first_time = TRUE;
 
 
-                while (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
+                while ((pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) ||
+                       (s->change_password != 0)) { // WINSCP
 
 
                     /* 
                     /* 
                      * We're being asked for a new password
                      * We're being asked for a new password
@@ -1302,6 +1331,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                     int got_new = FALSE; /* not live over crReturn */
                     int got_new = FALSE; /* not live over crReturn */
                     ptrlen prompt;  /* not live over crReturn */
                     ptrlen prompt;  /* not live over crReturn */
                     
                     
+                    if (s->change_password == 0) // WINSCP
                     {
                     {
                         const char *msg;
                         const char *msg;
                         if (changereq_first_time)
                         if (changereq_first_time)
@@ -1312,6 +1342,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
                         ppl_printf(("%s\r\n", msg));
                         ppl_printf(("%s\r\n", msg));
                     }
                     }
 
 
+                    s->change_password = 0; // WINSCP
+
                     prompt = get_string(pktin);
                     prompt = get_string(pktin);
 
 
                     s->cur_prompt = new_prompts(s->ppl.frontend);
                     s->cur_prompt = new_prompts(s->ppl.frontend);

+ 3 - 2
source/putty/sshcommon.c

@@ -689,7 +689,7 @@ void ssh_ppl_replace(PacketProtocolLayer *old, PacketProtocolLayer *new)
 
 
 void ssh_ppl_free(PacketProtocolLayer *ppl)
 void ssh_ppl_free(PacketProtocolLayer *ppl)
 {
 {
-    delete_callbacks_for_context(ppl);
+    delete_callbacks_for_context(get_frontend_callback_set(ppl->frontend), ppl); // WINSCP
     ppl->vt->free(ppl);
     ppl->vt->free(ppl);
 }
 }
 
 
@@ -707,6 +707,7 @@ void ssh_ppl_setup_queues(PacketProtocolLayer *ppl,
     ppl->in_pq->pqb.ic = &ppl->ic_process_queue;
     ppl->in_pq->pqb.ic = &ppl->ic_process_queue;
     ppl->ic_process_queue.fn = ssh_ppl_ic_process_queue_callback;
     ppl->ic_process_queue.fn = ssh_ppl_ic_process_queue_callback;
     ppl->ic_process_queue.ctx = ppl;
     ppl->ic_process_queue.ctx = ppl;
+    ppl->ic_process_queue.set = get_frontend_callback_set(ppl->frontend);
 
 
     /* If there's already something on the input queue, it will want
     /* If there's already something on the input queue, it will want
      * handling immediately. */
      * handling immediately. */
@@ -719,7 +720,7 @@ void ssh_ppl_user_output_string_and_free(PacketProtocolLayer *ppl, char *text)
     /* Messages sent via this function are from the SSH layer, not
     /* Messages sent via this function are from the SSH layer, not
      * from the server-side process, so they always have the stderr
      * from the server-side process, so they always have the stderr
      * flag set. */
      * flag set. */
-    from_backend(ppl->frontend, TRUE, text, strlen(text));
+    from_backend(ppl->frontend, -1, text, strlen(text)); // WINSCP
     sfree(text);
     sfree(text);
 }
 }
 
 

+ 1 - 1
source/putty/sshgss.h

@@ -53,7 +53,7 @@ struct ssh_gss_liblist {
     struct ssh_gss_library *libraries;
     struct ssh_gss_library *libraries;
     int nlibraries;
     int nlibraries;
 };
 };
-struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend);
+struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, Frontend *frontend);
 void ssh_gss_cleanup(struct ssh_gss_liblist *list);
 void ssh_gss_cleanup(struct ssh_gss_liblist *list);
 
 
 /*
 /*

+ 5 - 1
source/putty/sshppl.h

@@ -24,6 +24,8 @@ struct PacketProtocolLayerVtable {
 
 
     /* Protocol-level name of this layer. */
     /* Protocol-level name of this layer. */
     const char *name;
     const char *name;
+
+    unsigned int (*winscp_query)(PacketProtocolLayer *ppl, int query);
 };
 };
 
 
 struct PacketProtocolLayer {
 struct PacketProtocolLayer {
@@ -68,6 +70,7 @@ struct PacketProtocolLayer {
 #define ssh_ppl_want_user_input(ppl) ((ppl)->vt->want_user_input(ppl))
 #define ssh_ppl_want_user_input(ppl) ((ppl)->vt->want_user_input(ppl))
 #define ssh_ppl_got_user_input(ppl) ((ppl)->vt->got_user_input(ppl))
 #define ssh_ppl_got_user_input(ppl) ((ppl)->vt->got_user_input(ppl))
 #define ssh_ppl_reconfigure(ppl, conf) ((ppl)->vt->reconfigure(ppl, conf))
 #define ssh_ppl_reconfigure(ppl, conf) ((ppl)->vt->reconfigure(ppl, conf))
+#define ssh_ppl_winscp_query(ppl, query) ((ppl)->vt->winscp_query(ppl, query))
 
 
 /* ssh_ppl_free is more than just a macro wrapper on the vtable; it
 /* ssh_ppl_free is more than just a macro wrapper on the vtable; it
  * does centralised parts of the freeing too. */
  * does centralised parts of the freeing too. */
@@ -106,7 +109,8 @@ PacketProtocolLayer *ssh2_userauth_new(
     const char *default_username, int change_username,
     const char *default_username, int change_username,
     int try_ki_auth,
     int try_ki_auth,
     int try_gssapi_auth, int try_gssapi_kex_auth,
     int try_gssapi_auth, int try_gssapi_kex_auth,
-    int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss);
+    int gssapi_fwd, struct ssh_connection_shared_gss_state *shgss,
+    const char * loghost, int change_password); // WINSCP
 PacketProtocolLayer *ssh2_connection_new(
 PacketProtocolLayer *ssh2_connection_new(
     Ssh ssh, ssh_sharing_state *connshare, int is_simple,
     Ssh ssh, ssh_sharing_state *connshare, int is_simple,
     Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out);
     Conf *conf, const char *peer_verstring, ConnectionLayer **cl_out);

+ 1 - 1
source/putty/windows/wingss.c

@@ -98,7 +98,7 @@ const char *gsslogmsg = NULL;
 
 
 static void ssh_sspi_bind_fns(struct ssh_gss_library *lib);
 static void ssh_sspi_bind_fns(struct ssh_gss_library *lib);
 
 
-struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, void *frontend) // MPEXT
+struct ssh_gss_liblist *ssh_gss_setup(Conf *conf, Frontend *frontend) // MPEXT
 {
 {
     HMODULE module;
     HMODULE module;
     HKEY regkey;
     HKEY regkey;