Martin Prikryl 10 vuotta sitten
vanhempi
sitoutus
eb3fe4e01f

+ 1 - 1
dotnet/properties/AssemblyInfo.cs

@@ -21,7 +21,7 @@ using System.Runtime.InteropServices;
 
 [assembly: AssemblyVersion("1.2.9.0")]
 [assembly: AssemblyFileVersion("1.2.9.0")]
-[assembly: AssemblyInformationalVersionAttribute("5.7.4.0")]
+[assembly: AssemblyInformationalVersionAttribute("5.7.5.0")]
 
 [assembly: CLSCompliant(true)]
 

+ 1 - 1
libs/openssl/crypto/bio/bio.h

@@ -290,7 +290,7 @@ void BIO_clear_flags(BIO *b, int flags);
  * BIO_CB_RETURN flag indicates if it is after the call
  */
 # define BIO_CB_RETURN   0x80
-# define BIO_CB_return(a) ((a)|BIO_CB_RETURN))
+# define BIO_CB_return(a) ((a)|BIO_CB_RETURN)
 # define BIO_cb_pre(a)   (!((a)&BIO_CB_RETURN))
 # define BIO_cb_post(a)  ((a)&BIO_CB_RETURN)
 

+ 2 - 2
libs/openssl/crypto/buildinf.h

@@ -9,11 +9,11 @@
   /* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
   #define CFLAGS "compiler: cl  /MD /Ox /O2 /Ob2 -DOPENSSL_THREADS  -DDSO_WIN32  -DOPENSSL_USE_APPLINK -I. -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_STATIC_ENGINE    "
   #define PLATFORM "VC-WIN32"
-  #define DATE "Mon Jun 15 08:27:41 2015"
+  #define DATE "Mon Jul 20 10:57:37 2015"
 #endif
 #ifdef MK1MF_PLATFORM_BC_NT
   /* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
   #define CFLAGS "compiler: bcc32 -DWIN32_LEAN_AND_MEAN -q -w-ccc -w-rch -w-pia -w-aus -w-par -w-inl  -c -tWC -tWM -DOPENSSL_SYSNAME_WIN32 -DL_ENDIAN -DDSO_WIN32 -D_stricmp=stricmp -D_strnicmp=strnicmp -D_timeb=timeb -D_ftime=ftime -O2 -ff -fp -DBN_ASM -DMD5_ASM -DSHA1_ASM -DRMD160_ASM -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_DYNAMIC_ENGINE    "
   #define PLATFORM "BC-NT"
-  #define DATE "Mon Jun 15 08:27:41 2015"
+  #define DATE "Mon Jul 20 10:57:37 2015"
 #endif

+ 1 - 1
libs/openssl/crypto/evp/e_aes.c

@@ -1146,7 +1146,7 @@ static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
     case EVP_CTRL_CCM_SET_TAG:
         if ((arg & 1) || arg < 4 || arg > 16)
             return 0;
-        if ((c->encrypt && ptr) || (!c->encrypt && !ptr))
+        if (c->encrypt && ptr)
             return 0;
         if (ptr) {
             cctx->tag_set = 1;

+ 1 - 1
libs/openssl/crypto/opensslconf.h

@@ -189,7 +189,7 @@ extern "C" {
 #endif
 
 #if defined(DES_RISC1) && defined(DES_RISC2)
-YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
+#error YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
 #endif
 
 /* Unroll the inner loop, this sometimes helps, sometimes hinders.

+ 3 - 3
libs/openssl/crypto/opensslv.h

@@ -30,11 +30,11 @@ extern "C" {
  * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
  *  major minor fix final patch/beta)
  */
-# define OPENSSL_VERSION_NUMBER  0x100010ffL
+# define OPENSSL_VERSION_NUMBER  0x1000110fL
 # ifdef OPENSSL_FIPS
-#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1o-fips 12 Jun 2015"
+#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1p-fips 9 Jul 2015"
 # else
-#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1o 12 Jun 2015"
+#  define OPENSSL_VERSION_TEXT    "OpenSSL 1.0.1p 9 Jul 2015"
 # endif
 # define OPENSSL_VERSION_PTEXT   " part of " OPENSSL_VERSION_TEXT
 

+ 2 - 0
libs/openssl/crypto/pkcs12/p12_kiss.c

