Explorar el Código

Bug 1638: Allow authentication with empty passwords in scripting

https://winscp.net/tracker/1638

Source commit: 5b00160666c5a8153219d5f4ee48bff9a8760c97
Martin Prikryl hace 7 años
padre
commit
e29607679e

+ 2 - 1
dotnet/SessionOptions.cs

@@ -201,8 +201,9 @@ namespace WinSCP
                 string parameters = userInfo;
                 userInfo = CutToChar(ref parameters, ';');
 
+                bool hasPassword = (userInfo.IndexOf(':') >= 0);
                 UserName = EmptyToNull(UriUnescape(CutToChar(ref userInfo, ':')));
-                Password = EmptyToNull(UriUnescape(userInfo));
+                Password = hasPassword ? UriUnescape(userInfo) : null;
 
                 while (!string.IsNullOrEmpty(parameters))
                 {

+ 11 - 0
source/core/Common.cpp

@@ -34,6 +34,7 @@ const wchar_t TokenReplacement = wchar_t(true);
 const UnicodeString LocalInvalidChars(TraceInitStr(L"/\\:*?\"<>|"));
 const UnicodeString PasswordMask(TraceInitStr(L"***"));
 const UnicodeString Ellipsis(TraceInitStr(L"..."));
+const UnicodeString EmptyString(TraceInitStr(L"\1\1\1")); // magic
 //---------------------------------------------------------------------------
 UnicodeString ReplaceChar(UnicodeString Str, wchar_t A, wchar_t B)
 {
@@ -3749,3 +3750,13 @@ UnicodeString __fastcall GetFileMimeType(const UnicodeString & FileName)
   }
   return Result;
 }
+//---------------------------------------------------------------------------
+UnicodeString NormalizeString(const UnicodeString & S)
+{
+  UnicodeString Result = S;
+  if (Result == EmptyString)
+  {
+    Result = UnicodeString();
+  }
+  return Result;
+}

+ 2 - 0
source/core/Common.h

@@ -26,6 +26,7 @@ extern const wchar_t TokenReplacement;
 extern const UnicodeString LocalInvalidChars;
 extern const UnicodeString PasswordMask;
 extern const UnicodeString Ellipsis;
+extern const UnicodeString EmptyString;
 //---------------------------------------------------------------------------
 extern const UnicodeString HttpProtocol;
 extern const UnicodeString HttpsProtocol;
@@ -62,6 +63,7 @@ UnicodeString RemoveMainInstructionsTag(UnicodeString S);
 UnicodeString UnformatMessage(UnicodeString S);
 UnicodeString RemoveInteractiveMsgTag(UnicodeString S);
 UnicodeString RemoveEmptyLines(const UnicodeString & S);
+UnicodeString NormalizeString(const UnicodeString & S);
 bool IsNumber(const UnicodeString Str);
 UnicodeString __fastcall SystemTemporaryDirectory();
 UnicodeString __fastcall GetShellFolderPath(int CSIdl);

+ 1 - 1
source/core/FileMasks.cpp

@@ -1232,7 +1232,7 @@ bool __fastcall TFileCustomCommand::PatternReplacement(
   {
     if (FData.SessionData != NULL)
     {
-      Replacement = FData.SessionData->Password;
+      Replacement = NormalizeString(FData.SessionData->Password);
     }
   }
   else if (SameText(Pattern, L"!#"))

+ 1 - 1
source/core/FtpFileSystem.cpp

@@ -364,7 +364,7 @@ void __fastcall TFTPFileSystem::Open()
 
   UnicodeString HostName = Data->HostNameExpanded;
   UnicodeString UserName = Data->UserNameExpanded;
-  UnicodeString Password = Data->Password;
+  UnicodeString Password = NormalizeString(Data->Password);
   UnicodeString Account = Data->FtpAccount;
   UnicodeString Path = Data->RemoteDirectory;
   int ServerType;

+ 1 - 1
source/core/S3FileSystem.cpp

@@ -98,7 +98,7 @@ void __fastcall TS3FileSystem::Open()
   }
   FAccessKeyId = UTF8String(AccessKeyId);
 
-  UnicodeString SecretAccessKey = UTF8String(Data->Password);
+  UnicodeString SecretAccessKey = UTF8String(NormalizeString(Data->Password));
   if (SecretAccessKey.IsEmpty())
   {
     if (!FTerminal->PromptUser(Data, pkPassword, LoadStr(S3_SECRET_ACCESS_KEY_TITLE), L"",

+ 5 - 5
source/core/SecureShell.cpp

@@ -847,7 +847,7 @@ bool __fastcall TSecureShell::PromptUser(bool /*ToServer*/,
       LogEvent(L"Using stored password.");
       FUI->Information(LoadStr(AUTH_PASSWORD), false);
       Result = true;
-      Results->Strings[0] = FSessionData->Password;
+      Results->Strings[0] = NormalizeString(FSessionData->Password);
       FStoredPasswordTriedForKI = true;
     }
     else if (Instructions.IsEmpty() && !InstructionsRequired && (Prompts->Count == 0))
@@ -863,7 +863,7 @@ bool __fastcall TSecureShell::PromptUser(bool /*ToServer*/,
       LogEvent(L"Using stored password.");
       FUI->Information(LoadStr(AUTH_PASSWORD), false);
       Result = true;
-      Results->Strings[0] = FSessionData->Password;
+      Results->Strings[0] = NormalizeString(FSessionData->Password);
       FStoredPasswordTried = true;
     }
   }
@@ -888,9 +888,9 @@ bool __fastcall TSecureShell::PromptUser(bool /*ToServer*/,
         LogEvent(L"Using stored password and new password.");
         Result = true;
         DebugAssert(Results->Count == 3);
-        Results->Strings[0] = FSessionData->Password;
-        Results->Strings[1] = FSessionData->NewPassword;
-        Results->Strings[2] = FSessionData->NewPassword;
+        Results->Strings[0] = NormalizeString(FSessionData->Password);
+        Results->Strings[1] = NormalizeString(FSessionData->NewPassword);
+        Results->Strings[2] = NormalizeString(FSessionData->NewPassword);
         FStoredPasswordTried = true;
       }
     }

+ 9 - 4
source/core/SessionData.cpp

@@ -1929,10 +1929,15 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
         }
       }
 
