1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00

Warning when pasting a session URL with unsafe settings

Source commit: a6a8ab80fab4384666d8f4835e7f5fefb91c4aa9
This commit is contained in:
Martin Prikryl
2026-06-10 13:45:39 +00:00
parent 93cd106447
commit 1636165e08
8 changed files with 74 additions and 25 deletions

View File

@@ -134,6 +134,7 @@ __fastcall TSessionData::TSessionData(UnicodeString aName):
{
Default();
FModified = true;
FUnsafeSettings = nullptr;
}
//---------------------------------------------------------------------
_fastcall TSessionData::~TSessionData()
@@ -687,11 +688,15 @@ bool __fastcall TSessionData::IsInFolderOrWorkspace(const UnicodeString & AFolde
return StartsText(UnixIncludeTrailingBackslash(AFolder), Name);
}
//---------------------------------------------------------------------
void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword, bool Unsafe, bool RespectDisablePasswordStoring)
void TSessionData::DoLoad(
THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword,
bool Unsafe, bool RespectDisablePasswordStoring, bool & UnsafeSettings)
{
// Make sure we only ever use methods supported by TOptionsStorage
// (implemented by TOptionsIniFile)
UnsafeSettings = false;
PortNumber = Storage->ReadInteger(L"PortNumber", PortNumber);
UserName = Storage->ReadString(L"UserName", UserName);
// must be loaded after UserName, because HostName may be in format user@host
@@ -709,6 +714,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
SET_SESSION_PROPERTY_FROM(PROP, A##PROP); \
}
#define LOAD_PASSWORD(PROP, PLAIN_NAME) LOAD_PASSWORD_EX(PROP, PLAIN_NAME, TEXT(#PROP), RewritePassword = true;)
#define LOADING_UNSAFE TValueRestorer<bool *> UnsafeSettingsRestorer(FUnsafeSettings, &UnsafeSettings);
bool LoadPasswords = !Configuration->DisablePasswordStoring || !RespectDisablePasswordStoring;
if (LoadPasswords)
{
@@ -754,6 +760,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
HostKeyList = Storage->ReadString(L"HostKey", HostKeyList);
if (!Unsafe)
{
LOADING_UNSAFE;
GssLibList = Storage->ReadString(L"GSSLibs", GssLibList);
}
GssLibCustom = Storage->ReadString(L"GSSCustom", GssLibCustom);
@@ -780,12 +787,14 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
Special = Storage->ReadBool(L"Special", Special);
if (!Unsafe)
{
LOADING_UNSAFE;
Shell = Storage->ReadString(L"Shell", Shell);
}
ClearAliases = Storage->ReadBool(L"ClearAliases", ClearAliases);
UnsetNationalVars = Storage->ReadBool(L"UnsetNationalVars", UnsetNationalVars);
if (!Unsafe)
{
LOADING_UNSAFE;
ListingCommand = Storage->ReadString(L"ListingCommand",
Storage->ReadBool(L"AliasGroupList", false) ? UnicodeString(L"ls -gla") : ListingCommand);
}
@@ -796,6 +805,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
TimeDifferenceAuto = Storage->ReadBool(L"TimeDifferenceAuto", (TimeDifference == TDateTime()));
if (!Unsafe)
{
LOADING_UNSAFE;
DeleteToRecycleBin = Storage->ReadBool(L"DeleteToRecycleBin", DeleteToRecycleBin);
OverwrittenToRecycleBin = Storage->ReadBool(L"OverwrittenToRecycleBin", OverwrittenToRecycleBin);
RecycleBinPath = Storage->ReadString(L"RecycleBinPath", RecycleBinPath);
@@ -839,6 +849,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
LOAD_PASSWORD_EX(ProxyPassword, L"ProxyPassword", L"ProxyPasswordEnc", );
if (!Unsafe)
{
LOADING_UNSAFE;
if (ProxyMethod == pmCmd)
{
ProxyLocalCommand = Storage->ReadStringRaw(L"ProxyTelnetCommand", ProxyLocalCommand);
@@ -874,6 +885,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
if (!Unsafe)
{
LOADING_UNSAFE;
SftpServer = Storage->ReadString(L"SftpServer", SftpServer);
}
#define READ_SFTP_BUG(BUG) \
@@ -962,6 +974,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
CustomParam1 = Storage->ReadString(L"CustomParam1", CustomParam1);
CustomParam2 = Storage->ReadString(L"CustomParam2", CustomParam2);
#undef LOADING_UNSAFE
#undef LOAD_PASSWORD
}
//---------------------------------------------------------------------
@@ -978,7 +991,8 @@ void __fastcall TSessionData::Load(THierarchicalStorage * Storage, bool PuttyImp
ClearSessionPasswords();
FProxyPassword = L"";
DoLoad(Storage, PuttyImport, RewritePassword, false, true);
bool UnsafeSettings; // unused
DoLoad(Storage, PuttyImport, RewritePassword, false, true, UnsafeSettings);
Storage->CloseSubKey();
}
@@ -1958,6 +1972,10 @@ void __fastcall TSessionData::Modify()
{
FSource = ssStoredModified;
}
if (FUnsafeSettings != nullptr)
{
*FUnsafeSettings = true;
}
}
//---------------------------------------------------------------------
UnicodeString __fastcall TSessionData::GetSourceName()
@@ -2434,7 +2452,7 @@ bool TSessionData::ParseUrl(
if (RawSettings->Count > 0) // optimization
{
ApplyRawSettings(RawSettings.get(), Unsafe);
ApplyRawSettings(RawSettings.get(), Unsafe, ParsedInfo);
}
bool HasPassword = (UserInfo.Pos(L':') > 0);
@@ -2591,7 +2609,7 @@ bool TSessionData::ParseUrl(
std::unique_ptr<TStrings> RawSettings(new TStringList());
if (Options->FindSwitch(RawSettingsOption, RawSettings.get()))
{
ApplyRawSettings(RawSettings.get(), Unsafe);
ApplyRawSettings(RawSettings.get(), Unsafe, ParsedInfo);
}
}
if (Options->FindSwitch(PASSWORDSFROMFILES_SWITCH) &&
@@ -2607,16 +2625,28 @@ bool TSessionData::ParseUrl(
return true;
}
//---------------------------------------------------------------------
void __fastcall TSessionData::ApplyRawSettings(TStrings * RawSettings, bool Unsafe)
void TSessionData::ApplyRawSettings(TStrings * RawSettings, bool Unsafe)
{
std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(RawSettings, false));
ApplyRawSettings(OptionsStorage.get(), Unsafe, false);
int ParsedInfo;
ApplyRawSettings(RawSettings, Unsafe, ParsedInfo);
}
//---------------------------------------------------------------------
void __fastcall TSessionData::ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe, bool RespectDisablePasswordStoring)
void TSessionData::ApplyRawSettings(TStrings * RawSettings, bool Unsafe, int & ParsedInfo)
{
std::unique_ptr<TOptionsStorage> OptionsStorage(new TOptionsStorage(RawSettings, false));
bool UnsafeSettings;
ApplyRawSettings(OptionsStorage.get(), Unsafe, false, UnsafeSettings);
if (UnsafeSettings)
{
ParsedInfo |= piUnsafeSettings;
}
}
//---------------------------------------------------------------------
void TSessionData::ApplyRawSettings(
THierarchicalStorage * Storage, bool Unsafe, bool RespectDisablePasswordStoring, bool & UnsafeSettings)
{
bool Dummy;
DoLoad(Storage, false, Dummy, Unsafe, RespectDisablePasswordStoring);
DoLoad(Storage, false, Dummy, Unsafe, RespectDisablePasswordStoring, UnsafeSettings);
}
//---------------------------------------------------------------------
void __fastcall TSessionData::ConfigureTunnel(int APortNumber)
@@ -5787,12 +5817,11 @@ TSessionData * TStoredSessionList::ParseUrl(
return Data.release();
}
//---------------------------------------------------------------------
bool __fastcall TStoredSessionList::IsUrl(UnicodeString Url)
int TStoredSessionList::GetUrlInfo(const UnicodeString & Url)
{
int ParsedInfo;
std::unique_ptr<TSessionData> ParsedData(ParseUrl(Url, NULL, ParsedInfo));
bool Result = FLAGSET(ParsedInfo, piProtocolDefined);
return Result;
return ParsedInfo;
}
//---------------------------------------------------------------------
TSessionData * __fastcall TStoredSessionList::ResolveWorkspaceData(TSessionData * Data)

View File

@@ -64,6 +64,7 @@ enum TParsedInfoFlags
{
piDefaultsOnly = 0x01,
piProtocolDefined = 0x02,
piUnsafeSettings = 0x04,
};
//---------------------------------------------------------------------------
extern const UnicodeString CipherNames[CIPHER_COUNT];
@@ -265,6 +266,7 @@ private:
TSessionSource FSource;
bool FSaveOnly;
UnicodeString FLogicalHostName;
bool * FUnsafeSettings;
void __fastcall SetHostName(UnicodeString value);
UnicodeString __fastcall GetHostNameExpanded();
@@ -462,7 +464,9 @@ private:
UnicodeString __fastcall GetFolderName();
void __fastcall Modify();
UnicodeString __fastcall GetSourceName();
void __fastcall DoLoad(THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword, bool Unsafe, bool RespectDisablePasswordStoring);
void DoLoad(
THierarchicalStorage * Storage, bool PuttyImport, bool & RewritePassword,
bool Unsafe, bool RespectDisablePasswordStoring, bool & UnsafeSettings);
void __fastcall DoSave(THierarchicalStorage * Storage,
bool PuttyExport, const TSessionData * Default, bool DoNotEncryptPasswords);
UnicodeString __fastcall ReadXmlNode(_di_IXMLNode Node, const UnicodeString & Name, const UnicodeString & Default);
@@ -506,6 +510,7 @@ private:
void __fastcall SetAlgoList(AlgoT * List, const AlgoT * DefaultList, const UnicodeString * Names,
int Count, AlgoT WarnAlgo, UnicodeString value);
void DefaultProxy();
void ApplyRawSettings(TStrings * RawSettings, bool Unsafe, int & ParsedInfo);
static void __fastcall Remove(THierarchicalStorage * Storage, const UnicodeString & Name);
__property UnicodeString InternalStorageKey = { read = GetInternalStorageKey };
@@ -518,8 +523,8 @@ public:
void __fastcall DefaultSettings();
void __fastcall NonPersistent();
void __fastcall Load(THierarchicalStorage * Storage, bool PuttyImport);
void __fastcall ApplyRawSettings(TStrings * RawSettings, bool Unsafe);
void __fastcall ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe, bool RespectDisablePasswordStoring);
void ApplyRawSettings(TStrings * RawSettings, bool Unsafe);
void ApplyRawSettings(THierarchicalStorage * Storage, bool Unsafe, bool RespectDisablePasswordStoring, bool & UnsafeSettings);
void __fastcall ImportFromFilezilla(_di_IXMLNode Node, const UnicodeString & Path, _di_IXMLNode SettingsNode);
void ImportFromOpenssh(TStrings * Lines);
void __fastcall Save(THierarchicalStorage * Storage, bool PuttyExport,
@@ -789,7 +794,7 @@ public:
TSessionData * ParseUrl(
const UnicodeString & Url, TOptions * Options, int & ParsedInfo,
UnicodeString * FileName = NULL, UnicodeString * MaskedUrl = NULL, int Flags = 0);
bool __fastcall IsUrl(UnicodeString Url);
int GetUrlInfo(const UnicodeString & Url);
bool __fastcall CanOpen(TSessionData * Data);
void __fastcall GetFolderOrWorkspace(const UnicodeString & Name, TList * List);
TStrings * __fastcall GetFolderOrWorkspaceList(const UnicodeString & Name);

View File

@@ -9273,7 +9273,7 @@ bool __fastcall TCustomScpExplorerForm::CanPasteFromClipBoard()
if (NonEmptyTextFromClipboard(ClipboardText) &&
(ClipboardText.Pos(L"\n") == 0)) // it's already trimmed
{
if (StoredSessions->IsUrl(ClipboardText))
if (FLAGSET(StoredSessions->GetUrlInfo(ClipboardText), piProtocolDefined))
{
Result = true;
}
@@ -9311,8 +9311,14 @@ void __fastcall TCustomScpExplorerForm::PasteFromClipBoard()
UnicodeString ClipboardText;
if (NonEmptyTextFromClipboard(ClipboardText))
{
if (StoredSessions->IsUrl(ClipboardText))
int ParsedInfo = StoredSessions->GetUrlInfo(ClipboardText);
if (FLAGSET(ParsedInfo, piProtocolDefined))
{
if (FLAGSET(ParsedInfo, piUnsafeSettings) &&
(MessageDialog(LoadStr(UNSAFE_SESSION), qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaOK))
{
Abort();
}
NewSession(ClipboardText);
}
else

View File

@@ -1285,7 +1285,7 @@ void __fastcall TLoginDialog::ActionListUpdate(TBasicAction * BasicAction,
UnicodeString ClipboardUrl;
Action->Enabled =
NonEmptyTextFromClipboard(ClipboardUrl) &&
StoredSessions->IsUrl(ClipboardUrl);
FLAGSET(StoredSessions->GetUrlInfo(ClipboardUrl), piProtocolDefined);
}
else if (Action == GenerateUrlAction2)
{
@@ -3179,11 +3179,10 @@ void __fastcall TLoginDialog::LoginButtonDropDownClick(TObject * /*Sender*/)
MenuPopup(LoginDropDownMenu, LoginButton);
}
//---------------------------------------------------------------------------
void TLoginDialog::DoParseUrl(TSessionData * SessionData, const UnicodeString & Url)
void TLoginDialog::DoParseUrl(TSessionData * SessionData, const UnicodeString & Url, int & ParsedInfo)
{
// We do not want to pass in StoredSessions as we do not want the URL be
// parsed as pointing to a stored site.
int ParsedInfo; // unused
SessionData->ParseUrl(Url, NULL, NULL, ParsedInfo, NULL, NULL, pufPreferProtocol);
SessionData->RequireDirectories = false;
}
@@ -3206,7 +3205,13 @@ void __fastcall TLoginDialog::ParseUrl(const UnicodeString & Url)
}
else
{
DoParseUrl(SessionData.get(), Url);
int ParsedInfo;
DoParseUrl(SessionData.get(), Url, ParsedInfo);
if (FLAGSET(ParsedInfo, piUnsafeSettings) &&
(MessageDialog(LoadStr(UNSAFE_SESSION), qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaOK))
{
Abort();
}
}
LoadSession(SessionData.get());
@@ -3242,7 +3247,8 @@ void __fastcall TLoginDialog::ParseHostName()
{
// All this check is probably unnecessary, keeping it just to be safe
std::unique_ptr<TSessionData> SessionData(new TSessionData(EmptyStr));
DoParseUrl(SessionData.get(), HostName);
int ParsedInfo; // unused
DoParseUrl(SessionData.get(), HostName, ParsedInfo);
std::unique_ptr<TSessionData> HostNameSessionData(new TSessionData(EmptyStr));
HostNameSessionData->HostName = HostName;
if ((HostNameSessionData->HostName != HostName) || // Has legacy HostName property parsing intervened?

View File

@@ -414,7 +414,7 @@ private:
bool __fastcall IsEditable();
TSessionData * __fastcall CloneSelectedSession();
void __fastcall CloneToNewSite();
void DoParseUrl(TSessionData * SessionData, const UnicodeString & Url);
void DoParseUrl(TSessionData * SessionData, const UnicodeString & Url, int & ParsedInfo);
void __fastcall ParseUrl(const UnicodeString & Url);
void __fastcall ParseHostName();
void __fastcall ResetNewSiteData();

View File

@@ -94,6 +94,7 @@
#define COPYID_IDETITY_MISSING 1213
#define TAG_NOT_UNIQUE 1214
#define TAG_INVALID_CHAR 1215
#define UNSAFE_SESSION 1216
#define WIN_CONFIRMATION_STRINGS 1300
#define CONFIRM_OVERWRITE_SESSION 1301

View File

@@ -102,6 +102,7 @@ BEGIN
COPYID_IDETITY_MISSING, "Identity/key file was not specified."
TAG_NOT_UNIQUE, "Keys must be unique."
TAG_INVALID_CHAR, "Character \"%s\" is not allowed in tags."
UNSAFE_SESSION, "**Use potentially unsafe session settings?**\nThe provided session URL contains potentially unsafe settings. Proceed only if you trust its source."
WIN_CONFIRMATION_STRINGS, "WIN_CONFIRMATION"
CONFIRM_OVERWRITE_SESSION, "Site with name '%s' already exists. Overwrite?"

View File

@@ -2498,7 +2498,8 @@ int __fastcall BatchSettings(TConsole * Console, TProgramParams * Params)
Matches++;
std::unique_ptr<TSessionData> OriginalData(new TSessionData(L""));
OriginalData->CopyDataNoRecrypt(Data);
Data->ApplyRawSettings(OptionsStorage.get(), false, true);
bool UnsafeSettings; // unused
Data->ApplyRawSettings(OptionsStorage.get(), false, true, UnsafeSettings);
bool Changed = !OriginalData->IsSame(Data, false);
if (Changed)
{