@@ -135,10 +135,12 @@ int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
 
     while ((x = sk_X509_pop(ocerts))) {
         if (pkey && *pkey && cert && !*cert) {
+            ERR_set_mark();
             if (X509_check_private_key(x, *pkey)) {
                 *cert = x;
                 x = NULL;
             }
+            ERR_pop_to_mark();
         }
 
         if (ca && x) {

+ 16 - 10
libs/openssl/crypto/x509/x509_vfy.c

@@ -162,6 +162,14 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
         X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
         return -1;
     }
+    if (ctx->chain != NULL) {
+        /*
+         * This X509_STORE_CTX has already been used to verify a cert. We
+         * cannot do another one.
+         */
+        X509err(X509_F_X509_VERIFY_CERT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return -1;
+    }
 
     cb = ctx->verify_cb;
 
@@ -169,15 +177,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
      * first we make sure the chain we are going to build is present and that
      * the first entry is in place
      */
-    if (ctx->chain == NULL) {
-        if (((ctx->chain = sk_X509_new_null()) == NULL) ||
-            (!sk_X509_push(ctx->chain, ctx->cert))) {
-            X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
-            goto end;
-        }
-        CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
-        ctx->last_untrusted = 1;
+    if (((ctx->chain = sk_X509_new_null()) == NULL) ||
+        (!sk_X509_push(ctx->chain, ctx->cert))) {
+        X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
+        goto end;
     }
+    CRYPTO_add(&ctx->cert->references, 1, CRYPTO_LOCK_X509);
+    ctx->last_untrusted = 1;
 
     /* We use a temporary STACK so we can chop and hack at it */
     if (ctx->untrusted != NULL
@@ -306,7 +312,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
          * if the user hasn't switched off alternate chain checking
          */
         retry = 0;
-        if (j == ctx->last_untrusted &&
+        if (num == ctx->last_untrusted &&
             !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
             while (j-- > 1) {
                 xtmp2 = sk_X509_value(ctx->chain, j - 1);
@@ -328,8 +334,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
                         xtmp = sk_X509_pop(ctx->chain);
                         X509_free(xtmp);
                         num--;
-                        ctx->last_untrusted--;
                     }
+                    ctx->last_untrusted = sk_X509_num(ctx->chain);
                     retry = 1;
                     break;
                 }

+ 3 - 14
libs/openssl/ssl/s3_clnt.c

@@ -1381,8 +1381,6 @@ int ssl3_get_key_exchange(SSL *s)
 
 #ifndef OPENSSL_NO_PSK
     if (alg_k & SSL_kPSK) {
-        char tmp_id_hint[PSK_MAX_IDENTITY_LEN + 1];
-
         param_len = 2;
         if (param_len > n) {
             SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
@@ -1408,17 +1406,8 @@ int ssl3_get_key_exchange(SSL *s)
         }
         param_len += i;
 
-        /*
-         * If received PSK identity hint contains NULL characters, the hint
-         * is truncated from the first NULL. p may not be ending with NULL,
-         * so create a NULL-terminated string.
-         */
-        memcpy(tmp_id_hint, p, i);
-        memset(tmp_id_hint + i, 0, PSK_MAX_IDENTITY_LEN + 1 - i);
-        if (s->ctx->psk_identity_hint != NULL)
-            OPENSSL_free(s->ctx->psk_identity_hint);
-        s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
-        if (s->ctx->psk_identity_hint == NULL) {
+        s->session->psk_identity_hint = BUF_strndup((char *)p, i);
+        if (s->session->psk_identity_hint == NULL) {
             al = SSL_AD_HANDSHAKE_FAILURE;
             SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
             goto f_err;
@@ -2951,7 +2940,7 @@ int ssl3_send_client_key_exchange(SSL *s)
             }
 
             memset(identity, 0, sizeof(identity));
-            psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
+            psk_len = s->psk_client_callback(s, s->session->psk_identity_hint,
                                              identity, sizeof(identity) - 1,
                                              psk_or_pre_ms,
                                              sizeof(psk_or_pre_ms));

+ 1 - 1
libs/openssl/ssl/s3_srvr.c

@@ -2792,7 +2792,7 @@ int ssl3_get_client_key_exchange(SSL *s)
 
         if (s->session->psk_identity != NULL)
             OPENSSL_free(s->session->psk_identity);
-        s->session->psk_identity = BUF_strdup((char *)p);
+        s->session->psk_identity = BUF_strndup((char *)p, i);
         if (s->session->psk_identity == NULL) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
             goto psk_err;

+ 1 - 1
source/Console.cbproj

@@ -65,7 +65,7 @@
 			<ProjectType>CppConsoleApplication</ProjectType>
 			<SanitizedProjectName>Console</SanitizedProjectName>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.1.0.0;InternalName=console;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.7.4.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.1.0.0;InternalName=console;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.7.5.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>4</VerInfo_MajorVer>
 			<VerInfo_MinorVer>1</VerInfo_MinorVer>

+ 1 - 1
source/DragExt.cbproj

@@ -66,7 +66,7 @@
 			<SanitizedProjectName>DragExt</SanitizedProjectName>
 			<VerInfo_DLL>true</VerInfo_DLL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.7.4.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Drag&amp;Drop shell extension for WinSCP (32-bit);FileVersion=1.2.1.0;InternalName=dragext32;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=dragext.dll;ProductName=WinSCP;ProductVersion=5.7.5.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MinorVer>2</VerInfo_MinorVer>
 			<VerInfo_Release>1</VerInfo_Release>

+ 2 - 2
source/DragExt64.rc

@@ -1,6 +1,6 @@
 1 VERSIONINFO
 FILEVERSION 1,2,1,0
-PRODUCTVERSION 5,7,4,0
+PRODUCTVERSION 5,7,5,0
 FILEOS 0x4
 FILETYPE 0x2
 {
@@ -16,7 +16,7 @@ FILETYPE 0x2
             VALUE "LegalTrademarks", "\0"
             VALUE "OriginalFilename", "dragext64.dll\0"
             VALUE "ProductName", "WinSCP\0"
-            VALUE "ProductVersion", "5.7.4.0\0"
+            VALUE "ProductVersion", "5.7.5.0\0"
             VALUE "ReleaseType", "stable\0"
             VALUE "WWW", "http://winscp.net/\0"
         }

+ 2 - 2
source/WinSCP.cbproj

@@ -83,11 +83,11 @@
 			<SanitizedProjectName>WinSCP</SanitizedProjectName>
 			<UsingDelphiRTL>true</UsingDelphiRTL>
 			<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.7.4.0;InternalName=winscp;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.7.4.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
+			<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=WinSCP: SFTP, FTP and SCP client;FileVersion=5.7.5.0;InternalName=winscp;LegalCopyright=(c) 2000-2015 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.exe;ProductName=WinSCP;ProductVersion=5.7.5.0;ReleaseType=stable;WWW=http://winscp.net/</VerInfo_Keys>
 			<VerInfo_Locale>1033</VerInfo_Locale>
 			<VerInfo_MajorVer>5</VerInfo_MajorVer>
 			<VerInfo_MinorVer>7</VerInfo_MinorVer>
-			<VerInfo_Release>4</VerInfo_Release>
+			<VerInfo_Release>5</VerInfo_Release>
 		</PropertyGroup>
 	<PropertyGroup Condition="'$(Base_Win32)'!=''">
 			<Defines>IDE;STRICT;$(Defines)</Defines>

+ 3 - 16
source/core/FtpFileSystem.cpp

@@ -2388,23 +2388,10 @@ void __fastcall TFTPFileSystem::DoReadDirectory(TRemoteFileList * FileList)
   FLastDataSent = Now();
 }
 //---------------------------------------------------------------------------
-bool __fastcall TFTPFileSystem::TimeZoneDifferenceApplicable(TModificationFmt ModificationFmt)
-{
-  // Full precision is available for MLST only, so we would not be here.
-  return (ModificationFmt == mfMDHM) || ALWAYS_FALSE(ModificationFmt == mfFull);
-}
-//---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::ApplyTimeDifference(TRemoteFile * File)
 {
-  // FTimeDifference is not only optimization, but also prevents assertion failing
-  // in TimeZoneDifferenceApplicable when the file has full precision
-  if ((FTimeDifference != 0) &&
-      TimeZoneDifferenceApplicable(File->ModificationFmt))
-  {
-    assert(File->Modification == File->LastAccess);
-    File->Modification = IncSecond(File->Modification, FTimeDifference);
-    File->LastAccess = IncSecond(File->LastAccess, FTimeDifference);
-  }
+  assert(File->Modification == File->LastAccess);
+  File->ShiftTimeInSeconds(FTimeDifference);
 }
 //---------------------------------------------------------------------------
 void __fastcall TFTPFileSystem::AutoDetectTimeDifference(TRemoteFileList * FileList)
@@ -2422,7 +2409,7 @@ void __fastcall TFTPFileSystem::AutoDetectTimeDifference(TRemoteFileList * FileL
       // (it should not be problem to use them otherwise).
       // We are also not interested in files with day precision only.
       if (!File->IsDirectory && !File->IsSymLink &&
-          TimeZoneDifferenceApplicable(File->ModificationFmt))
+          File->IsTimeShiftingApplicable())
       {
         FDetectTimeDifference = false;
 

+ 0 - 1
source/core/FtpFileSystem.h

@@ -188,7 +188,6 @@ protected:
   bool __fastcall SupportsReadingFile();
   void __fastcall AutoDetectTimeDifference(TRemoteFileList * FileList);
   void __fastcall ApplyTimeDifference(TRemoteFile * File);
-  bool __fastcall TimeZoneDifferenceApplicable(TModificationFmt ModificationFmt);
   UnicodeString __fastcall DoCalculateFileChecksum(bool UsingHashCommand, const UnicodeString & Alg, TRemoteFile * File);
   void __fastcall DoCalculateFilesChecksum(bool UsingHashCommand, const UnicodeString & Alg,
     TStrings * FileList, TStrings * Checksums,

+ 10 - 5
source/core/RemoteFiles.cpp

@@ -7,6 +7,7 @@
 
 #include <SysUtils.hpp>
 #include <StrUtils.hpp>
+#include <DateUtils.hpp>
 
 #include "Exceptions.h"
 #include "Interface.h"
@@ -971,15 +972,19 @@ bool __fastcall TRemoteFile::GetBrokenLink()
   // "!FLinkTo.IsEmpty()" removed because it does not work with SFTP
 }
 //---------------------------------------------------------------------------
-void __fastcall TRemoteFile::ShiftTime(const TDateTime & Difference)
+bool __fastcall TRemoteFile::IsTimeShiftingApplicable()
 {
-  double D = double(Difference);
-  if ((D != 0) && (FModificationFmt != mfMDY))
+  return (ModificationFmt == mfMDHM) || (ModificationFmt == mfFull);
+}
+//---------------------------------------------------------------------------
+void __fastcall TRemoteFile::ShiftTimeInSeconds(__int64 Seconds)
+{
+  if ((Seconds != 0) && IsTimeShiftingApplicable())
   {
     assert(int(FModification) != 0);
-    FModification = double(FModification) + D;
+    FModification = IncSecond(FModification, Seconds);
     assert(int(FLastAccess) != 0);
-    FLastAccess = double(FLastAccess) + D;
+    FLastAccess = IncSecond(FLastAccess, Seconds);
   }
 }
 //---------------------------------------------------------------------------

+ 2 - 1
source/core/RemoteFiles.h

@@ -141,7 +141,8 @@ public:
   virtual __fastcall ~TRemoteFile();
   TRemoteFile * __fastcall Duplicate(bool Standalone = true) const;
 
-  void __fastcall ShiftTime(const TDateTime & Difference);
+  void __fastcall ShiftTimeInSeconds(__int64 Seconds);
+  bool __fastcall IsTimeShiftingApplicable();
   void __fastcall Complete();
 
   __property int Attr = { read = GetAttr };

+ 1 - 1
source/core/ScpFileSystem.cpp

@@ -1102,7 +1102,7 @@ TRemoteFile * __fastcall TSCPFileSystem::CreateRemoteFile(
   {
     File->Terminal = FTerminal;
     File->ListingStr = ListingStr;
-    File->ShiftTime(FTerminal->SessionData->TimeDifference);
+    File->ShiftTimeInSeconds(TimeToSeconds(FTerminal->SessionData->TimeDifference));
     File->Complete();
   }
   catch(...)

+ 20 - 15
source/core/Script.cpp

@@ -349,7 +349,7 @@ void __fastcall TScript::Init()
   FCommands->Register(L"man", 0, SCRIPT_HELP_HELP, &HelpProc, 0, -1, false);
   // the call command does not have switches itself, but the commands may have
   FCommands->Register(L"call", SCRIPT_CALL_DESC2, SCRIPT_CALL_HELP2, &CallProc, 1, -1, true);
-  FCommands->Register(L"!", 0, SCRIPT_CALL_HELP2, &CallProc, 1, -1, false);
+  FCommands->Register(L"!", 0, SCRIPT_CALL_HELP2, &CallProc, 1, -1, true);
   FCommands->Register(L"pwd", SCRIPT_PWD_DESC, SCRIPT_PWD_HELP, &PwdProc, 0, 0, false);
   FCommands->Register(L"cd", SCRIPT_CD_DESC, SCRIPT_CD_HELP, &CdProc, 0, 1, false);
   FCommands->Register(L"ls", SCRIPT_LS_DESC, SCRIPT_LS_HELP2, &LsProc, 0, 1, false);
@@ -363,11 +363,11 @@ void __fastcall TScript::Init()
   FCommands->Register(L"symlink", 0, SCRIPT_LN_HELP, &LnProc, 2, 2, false);
   FCommands->Register(L"mkdir", SCRIPT_MKDIR_DESC, SCRIPT_MKDIR_HELP, &MkDirProc, 1, 1, false);
   FCommands->Register(L"get", SCRIPT_GET_DESC, SCRIPT_GET_HELP7, &GetProc, 1, -1, true);
-  FCommands->Register(L"recv", 0, SCRIPT_GET_HELP7, &GetProc, 1, -1, false);
-  FCommands->Register(L"mget", 0, SCRIPT_GET_HELP7, &GetProc, 1, -1, false);
+  FCommands->Register(L"recv", 0, SCRIPT_GET_HELP7, &GetProc, 1, -1, true);
+  FCommands->Register(L"mget", 0, SCRIPT_GET_HELP7, &GetProc, 1, -1, true);
   FCommands->Register(L"put", SCRIPT_PUT_DESC, SCRIPT_PUT_HELP7, &PutProc, 1, -1, true);
-  FCommands->Register(L"send", 0, SCRIPT_PUT_HELP7, &PutProc, 1, -1, false);
-  FCommands->Register(L"mput", 0, SCRIPT_PUT_HELP7, &PutProc, 1, -1, false);
+  FCommands->Register(L"send", 0, SCRIPT_PUT_HELP7, &PutProc, 1, -1, true);
+  FCommands->Register(L"mput", 0, SCRIPT_PUT_HELP7, &PutProc, 1, -1, true);
   FCommands->Register(L"option", SCRIPT_OPTION_DESC, SCRIPT_OPTION_HELP7, &OptionProc, -1, 2, false);
   FCommands->Register(L"ascii", 0, SCRIPT_OPTION_HELP7, &AsciiProc, 0, 0, false);
   FCommands->Register(L"binary", 0, SCRIPT_OPTION_HELP7, &BinaryProc, 0, 0, false);
@@ -606,18 +606,23 @@ TStrings * __fastcall TScript::CreateFileList(TScriptProcParams * Parameters, in
           TFileMasks Mask;
           Mask.SetMask(UnixExtractFileName(FileName));
           bool AnyFound = false;
-          for (int i = 0; i < FileList->Count; i++)
+
+          // Can happen in "batch continue" mode
+          if (FileList != NULL)
           {
-            TRemoteFile * File = FileList->Files[i];
-            TFileMasks::TParams Params;
-            Params.Size = File->Size;
-            Params.Modification = File->Modification;
-            if (!File->IsThisDirectory && !File->IsParentDirectory &&
-                Mask.Matches(File->FileName, false, UnicodeString(), &Params))
+            for (int i = 0; i < FileList->Count; i++)
             {
-              Result->AddObject(FileDirectory + File->FileName,
-                FLAGSET(ListType, fltQueryServer) ? File->Duplicate() : NULL);
-              AnyFound = true;
+              TRemoteFile * File = FileList->Files[i];
+              TFileMasks::TParams Params;
+              Params.Size = File->Size;
+              Params.Modification = File->Modification;
+              if (!File->IsThisDirectory && !File->IsParentDirectory &&
+                  Mask.Matches(File->FileName, false, UnicodeString(), &Params))
+              {
+                Result->AddObject(FileDirectory + File->FileName,
+                  FLAGSET(ListType, fltQueryServer) ? File->Duplicate() : NULL);
+                AnyFound = true;
+              }
             }
           }
 

+ 6 - 1
source/core/SecureShell.cpp

@@ -253,6 +253,7 @@ Conf * __fastcall TSecureShell::StoreToConfig(TSessionData * Data, bool Simple)
   conf_set_int(conf, CONF_sshbug_maxpkt2, Data->Bug[sbMaxPkt2]);
   conf_set_int(conf, CONF_sshbug_ignore2, Data->Bug[sbIgnore2]);
   conf_set_int(conf, CONF_sshbug_winadj, Data->Bug[sbWinAdj]);
+  conf_set_int(conf, CONF_sshbug_oldgex2, Data->Bug[sbOldGex2]);
 
   if (!Data->TunnelPortFwd.IsEmpty())
   {
@@ -440,6 +441,10 @@ void __fastcall TSecureShell::Open()
   {
     FSshImplementation = sshiTitan;
   }
+  else if (ContainsText(FSessionInfo.SshImplementation, L"CerberusFTPServer"))
+  {
+    FSshImplementation = sshiCerberus;
+  }
   else
   {
     FSshImplementation = sshiUnknown;
@@ -2308,7 +2313,7 @@ void __fastcall TSecureShell::CollectUsage()
   {
     Configuration->Usage->Inc(L"OpenedSessionsSSHServU");
   }
-  else if (ContainsText(FSessionInfo.SshImplementation, L"CerberusFTPServer"))
+  else if (SshImplementation == sshiCerberus)
   {
     // Ntb, Cerberus can also be detected using vendor-id extension
     // Cerberus FTP Server 7.0.5.3 (70005003) by Cerberus, LLC

+ 1 - 1
source/core/SecureShell.h

@@ -17,7 +17,7 @@ typedef struct _WSANETWORKEVENTS WSANETWORKEVENTS;
 typedef UINT_PTR SOCKET;
 typedef std::set<SOCKET> TSockets;
 struct TPuttyTranslation;
-enum TSshImplementation { sshiUnknown, sshiOpenSSH, sshiProFTPD, sshiBitvise, sshiTitan };
+enum TSshImplementation { sshiUnknown, sshiOpenSSH, sshiProFTPD, sshiBitvise, sshiTitan, sshiOpenVMS, sshiCerberus };
 //---------------------------------------------------------------------------
 class TSecureShell
 {

+ 6 - 1
source/core/SessionData.cpp

@@ -601,6 +601,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & Rewr
   READ_BUG(Rekey2);
   READ_BUG(MaxPkt2);
   READ_BUG(Ignore2);
+  READ_BUG(OldGex2);
   READ_BUG(WinAdj);
   #undef READ_BUG
 
@@ -819,7 +820,10 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
       WRITE_DATA(Bool, IgnoreLsWarnings);
       WRITE_DATA(Integer, SCPLsFullTime);
       WRITE_DATA(Bool, Scp1Compatibility);
-      if (TimeDifferenceAuto)
+      // TimeDifferenceAuto is valid for FTP protocol only.
+      // For other protocols it's typically true (default value),
+      // but ignored so TimeDifference is still taken into account (SCP only actually)
+      if (TimeDifferenceAuto && (FSProtocol == fsFTP))
       {
         // Have to delete it as TimeDifferenceAuto is not saved when enabled,
         // but the default is derived from value of TimeDifference.
@@ -873,6 +877,7 @@ void __fastcall TSessionData::Save(THierarchicalStorage * Storage,
     WRITE_BUG(Rekey2);
     WRITE_BUG(MaxPkt2);
     WRITE_BUG(Ignore2);
+    WRITE_BUG(OldGex2);
     WRITE_BUG(WinAdj);
     #undef WRITE_BUG
     #undef WRITE_DATA_CONV_FUNC

+ 1 - 1
source/core/SessionData.h

@@ -23,7 +23,7 @@ enum TSshProt { ssh1only, ssh1, ssh2, ssh2only };
 enum TKex { kexWarn, kexDHGroup1, kexDHGroup14, kexDHGEx, kexRSA };
 #define KEX_COUNT (kexRSA+1)
 enum TSshBug { sbIgnore1, sbPlainPW1, sbRSA1, sbHMAC2, sbDeriveKey2, sbRSAPad2,
-  sbPKSessID2, sbRekey2, sbMaxPkt2, sbIgnore2, sbWinAdj };
+  sbPKSessID2, sbRekey2, sbMaxPkt2, sbIgnore2, sbOldGex2, sbWinAdj };
 #define BUG_COUNT (sbWinAdj+1)
 enum TSftpBug { sbSymlink, sbSignedTS };
 #define SFTP_BUG_COUNT (sbSignedTS+1)

+ 4 - 1
source/core/SftpFileSystem.cpp

@@ -3406,7 +3406,10 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
           }
         }
 
-        if ((FVersion >= 6) && ListingPacket.CanGetBool())
+        if ((FVersion >= 6) &&
+            // As of 7.0.9 the Cerberus SFTP server always sets the end-of-list to true.
+            (FSecureShell->SshImplementation != sshiCerberus) &&
+            ListingPacket.CanGetBool())
         {
           isEOF = ListingPacket.GetBool();
         }

+ 18 - 1
source/forms/Console.cpp

@@ -44,6 +44,7 @@ __fastcall TConsoleDialog::TConsoleDialog(TComponent* AOwner)
   FPrevTerminalClose = NULL;;
   FLastTerminal = NULL;
   FDirectoryChanged = false;
+  FExecuting = false;
   OutputMemo->Color = clBlack;
   OutputMemo->Font->Color = (TColor)0x00BBBBBB;
   FixComboBoxResizeBug(CommandEdit);
@@ -113,8 +114,12 @@ void __fastcall TConsoleDialog::DoChangeDirectory(TObject * Sender)
 void __fastcall TConsoleDialog::UpdateControls()
 {
   DirectoryLabel->Caption = (FTerminal ? FTerminal->CurrentDirectory : UnicodeString());
+  // Disabling buttons while executing to prevent recursive execution,
+  // now that message queue is processed while command is executing.
   EnableControl(ExecuteButton,
-    (FTerminal != NULL) ? FTerminal->AllowedAnyCommand(CommandEdit->Text) : false);
+    ((FTerminal != NULL) ? FTerminal->AllowedAnyCommand(CommandEdit->Text) : false) &&
+    !FExecuting);
+  EnableControl(CancelBtn, !FExecuting);
 }
 //---------------------------------------------------------------------
 bool __fastcall TConsoleDialog::Execute(const UnicodeString Command,
@@ -197,6 +202,10 @@ void __fastcall TConsoleDialog::DoExecuteCommand()
     UnicodeString Command = CommandEdit->Text;
     OutputMemo->Lines->Add(FORMAT(L"%s$ %s", (CurrentDirectory, Command)));
     Configuration->Usage->Inc(L"RemoteCommandExecutions");
+    TAutoFlag ExecutingFlag(FExecuting);
+    UpdateControls();
+    // give a chance for disabled buttons to redraw
+    Application->ProcessMessages();
     FTerminal->AnyCommand(Command, AddLine);
   }
   __finally
@@ -211,6 +220,7 @@ void __fastcall TConsoleDialog::DoExecuteCommand()
         FTerminal->ReadCurrentDirectory();
       }
     }
+    UpdateControls();
   }
 
   if (CurrentDirectory != FTerminal->CurrentDirectory)
@@ -337,3 +347,10 @@ void __fastcall TConsoleDialog::OutputMemoContextPopup(TObject * Sender,
   MenuPopup(Sender, MousePos, Handled);
 }
 //---------------------------------------------------------------------------
+void __fastcall TConsoleDialog::FormCloseQuery(TObject * /*Sender*/, bool & CanClose)
+{
+  // Probably not necessary as this is called from top-level dialog loop,
+  // where we do not get until ExecuteButtonClick exists.
+  CanClose = !FExecuting;
+}
+//---------------------------------------------------------------------------

+ 1 - 0
source/forms/Console.dfm

@@ -49,6 +49,7 @@ object ConsoleDialog: TConsoleDialog
     0000000000000000000000000000000000000000000000000000000000000000
     0000000000000000000000000000000000000000000000000000FFFF0000}
   OldCreateOrder = True
+  OnCloseQuery = FormCloseQuery
   OnShow = FormShow
   DesignSize = (
     551

+ 2 - 0
source/forms/Console.h

@@ -50,6 +50,7 @@ __published:
   void __fastcall FormShow(TObject *Sender);
   void __fastcall OutputMemoContextPopup(TObject *Sender, TPoint &MousePos,
           bool &Handled);
+  void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
 
 private:
   TTerminal * FTerminal;
@@ -59,6 +60,7 @@ private:
   TRect FAutoBounds;
   bool FClearExceptionOnFail;
   bool FDirectoryChanged;
+  bool FExecuting;
 
   void __fastcall DoExecuteCommand();
   void __fastcall ExecuteCommand();

+ 1 - 1
source/forms/Login.dfm

@@ -299,7 +299,7 @@ object LoginDialog: TLoginDialog
         object SaveButton: TButton
           Left = 12
           Top = 193
-          Width = 96
+          Width = 98
           Height = 25
           Action = SaveSessionAction
           Anchors = [akLeft, akBottom]

+ 1 - 1
source/forms/Preferences.cpp

@@ -2172,7 +2172,7 @@ void __fastcall TPreferencesDialog::NavigationTreeChanging(TObject * /*Sender*/,
 //---------------------------------------------------------------------------
 void __fastcall TPreferencesDialog::LanguagesGetMoreButtonClick(TObject * /*Sender*/)
 {
-  OpenBrowser(LoadStr(LOCALES_URL));
+  OpenBrowser(ProgramUrl(LoadStr(LOCALES_URL)));
 }
 //---------------------------------------------------------------------------
 void __fastcall TPreferencesDialog::CommanderClick(TObject * /*Sender*/)

+ 1 - 0
source/putty/PUTTY.H

@@ -837,6 +837,7 @@ void cleanup_exit(int);
     X(INT, NONE, sshbug_rekey2) \
     X(INT, NONE, sshbug_maxpkt2) \
     X(INT, NONE, sshbug_ignore2) \
+    X(INT, NONE, sshbug_oldgex2) \
     X(INT, NONE, sshbug_winadj) \
     /*                                                                \
      * ssh_simple means that we promise never to open any channel     \

+ 35 - 3
source/putty/SSH.C

@@ -87,7 +87,8 @@
 #define SSH2_MSG_NEWKEYS                          21	/* 0x15 */
 #define SSH2_MSG_KEXDH_INIT                       30	/* 0x1e */
 #define SSH2_MSG_KEXDH_REPLY                      31	/* 0x1f */
-#define SSH2_MSG_KEX_DH_GEX_REQUEST               30	/* 0x1e */
+#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD           30	/* 0x1e */
+#define SSH2_MSG_KEX_DH_GEX_REQUEST               34	/* 0x1e */
 #define SSH2_MSG_KEX_DH_GEX_GROUP                 31	/* 0x1f */
 #define SSH2_MSG_KEX_DH_GEX_INIT                  32	/* 0x20 */
 #define SSH2_MSG_KEX_DH_GEX_REPLY                 33	/* 0x21 */
@@ -197,6 +198,10 @@ static const char *const ssh2_disconnect_reasons[] = {
 #define BUG_SSH2_MAXPKT				256
 #define BUG_CHOKES_ON_SSH2_IGNORE               512
 #define BUG_CHOKES_ON_WINADJ                   1024
+#define BUG_SSH2_OLDGEX                        4096
+
+#define DH_MIN_SIZE 1024
+#define DH_MAX_SIZE 8192
 
 /*
  * Codes for terminal modes.
@@ -368,6 +373,7 @@ static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)
     translate(SSH2_MSG_NEWKEYS);
     translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);
     translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);
+    translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX);
     translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
     translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
     translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
@@ -2620,6 +2626,17 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring)
 	logevent("We believe remote version has SSH-2 ignore bug");
     }
 
+    if (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == FORCE_ON ||
+	(conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == AUTO &&
+	 (wc_match("OpenSSH_2.[235]*", imp)))) {
+	/*
+	 * These versions only support the original (pre-RFC4419)
+	 * SSH-2 GEX request.
+	 */
+	ssh->remote_bugs |= BUG_SSH2_OLDGEX;
+	logevent("We believe remote version has outdated SSH-2 GEX");
+    }
+
     if (conf_get_int(ssh->conf, CONF_sshbug_winadj) == FORCE_ON) {
 	/*
 	 * Servers that don't support our winadj request for one
@@ -6066,8 +6083,19 @@ static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
              * much data.
              */
             s->pbits = 512 << ((s->nbits - 1) / 64);
-            s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);
-            ssh2_pkt_adduint32(s->pktout, s->pbits);
+            if (s->pbits < DH_MIN_SIZE)
+                s->pbits = DH_MIN_SIZE;
+            if (s->pbits > DH_MAX_SIZE)
+                s->pbits = DH_MAX_SIZE;
+            if ((ssh->remote_bugs & BUG_SSH2_OLDGEX)) {
+                s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
+                ssh2_pkt_adduint32(s->pktout, s->pbits);
+            } else {
+                s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_DH_GEX_REQUEST);
+                ssh2_pkt_adduint32(s->pktout, DH_MIN_SIZE);
+                ssh2_pkt_adduint32(s->pktout, s->pbits);
+                ssh2_pkt_adduint32(s->pktout, DH_MAX_SIZE);
+            }
             ssh2_pkt_send_noqueue(ssh, s->pktout);
 
             crWaitUntilV(pktin);
@@ -6135,7 +6163,11 @@ static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
 
         hash_string(ssh->kex->hash, ssh->exhash, s->hostkeydata, s->hostkeylen);
         if (!ssh->kex->pdata) {
+            if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))
+                hash_uint32(ssh->kex->hash, ssh->exhash, DH_MIN_SIZE);
             hash_uint32(ssh->kex->hash, ssh->exhash, s->pbits);
+            if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))
+                hash_uint32(ssh->kex->hash, ssh->exhash, DH_MAX_SIZE);
             hash_mpint(ssh->kex->hash, ssh->exhash, s->p);
             hash_mpint(ssh->kex->hash, ssh->exhash, s->g);
         }

+ 1 - 1
source/windows/Setup.cpp

@@ -754,7 +754,7 @@ UnicodeString __fastcall GetUsageData()
   return Configuration->Usage->Serialize();
 }
 //---------------------------------------------------------------------------
-static UnicodeString ProgramUrl(UnicodeString URL)
+UnicodeString __fastcall ProgramUrl(UnicodeString URL)
 {
   TVSFixedFileInfo * FileInfo = Configuration->FixedApplicationInfo;
   UnicodeString CurrentVersionStr =

+ 1 - 0
source/windows/Setup.h

@@ -20,5 +20,6 @@ UnicodeString __fastcall CampaignUrl(UnicodeString URL);
 void __fastcall UpdateJumpList(TStrings * SessionNames, TStrings * WorkspaceNames);
 bool __fastcall AnyOtherInstanceOfSelf();
 bool __fastcall IsInstalled();
+UnicodeString __fastcall ProgramUrl(UnicodeString URL);
 //---------------------------------------------------------------------------
 #endif

+ 11 - 1
source/windows/WinApi.h

@@ -5,6 +5,16 @@
 #include <shlobj.h>
 //---------------------------------------------------------------------------
 typedef BOOL WINAPI (* ChangeWindowMessageFilterExProc)(
-    HWND hwnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
+  HWND hwnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
+//---------------------------------------------------------------------------
+typedef enum _Monitor_DPI_Type {
+  MDT_Effective_DPI  = 0,
+  MDT_Angular_DPI    = 1,
+  MDT_Raw_DPI        = 2,
+  MDT_Default        = MDT_Effective_DPI
+} MONITOR_DPI_TYPE;
+//---------------------------------------------------------------------------
+typedef HRESULT WINAPI (* GetDpiForMonitorProc)(
+  HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT * dpiX, UINT * dpiY);
 //---------------------------------------------------------------------------
 #endif  // WinApiH

+ 62 - 0
source/windows/WinMain.cpp

@@ -18,6 +18,7 @@
 #include "WinConfiguration.h"
 #include "GUITools.h"
 #include "Tools.h"
+#include "WinApi.h"
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
 //---------------------------------------------------------------------------
@@ -329,8 +330,69 @@ void __fastcall UpdateStaticUsage()
   Configuration->Usage->Set(L"Locale",
     IntToHex(static_cast<int>(WinConfiguration->Locale), 4));
   Configuration->Usage->Set(L"PixelsPerInch", Screen->PixelsPerInch);
+
+  bool PixelsPerInchSystemDiffers = false;
+  bool PixelsPerInchMonitorsDiffer = false;
+  bool PixelsPerInchAxesDiffer = false;
+
+  HINSTANCE ShCoreLibrary = LoadLibrary(L"shcore.dll");
+  if (ShCoreLibrary != NULL)
+  {
+    GetDpiForMonitorProc GetDpiForMonitor =
+      (GetDpiForMonitorProc)GetProcAddress(ShCoreLibrary, "GetDpiForMonitor");
+
+    if (GetDpiForMonitor != NULL)
+    {
+      unsigned int PrimaryDpiX;
+      unsigned int PrimaryDpiY;
+
+      for (int Index = 0; Index < Screen->MonitorCount; Index++)
+      {
+        unsigned int DpiX;
+        unsigned int DpiY;
+        GetDpiForMonitor(Screen->Monitors[0]->Handle, MDT_Default, &DpiX, &DpiY);
+
+        if (DpiX != DpiY)
+        {
+          PixelsPerInchAxesDiffer = true;
+        }
+
+        if (Index == 0)
+        {
+          PrimaryDpiX = DpiX;
+          PrimaryDpiY = DpiY;
+
+          // PixelsPerInch is GetDeviceCaps(DC, LOGPIXELSY)
+          if (DpiY != (unsigned int)Screen->PixelsPerInch)
+          {
+            PixelsPerInchSystemDiffers = true;
+          }
+        }
+        else
+        {
+          if ((DpiX != PrimaryDpiX) ||
+              (DpiY != PrimaryDpiY))
+          {
+            PixelsPerInchMonitorsDiffer = true;
+          }
+        }
+      }
+    }
+  }
+
+  if (PixelsPerInchSystemDiffers)
+  {
+    Configuration->Usage->Inc(L"PixelsPerInchSystemDiffered");
+  }
+  Configuration->Usage->Set(L"PixelsPerInchMonitorsDiffer", PixelsPerInchMonitorsDiffer);
+  Configuration->Usage->Set(L"PixelsPerInchAxesDiffer", PixelsPerInchAxesDiffer);
+
   Configuration->Usage->Set(L"WorkAreaWidth", Screen->WorkAreaWidth);
   Configuration->Usage->Set(L"WorkAreaHeight", Screen->WorkAreaHeight);
+  HDC DC = GetDC(NULL);
+  int Planes = GetDeviceCaps(DC, PLANES);
+  int BitsPixel = GetDeviceCaps(DC, BITSPIXEL);
+  Configuration->Usage->Set(L"ColorDepth", Planes * BitsPixel);
   Configuration->Usage->Set(L"MonitorCount", Screen->MonitorCount);
   Configuration->Usage->Set(L"NotUseThemes", !UseThemes());
   Configuration->Usage->Set(L"ThemeDefaultFontSize", Application->DefaultFont->Size);