+      bool HasPassword = (UserInfo.Pos(L':') > 0);
       UnicodeString RawUserName = CutToChar(UserInfo, L':', false);
       UserName = DecodeUrlChars(RawUserName);
 
       Password = DecodeUrlChars(UserInfo);
+      if (HasPassword && Password.IsEmpty())
+      {
+        Password = EmptyString;
+      }
 
       UnicodeString RemoteDirectoryWithSessionParams = Url.SubString(PSlash, Url.Length() - PSlash + 1);
       ARemoteDirectory = CutToChar(RemoteDirectoryWithSessionParams, UrlParamSeparator, false);
@@ -1954,11 +1959,11 @@ bool __fastcall TSessionData::ParseUrl(UnicodeString Url, TOptions * Options,
       if (MaskedUrl != NULL)
       {
         (*MaskedUrl) += RawUserName;
-        if (!UserInfo.IsEmpty())
+        if (HasPassword)
         {
           (*MaskedUrl) += L":" + PasswordMask;
         }
-        if (!RawUserName.IsEmpty() || !UserInfo.IsEmpty())
+        if (!RawUserName.IsEmpty() || HasPassword)
         {
           (*MaskedUrl) += L"@";
         }
@@ -2912,7 +2917,7 @@ UnicodeString __fastcall TSessionData::GenerateSessionUrl(unsigned int Flags)
 
     if (FLAGSET(Flags, sufPassword) && !Password.IsEmpty())
     {
-      Url += L":" + EncodeUrlString(Password);
+      Url += L":" + EncodeUrlString(NormalizeString(Password));
     }
 
     if (FLAGSET(Flags, sufHostKey) && !HostKey.IsEmpty())
@@ -3175,7 +3180,7 @@ void __fastcall TSessionData::GenerateAssemblyCode(
   }
   if (SessionData->Password != FactoryDefaults->Password)
   {
-    AddAssemblyProperty(Head, Language, L"Password", Password);
+    AddAssemblyProperty(Head, Language, L"Password", NormalizeString(Password));
     SessionData->Password = FactoryDefaults->Password;
   }
 

+ 1 - 1
source/core/SessionInfo.cpp

@@ -1109,7 +1109,7 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
     ADF(L"Session name: %s (%s)", (Data->SessionName, Data->Source));
     ADF(L"Host name: %s (Port: %d)", (Data->HostNameExpanded, Data->PortNumber));
     ADF(L"User name: %s (Password: %s, Key file: %s, Passphrase: %s)",
-      (Data->UserNameExpanded, LogSensitive(Data->Password),
+      (Data->UserNameExpanded, LogSensitive(NormalizeString(Data->Password)),
        LogSensitive(Data->PublicKeyFile), LogSensitive(Data->Passphrase)));
     if (Data->UsesSsh)
     {

+ 1 - 1
source/core/WebDAVFileSystem.cpp

@@ -1866,7 +1866,7 @@ int TWebDAVFileSystem::NeonRequestAuth(
     {
       if (!SessionData->Password.IsEmpty() && !FileSystem->FStoredPasswordTried)
       {
-        APassword = SessionData->Password;
+        APassword = NormalizeString(SessionData->Password);
         FileSystem->FStoredPasswordTried = true;
       }
       else

+ 1 - 1
source/forms/Login.cpp

@@ -502,7 +502,7 @@ void __fastcall TLoginDialog::LoadSession(TSessionData * SessionData)
     bool Editable = IsEditable();
     if (Editable)
     {
-      PasswordEdit->Text = SessionData->Password;
+      PasswordEdit->Text = NormalizeString(SessionData->Password);
     }
     else
     {

+ 1 - 0
source/windows/GUITools.cpp

@@ -188,6 +188,7 @@ void __fastcall OpenSessionInPutty(const UnicodeString PuttyPath,
 
     if (!Password.IsEmpty() && !RemoteCustomCommand.IsPasswordCommand(AParams))
     {
+      Password = NormalizeString(Password); // if password is empty, we should quote it always
       AddToList(PuttyParams, FORMAT(L"-pw %s", (EscapePuttyCommandParam(Password))), L" ");
     }