Bläddra i källkod

Bug 1995: Support S3 servers without TLS encryption

https://winscp.net/tracker/1995

Source commit: ab6c0e4140430caa3512fcc6617e5ad98b57a30a
Martin Prikryl 3 år sedan
förälder
incheckning
1385cd78a5

+ 14 - 7
dotnet/Session.cs

@@ -1911,11 +1911,11 @@ namespace WinSCP
         {
             using (Logger.CreateCallstack())
             {
-                if (sessionOptions.WebdavSecure)
+                if (sessionOptions.Secure)
                 {
-                    if (sessionOptions.Protocol != Protocol.Webdav)
+                    if ((sessionOptions.Protocol != Protocol.Webdav) && (sessionOptions.Protocol != Protocol.S3))
                     {
-                        throw Logger.WriteException(new ArgumentException("SessionOptions.WebdavSecure is set, but SessionOptions.Protocol is not Protocol.Webdav."));
+                        throw Logger.WriteException(new ArgumentException("SessionOptions.Secure is set, but SessionOptions.Protocol is not Protocol.Webdav nor Protocol.S3."));
                     }
                 }
 
@@ -1935,7 +1935,7 @@ namespace WinSCP
                         break;
 
                     case Protocol.Webdav:
-                        if (!sessionOptions.WebdavSecure)
+                        if (!sessionOptions.Secure)
                         {
                             head = "dav://";
                         }
@@ -1946,7 +1946,14 @@ namespace WinSCP
                         break;
 
                     case Protocol.S3:
-                        head = "s3://";
+                        if (!sessionOptions.Secure)
+                        {
+                            head = "s3plain://";
+                        }
+                        else
+                        {
+                            head = "s3://";
+                        }
                         break;
 
                     default:
@@ -2101,7 +2108,7 @@ namespace WinSCP
                 {
                     if (!sessionOptions.IsTls)
                     {
-                        throw Logger.WriteException(new ArgumentException("SessionOptions.TlsClientCertificatePath is set, but neither SessionOptions.FtpSecure nor SessionOptions.WebdavSecure is enabled nor is the protocol S3."));
+                        throw Logger.WriteException(new ArgumentException("SessionOptions.TlsClientCertificatePath is set, but neither SessionOptions.FtpSecure nor SessionOptions.Secure is enabled."));
                     }
                     switches.Add(FormatSwitch("clientcert", sessionOptions.TlsClientCertificatePath));
                 }
@@ -2134,7 +2141,7 @@ namespace WinSCP
                 {
                     if (!sessionOptions.IsTls)
                     {
-                        throw Logger.WriteException(new ArgumentException("SessionOptions.TlsHostCertificateFingerprint or SessionOptions.GiveUpSecurityAndAcceptAnyTlsHostCertificate is set, but neither SessionOptions.FtpSecure nor SessionOptions.WebdavSecure is enabled nor is the protocol S3."));
+                        throw Logger.WriteException(new ArgumentException("SessionOptions.TlsHostCertificateFingerprint or SessionOptions.GiveUpSecurityAndAcceptAnyTlsHostCertificate is set, but neither SessionOptions.FtpSecure nor SessionOptions.Secure is enabled."));
                     }
                     string tlsHostCertificateFingerprint = sessionOptions.TlsHostCertificateFingerprint;
                     if (sessionOptions.GiveUpSecurityAndAcceptAnyTlsHostCertificate)

+ 11 - 4
dotnet/SessionOptions.cs

@@ -69,6 +69,7 @@ namespace WinSCP
         public string PrivateKeyPassphrase { get { return GetPassword(_securePrivateKeyPassphrase); } set { SetPassword(ref _securePrivateKeyPassphrase, value); } }
         public SecureString SecurePrivateKeyPassphrase { get { return _securePrivateKeyPassphrase; } set { _securePrivateKeyPassphrase = value; } }
         public string RootPath { get { return _rootPath; } set { SetRootPath(value); } }
+        public bool Secure { get; set; }
 
         // SSH
         public string SshHostKeyFingerprint { get { return _sshHostKeyFingerprint; } set { SetSshHostKeyFingerprint(value); } }
@@ -85,7 +86,8 @@ namespace WinSCP
         public FtpSecure FtpSecure { get; set; }
 
         // WebDAV
-        public bool WebdavSecure { get; set; }
+        [Obsolete("Use Secure")]
+        public bool WebdavSecure { get { return Secure; } set { Secure = value; } }
         [Obsolete("Use RootPath")]
         public string WebdavRoot { get { return RootPath; } set { RootPath = value; } }
 
@@ -304,7 +306,12 @@ namespace WinSCP
                      protocol.Equals("https", StringComparison.OrdinalIgnoreCase))
             {
                 Protocol = Protocol.Webdav;
-                WebdavSecure = true;
+                Secure = true;
+            }
+            else if (protocol.Equals("s3plain", StringComparison.OrdinalIgnoreCase))
+            {
+                Protocol = Protocol.S3;
+                Secure = false;
             }
             else if (protocol.Equals("s3", StringComparison.OrdinalIgnoreCase))
             {
@@ -359,8 +366,7 @@ namespace WinSCP
         {
             return
                 ((Protocol == Protocol.Ftp) && (FtpSecure != FtpSecure.None)) ||
-                ((Protocol == Protocol.Webdav) && WebdavSecure) ||
-                (Protocol == Protocol.S3);
+                (((Protocol == Protocol.Webdav) || (Protocol == Protocol.S3)) && Secure);
         }
 
         private void SetSshHostKeyFingerprint(string s)
@@ -419,6 +425,7 @@ namespace WinSCP
             if ((_protocol == Protocol.S3) && string.IsNullOrEmpty(HostName))
             {
                 HostName = "s3.amazonaws.com";
+                Secure = true;
             }
         }
 

+ 6 - 3
libs/libs3/src/request.c

@@ -1248,9 +1248,12 @@ static S3Status setup_neon(Request *request,
 
     // WINSCP (neon sets "nodelay" unconditionally)
 
-    // WINSCP (we should verify peer always)
-    ne_ssl_set_verify(request->NeonSession, neon_ssl_callback, request);
-    ne_ssl_trust_default_ca(request->NeonSession);
+    if (params->bucketContext.protocol == S3ProtocolHTTPS)
+    {
+      // WINSCP (we should verify peer always)
+      ne_ssl_set_verify(request->NeonSession, neon_ssl_callback, request);
+      ne_ssl_trust_default_ca(request->NeonSession);
+    }
 
     // Follow any redirection directives that S3 sends
     // TODO

+ 1 - 1
source/core/S3FileSystem.cpp

@@ -228,7 +228,7 @@ void __fastcall TS3FileSystem::Open()
   FHostName = UTF8String(Data->HostNameExpanded);
   FPortSuffix = UTF8String();
   int ADefaultPort = FTerminal->SessionData->GetDefaultPort();
-  DebugAssert(ADefaultPort == HTTPSPortNumber);
+  DebugAssert((ADefaultPort == HTTPSPortNumber) || (ADefaultPort == HTTPPortNumber));
   if (FTerminal->SessionData->PortNumber != ADefaultPort)
   {
     FPortSuffix = UTF8String(FORMAT(L":%d", (FTerminal->SessionData->PortNumber)));

+ 16 - 2
source/core/SessionData.cpp

@@ -66,6 +66,7 @@ const UnicodeString FtpesProtocol(L"ftpes");
 const UnicodeString WebDAVProtocol(L"dav");
 const UnicodeString WebDAVSProtocol(L"davs");
 const UnicodeString S3Protocol(L"s3");
+const UnicodeString S3PlainProtocol(L"s3plain");
 const UnicodeString SshProtocol(L"ssh");
 const UnicodeString WinSCPProtocolPrefix(L"winscp-");
 const wchar_t UrlParamSeparator = L';';
@@ -2110,8 +2111,14 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
     AFtps = ftpsImplicit;
     DefaultProtocolPortNumber = HTTPSPortNumber;
   }
+  else if (IsProtocolUrl(Url, S3PlainProtocol, ProtocolLen) ||
+           IsProtocolUrl(Url, HttpProtocol, ProtocolLen))
+  {
+    AFSProtocol = fsS3;
+    AFtps = ftpsNone;
+    DefaultProtocolPortNumber = HTTPPortNumber;
+  }
   else if (IsProtocolUrl(Url, S3Protocol, ProtocolLen) ||
-           IsProtocolUrl(Url, HttpProtocol, ProtocolLen) || // sic
            IsProtocolUrl(Url, HttpsProtocol, ProtocolLen))
   {
     AFSProtocol = fsS3;
@@ -3402,7 +3409,14 @@ UnicodeString __fastcall TSessionData::GetProtocolUrl(bool HttpForWebDAV)
       break;
 
     case fsS3:
-      Url = S3Protocol;
+      if (Ftps == ftpsImplicit)
+      {
+        Url = S3Protocol;
+      }
+      else
+      {
+        Url = S3PlainProtocol;
+      }
       break;
   }
 

+ 18 - 6
source/forms/Login.cpp

@@ -128,7 +128,7 @@ void __fastcall TLoginDialog::InitControls()
   int FtpsNoneIndex = FtpsToIndex(ftpsNone);
   int FtpsImplicitIndex = FtpsToIndex(ftpsImplicit);
   // Items item setter is implemented as deleting and re-adding the item. If we do it for the last item
-  // (explicit for FTP, implicit for WebDAV), the ItemIndex is effectivelly reset to -1.
+  // (explicit for FTP, implicit for WebDAV/S3), the ItemIndex is effectivelly reset to -1.
   // This happens when TLS is set in the default session settings.
   // Also as TransferProtocolComboChange is not triggered it results in currupted state in respect to protocol/tls to port number sync.
   int Index = FtpsCombo->ItemIndex;
@@ -651,9 +651,9 @@ void __fastcall TLoginDialog::UpdateControls()
     // session
     FtpsCombo->Visible = Editable && FtpProtocol;
     FtpsLabel->Visible = FtpProtocol;
-    WebDavsCombo->Visible = Editable && WebDavProtocol;
-    WebDavsLabel->Visible = WebDavProtocol;
-    EncryptionView->Visible = !Editable && (FtpProtocol || WebDavProtocol);
+    WebDavsCombo->Visible = Editable && (WebDavProtocol || S3Protocol);
+    WebDavsLabel->Visible = WebDavProtocol || S3Protocol;
+    EncryptionView->Visible = !Editable && (FtpProtocol || WebDavProtocol || S3Protocol);
 
     BasicSshPanel->Visible = SshProtocol;
     BasicFtpPanel->Visible = FtpProtocol && Editable;
@@ -2128,7 +2128,8 @@ int __fastcall TLoginDialog::FtpsToIndex(TFtps Ftps)
 //---------------------------------------------------------------------------
 TFtps __fastcall TLoginDialog::GetFtps()
 {
-  int Index = ((GetFSProtocol(false) == fsWebDAV) ? WebDavsCombo->ItemIndex : FtpsCombo->ItemIndex);
+  TFSProtocol FSProtocol = GetFSProtocol(false);
+  int Index = (((FSProtocol == fsWebDAV) || (FSProtocol == fsS3)) ? WebDavsCombo->ItemIndex : FtpsCombo->ItemIndex);
   TFtps Ftps;
   switch (Index)
   {
@@ -2187,7 +2188,7 @@ void __fastcall TLoginDialog::TransferProtocolComboChange(TObject * Sender)
     {
       // Note that this happens even when loading the session
       // But the values will get overwritten.
-      FtpsCombo->ItemIndex = FtpsToIndex(ftpsImplicit);
+      WebDavsCombo->ItemIndex = FtpsToIndex(ftpsImplicit);
       HostNameEdit->Text = S3HostName;
     }
     else
@@ -2220,6 +2221,12 @@ void __fastcall TLoginDialog::TransferProtocolComboChange(TObject * Sender)
     S3CredentialsEnvCheck->Checked = false;
   }
 
+  UpdatePortWithProtocol();
+  DataChange(Sender);
+}
+//---------------------------------------------------------------------------
+void TLoginDialog::UpdatePortWithProtocol()
+{
   int ADefaultPort = DefaultPort();
   if (!NoUpdate && FUpdatePortWithProtocol)
   {
@@ -2237,6 +2244,11 @@ void __fastcall TLoginDialog::TransferProtocolComboChange(TObject * Sender)
     }
   }
   FDefaultPort = ADefaultPort;
+}
+//---------------------------------------------------------------------------
+void __fastcall TLoginDialog::EncryptionComboChange(TObject * Sender)
+{
+  UpdatePortWithProtocol();
   DataChange(Sender);
 }
 //---------------------------------------------------------------------------

+ 2 - 2
source/forms/Login.dfm

@@ -263,7 +263,7 @@ object LoginDialog: TLoginDialog
           Height = 21
           Style = csDropDownList
           TabOrder = 2
-          OnChange = TransferProtocolComboChange
+          OnChange = EncryptionComboChange
           Items.Strings = (
             'No encryption'
             'TLS/SSL Implicit encryptionX'
@@ -276,7 +276,7 @@ object LoginDialog: TLoginDialog
           Height = 21
           Style = csDropDownList
           TabOrder = 3
-          OnChange = TransferProtocolComboChange
+          OnChange = EncryptionComboChange
           Items.Strings = (
             'No encryptionX'
             'TLS/SSL Implicit encryptionX')

+ 2 - 0
source/forms/Login.h

@@ -290,6 +290,7 @@ __published:
   void __fastcall SearchSiteActionExecute(TObject *Sender);
   void __fastcall PanelMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
   void __fastcall S3CredentialsEnvCheckClick(TObject *Sender);
+  void __fastcall EncryptionComboChange(TObject *Sender);
 
 private:
   int NoUpdate;
@@ -411,6 +412,7 @@ private:
   void UpdateS3Credentials();
   void UpdateLoginButton();
   void FloodFill(TBitmap * Bitmap, int X, int Y);
+  void UpdatePortWithProtocol();
 
 protected:
   void __fastcall Default();