mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Removing support for SSH-1
Source commit: 75607516cc12c02235795c32cd3f9e67d920bade
This commit is contained in:
@@ -170,21 +170,6 @@
|
||||
<BuildOrder>23</BuildOrder>
|
||||
<BuildOrder>19</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1bpp.c">
|
||||
<BuildOrder>53</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1censor.c">
|
||||
<BuildOrder>57</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1connection.c">
|
||||
<BuildOrder>64</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1connection-client.c">
|
||||
<BuildOrder>71</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh1login.c">
|
||||
<BuildOrder>65</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\ssh2bpp.c">
|
||||
<BuildOrder>54</BuildOrder>
|
||||
</CppCompile>
|
||||
@@ -245,14 +230,6 @@
|
||||
<CppCompile Include="putty\sshcommon.c">
|
||||
<BuildOrder>62</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\sshcrc.c">
|
||||
<BuildOrder>38</BuildOrder>
|
||||
<BuildOrder>36</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\sshcrcda.c">
|
||||
<BuildOrder>41</BuildOrder>
|
||||
<BuildOrder>35</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="putty\sshdes.c">
|
||||
<BuildOrder>44</BuildOrder>
|
||||
<BuildOrder>32</BuildOrder>
|
||||
|
||||
@@ -956,11 +956,6 @@ UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const s
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall GetSsh1KeyType()
|
||||
{
|
||||
return UnicodeString(ssh_rsa.cache_id);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall GetKeyTypeHuman(const UnicodeString & KeyType)
|
||||
{
|
||||
UnicodeString Result;
|
||||
|
||||
@@ -37,7 +37,6 @@ void __fastcall DllHijackingProtection();
|
||||
UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const struct ssh_keyalg *& Algorithm);
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall GetKeyTypeHuman(const UnicodeString & KeyType);
|
||||
UnicodeString __fastcall GetSsh1KeyType();
|
||||
//---------------------------------------------------------------------------
|
||||
bool IsOpenSSH(const UnicodeString & SshImplementation);
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -123,27 +123,16 @@ inline void __fastcall TSecureShell::UpdateSessionInfo()
|
||||
{
|
||||
if (!FSessionInfoValid)
|
||||
{
|
||||
FSshVersion = get_ssh_version(FBackendHandle);
|
||||
DebugAssert(get_ssh_version(FBackendHandle) == 2);
|
||||
FSessionInfo.ProtocolBaseName = L"SSH";
|
||||
FSessionInfo.ProtocolName =
|
||||
FORMAT(L"%s-%d", (FSessionInfo.ProtocolBaseName, get_ssh_version(FBackendHandle)));
|
||||
FSessionInfo.SecurityProtocolName = FSessionInfo.ProtocolName;
|
||||
|
||||
if (FSshVersion == 1)
|
||||
{
|
||||
FSessionInfo.CSCipher = GetCipherName(get_cipher(FBackendHandle));
|
||||
FSessionInfo.SCCipher = FSessionInfo.CSCipher;
|
||||
// Retrieval of compression is not implemented for SSH-1
|
||||
FSessionInfo.CSCompression = UnicodeString();
|
||||
FSessionInfo.SCCompression = UnicodeString();
|
||||
}
|
||||
else
|
||||
{
|
||||
FSessionInfo.CSCipher = GetCipherName(get_cscipher(FBackendHandle));
|
||||
FSessionInfo.SCCipher = GetCipherName(get_sccipher(FBackendHandle));
|
||||
FSessionInfo.CSCompression = GetCompressorName(get_cscomp(FBackendHandle));
|
||||
FSessionInfo.SCCompression = GetDecompressorName(get_sccomp(FBackendHandle));
|
||||
}
|
||||
FSessionInfo.CSCipher = GetCipherName(get_cscipher(FBackendHandle));
|
||||
FSessionInfo.SCCipher = GetCipherName(get_sccipher(FBackendHandle));
|
||||
FSessionInfo.CSCompression = GetCompressorName(get_cscomp(FBackendHandle));
|
||||
FSessionInfo.SCCompression = GetDecompressorName(get_sccomp(FBackendHandle));
|
||||
|
||||
FSessionInfoValid = true;
|
||||
}
|
||||
@@ -259,10 +248,8 @@ Conf * __fastcall TSecureShell::StoreToConfig(TSessionData * Data, bool Simple)
|
||||
conf_set_filename(conf, CONF_keyfile, KeyFileFileName);
|
||||
filename_free(KeyFileFileName);
|
||||
|
||||
conf_set_int(conf, CONF_sshprot, Data->SshProt);
|
||||
conf_set_bool(conf, CONF_ssh2_des_cbc, Data->Ssh2DES);
|
||||
conf_set_bool(conf, CONF_ssh_no_userauth, Data->SshNoUserAuth);
|
||||
conf_set_bool(conf, CONF_try_tis_auth, Data->AuthTIS);
|
||||
conf_set_bool(conf, CONF_try_ki_auth, Data->AuthKI);
|
||||
conf_set_bool(conf, CONF_try_gssapi_auth, Data->AuthGSSAPI);
|
||||
conf_set_bool(conf, CONF_try_gssapi_kex, Data->AuthGSSAPIKEX);
|
||||
@@ -285,9 +272,6 @@ Conf * __fastcall TSecureShell::StoreToConfig(TSessionData * Data, bool Simple)
|
||||
conf_set_int(conf, CONF_proxy_dns, Data->ProxyDNS);
|
||||
conf_set_bool(conf, CONF_even_proxy_localhost, Data->ProxyLocalhost);
|
||||
|
||||
conf_set_int(conf, CONF_sshbug_ignore1, Data->Bug[sbIgnore1]);
|
||||
conf_set_int(conf, CONF_sshbug_plainpw1, Data->Bug[sbPlainPW1]);
|
||||
conf_set_int(conf, CONF_sshbug_rsa1, Data->Bug[sbRSA1]);
|
||||
conf_set_int(conf, CONF_sshbug_hmac2, Data->Bug[sbHMAC2]);
|
||||
conf_set_int(conf, CONF_sshbug_derivekey2, Data->Bug[sbDeriveKey2]);
|
||||
conf_set_int(conf, CONF_sshbug_rsapad2, Data->Bug[sbRSAPad2]);
|
||||
@@ -2176,14 +2160,7 @@ unsigned long __fastcall TSecureShell::MaxPacketSize()
|
||||
UpdateSessionInfo();
|
||||
}
|
||||
|
||||
if (FSshVersion == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return winscp_query(FBackendHandle, WINSCP_QUERY_REMMAXPKT);
|
||||
}
|
||||
return winscp_query(FBackendHandle, WINSCP_QUERY_REMMAXPKT);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall TSecureShell::FormatKeyStr(UnicodeString KeyStr)
|
||||
@@ -2416,16 +2393,8 @@ UnicodeString TSecureShell::StoreHostKey(
|
||||
void TSecureShell::ParseFingerprint(const UnicodeString & Fingerprint, UnicodeString & SignKeyType, UnicodeString & Hash)
|
||||
{
|
||||
UnicodeString Buf = Fingerprint;
|
||||
UnicodeString SignKeyAlg, SignKeySize;
|
||||
if (get_ssh_version(FBackendHandle) == 1)
|
||||
{
|
||||
SignKeyAlg = GetSsh1KeyType();
|
||||
}
|
||||
else
|
||||
{
|
||||
SignKeyAlg = CutToChar(Buf, L' ', false);
|
||||
}
|
||||
SignKeySize = CutToChar(Buf, L' ', false);
|
||||
UnicodeString SignKeyAlg = CutToChar(Buf, L' ', false);
|
||||
UnicodeString SignKeySize = CutToChar(Buf, L' ', false);
|
||||
SignKeyType = SignKeyAlg + L' ' + SignKeySize;
|
||||
Hash = Buf;
|
||||
}
|
||||
@@ -2448,21 +2417,16 @@ void __fastcall TSecureShell::VerifyHostKey(
|
||||
|
||||
UnicodeString SignKeyType, MD5, SHA256;
|
||||
ParseFingerprint(AFingerprintMD5, SignKeyType, MD5);
|
||||
if (get_ssh_version(FBackendHandle) == 1)
|
||||
|
||||
DebugAssert(get_ssh_version(FBackendHandle) == 2);
|
||||
UnicodeString SignKeyTypeSHA256;
|
||||
ParseFingerprint(AFingerprintSHA256, SignKeyTypeSHA256, SHA256);
|
||||
DebugAssert(SignKeyTypeSHA256 == SignKeyType);
|
||||
if (DebugAlwaysTrue(StartsText(L"SHA256:", SHA256)))
|
||||
{
|
||||
DebugAssert(AFingerprintSHA256.IsEmpty());
|
||||
SHA256 = L"-";
|
||||
}
|
||||
else
|
||||
{
|
||||
UnicodeString SignKeyTypeSHA256;
|
||||
ParseFingerprint(AFingerprintSHA256, SignKeyTypeSHA256, SHA256);
|
||||
DebugAssert(SignKeyTypeSHA256 == SignKeyType);
|
||||
if (DebugAlwaysTrue(StartsText(L"SHA256:", SHA256)))
|
||||
{
|
||||
CutToChar(SHA256, L':', false);
|
||||
}
|
||||
CutToChar(SHA256, L':', false);
|
||||
}
|
||||
|
||||
UnicodeString FingerprintMD5 = SignKeyType + L' ' + MD5;
|
||||
DebugAssert(AFingerprintMD5 == FingerprintMD5);
|
||||
UnicodeString FingerprintSHA256 = SignKeyType + L' ' + SHA256;
|
||||
@@ -2755,14 +2719,7 @@ void __fastcall TSecureShell::CollectUsage()
|
||||
Configuration->Usage->Inc(L"OpenedSessionsPrivateKey2");
|
||||
}
|
||||
|
||||
if (FSshVersion == 1)
|
||||
{
|
||||
Configuration->Usage->Inc(L"OpenedSessionsSSH1");
|
||||
}
|
||||
else if (FSshVersion == 2)
|
||||
{
|
||||
Configuration->Usage->Inc(L"OpenedSessionsSSH2");
|
||||
}
|
||||
Configuration->Usage->Inc(L"OpenedSessionsSSH2");
|
||||
|
||||
if (SshImplementation == sshiOpenSSH)
|
||||
{
|
||||
|
||||
@@ -45,7 +45,6 @@ private:
|
||||
bool FStoredPasswordTried;
|
||||
bool FStoredPasswordTriedForKI;
|
||||
bool FStoredPassphraseTried;
|
||||
int FSshVersion;
|
||||
bool FOpened;
|
||||
bool FClosed;
|
||||
int FWaiting;
|
||||
|
||||
@@ -34,7 +34,6 @@ const UnicodeString CipherNames[CIPHER_COUNT] = {L"WARN", L"3des", L"blowfish",
|
||||
const UnicodeString KexNames[KEX_COUNT] = {L"WARN", L"dh-group1-sha1", L"dh-group14-sha1", L"dh-gex-sha1", L"rsa", L"ecdh"};
|
||||
const UnicodeString HostKeyNames[HOSTKEY_COUNT] = {L"WARN", L"rsa", L"dsa", L"ecdsa", L"ed25519", L"ed448"};
|
||||
const UnicodeString GssLibNames[GSSLIB_COUNT] = {L"gssapi32", L"sspi", L"custom"};
|
||||
const wchar_t SshProtList[][10] = {L"1", L"1>2", L"2>1", L"2"};
|
||||
// Update also order in Ssh2CipherList()
|
||||
const TCipher DefaultCipherList[CIPHER_COUNT] =
|
||||
{ cipAES, cipChaCha20, cipBlowfish, cip3DES, cipWarn, cipArcfour, cipDES };
|
||||
@@ -129,7 +128,6 @@ void __fastcall TSessionData::DefaultSettings()
|
||||
Timeout = 15;
|
||||
TryAgent = true;
|
||||
AgentFwd = false;
|
||||
AuthTIS = false;
|
||||
AuthKI = true;
|
||||
AuthKIPassword = true;
|
||||
AuthGSSAPI = true;
|
||||
@@ -138,7 +136,6 @@ void __fastcall TSessionData::DefaultSettings()
|
||||
LogicalHostName = L"";
|
||||
ChangeUsername = false;
|
||||
Compression = false;
|
||||
SshProt = ssh2only;
|
||||
Ssh2DES = false;
|
||||
SshNoUserAuth = false;
|
||||
for (int Index = 0; Index < CIPHER_COUNT; Index++)
|
||||
@@ -338,11 +335,9 @@ void __fastcall TSessionData::NonPersistant()
|
||||
PROPERTY(Timeout); \
|
||||
PROPERTY(TryAgent); \
|
||||
PROPERTY(AgentFwd); \
|
||||
PROPERTY(AuthTIS); \
|
||||
PROPERTY(LogicalHostName); \
|
||||
PROPERTY(ChangeUsername); \
|
||||
PROPERTY(Compression); \
|
||||
PROPERTY(SshProt); \
|
||||
PROPERTY(Ssh2DES); \
|
||||
PROPERTY(SshNoUserAuth); \
|
||||
PROPERTY(CipherList); \
|
||||
@@ -661,7 +656,6 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
|
||||
Timeout = Storage->ReadInteger(L"Timeout", Timeout);
|
||||
TryAgent = Storage->ReadBool(L"TryAgent", TryAgent);
|
||||
AgentFwd = Storage->ReadBool(L"AgentFwd", AgentFwd);
|
||||
AuthTIS = Storage->ReadBool(L"AuthTIS", AuthTIS);
|
||||
AuthKI = Storage->ReadBool(L"AuthKI", AuthKI);
|
||||
AuthKIPassword = Storage->ReadBool(L"AuthKIPassword", AuthKIPassword);
|
||||
// Continue to use setting keys of previous kerberos implementation (vaclav tomec),
|
||||
@@ -676,17 +670,6 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
|
||||
LogicalHostName = Storage->ReadString(L"LogicalHostName", Storage->ReadString(L"GSSAPIServerRealm", Storage->ReadString(L"KerbPrincipal", LogicalHostName)));
|
||||
ChangeUsername = Storage->ReadBool(L"ChangeUsername", ChangeUsername);
|
||||
Compression = Storage->ReadBool(L"Compression", Compression);
|
||||
TSshProt ASshProt = (TSshProt)Storage->ReadInteger(L"SshProt", SshProt);
|
||||
// Old sessions may contain the values correponding to the fallbacks we used to allow; migrate them
|
||||
if (ASshProt == ssh2deprecated)
|
||||
{
|
||||
ASshProt = ssh2only;
|
||||
}
|
||||
else if (ASshProt == ssh1deprecated)
|
||||
{
|
||||
ASshProt = ssh1only;
|
||||
}
|
||||
SshProt = ASshProt;
|
||||
Ssh2DES = Storage->ReadBool(L"Ssh2DES", Ssh2DES);
|
||||
SshNoUserAuth = Storage->ReadBool(L"SshNoUserAuth", SshNoUserAuth);
|
||||
CipherList = Storage->ReadString(L"Cipher", CipherList);
|
||||
@@ -799,9 +782,6 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
|
||||
#define READ_BUG(BUG) \
|
||||
Bug[sb##BUG] = TAutoSwitch(2 - Storage->ReadInteger(L"Bug"#BUG, \
|
||||
2 - Bug[sb##BUG]));
|
||||
READ_BUG(Ignore1);
|
||||
READ_BUG(PlainPW1);
|
||||
READ_BUG(RSA1);
|
||||
READ_BUG(HMAC2);
|
||||
READ_BUG(DeriveKey2);
|
||||
READ_BUG(RSAPad2);
|
||||
@@ -1040,7 +1020,6 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
|
||||
WRITE_DATA(Integer, Timeout);
|
||||
WRITE_DATA(Bool, TryAgent);
|
||||
WRITE_DATA(Bool, AgentFwd);
|
||||
WRITE_DATA(Bool, AuthTIS);
|
||||
WRITE_DATA(Bool, AuthKI);
|
||||
WRITE_DATA(Bool, AuthKIPassword);
|
||||
WRITE_DATA(String, Note);
|
||||
@@ -1065,7 +1044,6 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
|
||||
|
||||
WRITE_DATA(Bool, ChangeUsername);
|
||||
WRITE_DATA(Bool, Compression);
|
||||
WRITE_DATA(Integer, SshProt);
|
||||
WRITE_DATA(Bool, Ssh2DES);
|
||||
WRITE_DATA(Bool, SshNoUserAuth);
|
||||
WRITE_DATA_EX(String, L"Cipher", CipherList, );
|
||||
@@ -1173,9 +1151,6 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
|
||||
|
||||
#define WRITE_DATA_CONV_FUNC(X) (2 - (X))
|
||||
#define WRITE_BUG(BUG) WRITE_DATA_CONV(Integer, L"Bug" #BUG, Bug[sb##BUG]);
|
||||
WRITE_BUG(Ignore1);
|
||||
WRITE_BUG(PlainPW1);
|
||||
WRITE_BUG(RSA1);
|
||||
WRITE_BUG(HMAC2);
|
||||
WRITE_BUG(DeriveKey2);
|
||||
WRITE_BUG(RSAPad2);
|
||||
@@ -2653,11 +2628,6 @@ void __fastcall TSessionData::SetAgentFwd(bool value)
|
||||
SET_SESSION_PROPERTY(AgentFwd);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void __fastcall TSessionData::SetAuthTIS(bool value)
|
||||
{
|
||||
SET_SESSION_PROPERTY(AuthTIS);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void __fastcall TSessionData::SetAuthKI(bool value)
|
||||
{
|
||||
SET_SESSION_PROPERTY(AuthKI);
|
||||
@@ -2693,11 +2663,6 @@ void __fastcall TSessionData::SetCompression(bool value)
|
||||
SET_SESSION_PROPERTY(Compression);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void __fastcall TSessionData::SetSshProt(TSshProt value)
|
||||
{
|
||||
SET_SESSION_PROPERTY(SshProt);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void __fastcall TSessionData::SetSsh2DES(bool value)
|
||||
{
|
||||
SET_SESSION_PROPERTY(Ssh2DES);
|
||||
@@ -2708,11 +2673,6 @@ void __fastcall TSessionData::SetSshNoUserAuth(bool value)
|
||||
SET_SESSION_PROPERTY(SshNoUserAuth);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
UnicodeString __fastcall TSessionData::GetSshProtStr()
|
||||
{
|
||||
return SshProtList[FSshProt];
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
bool __fastcall TSessionData::GetUsesSsh()
|
||||
{
|
||||
return IsSshProtocol(FSProtocol);
|
||||
@@ -4346,7 +4306,6 @@ UnicodeString __fastcall TSessionData::ComposePath(
|
||||
void __fastcall TSessionData::DisableAuthentationsExceptPassword()
|
||||
{
|
||||
SshNoUserAuth = false;
|
||||
AuthTIS = false;
|
||||
AuthKI = false;
|
||||
AuthKIPassword = false;
|
||||
AuthGSSAPI = false;
|
||||
|
||||
@@ -17,7 +17,6 @@ enum TFSProtocol { fsSCPonly = 0, fsSFTP = 1, fsSFTPonly = 2, fsFTP = 5, fsWebDA
|
||||
#define FSPROTOCOL_COUNT (fsS3+1)
|
||||
extern const wchar_t * ProxyMethodNames;
|
||||
enum TProxyMethod { pmNone, pmSocks4, pmSocks5, pmHTTP, pmTelnet, pmCmd };
|
||||
enum TSshProt { ssh1only, ssh1deprecated, ssh2deprecated, ssh2only };
|
||||
enum TKex { kexWarn, kexDHGroup1, kexDHGroup14, kexDHGEx, kexRSA, kexECDH };
|
||||
#define KEX_COUNT (kexECDH+1)
|
||||
enum THostKey { hkWarn, hkRSA, hkDSA, hkECDSA, hkED25519, hkED448, hkMax };
|
||||
@@ -25,7 +24,7 @@ enum THostKey { hkWarn, hkRSA, hkDSA, hkECDSA, hkED25519, hkED448, hkMax };
|
||||
enum TGssLib { gssGssApi32, gssSspi, gssCustom };
|
||||
#define GSSLIB_COUNT (gssCustom+1)
|
||||
// names have to match PuTTY registry entries (see settings.c)
|
||||
enum TSshBug { sbIgnore1, sbPlainPW1, sbRSA1, sbHMAC2, sbDeriveKey2, sbRSAPad2,
|
||||
enum TSshBug { sbHMAC2, sbDeriveKey2, sbRSAPad2,
|
||||
sbPKSessID2, sbRekey2, sbMaxPkt2, sbIgnore2, sbOldGex2, sbWinAdj, sbChanReq };
|
||||
#define BUG_COUNT (sbChanReq+1)
|
||||
enum TSftpBug { sbSymlink, sbSignedTS };
|
||||
@@ -114,7 +113,6 @@ private:
|
||||
bool FTryAgent;
|
||||
bool FAgentFwd;
|
||||
UnicodeString FListingCommand;
|
||||
bool FAuthTIS;
|
||||
bool FAuthKI;
|
||||
bool FAuthKIPassword;
|
||||
bool FAuthGSSAPI;
|
||||
@@ -122,7 +120,6 @@ private:
|
||||
bool FGSSAPIFwdTGT;
|
||||
bool FChangeUsername;
|
||||
bool FCompression;
|
||||
TSshProt FSshProt;
|
||||
bool FSsh2DES;
|
||||
bool FSshNoUserAuth;
|
||||
TCipher FCiphers[CIPHER_COUNT];
|
||||
@@ -263,7 +260,6 @@ private:
|
||||
void __fastcall SetPingInterval(int value);
|
||||
void __fastcall SetTryAgent(bool value);
|
||||
void __fastcall SetAgentFwd(bool value);
|
||||
void __fastcall SetAuthTIS(bool value);
|
||||
void __fastcall SetAuthKI(bool value);
|
||||
void __fastcall SetAuthKIPassword(bool value);
|
||||
void __fastcall SetAuthGSSAPI(bool value);
|
||||
@@ -271,7 +267,6 @@ private:
|
||||
void __fastcall SetGSSAPIFwdTGT(bool value);
|
||||
void __fastcall SetChangeUsername(bool value);
|
||||
void __fastcall SetCompression(bool value);
|
||||
void __fastcall SetSshProt(TSshProt value);
|
||||
void __fastcall SetSsh2DES(bool value);
|
||||
void __fastcall SetSshNoUserAuth(bool value);
|
||||
void __fastcall SetCipher(int Index, TCipher value);
|
||||
@@ -337,7 +332,6 @@ private:
|
||||
void __fastcall SetSourceAddress(const UnicodeString & value);
|
||||
void __fastcall SetProtocolFeatures(const UnicodeString & value);
|
||||
void __fastcall SetSshSimple(bool value);
|
||||
UnicodeString __fastcall GetSshProtStr();
|
||||
bool __fastcall GetUsesSsh();
|
||||
void __fastcall SetCipherList(UnicodeString value);
|
||||
UnicodeString __fastcall GetCipherList() const;
|
||||
@@ -557,7 +551,6 @@ public:
|
||||
__property bool TryAgent = { read=FTryAgent, write=SetTryAgent };
|
||||
__property bool AgentFwd = { read=FAgentFwd, write=SetAgentFwd };
|
||||
__property UnicodeString ListingCommand = { read = FListingCommand, write = SetListingCommand };
|
||||
__property bool AuthTIS = { read=FAuthTIS, write=SetAuthTIS };
|
||||
__property bool AuthKI = { read=FAuthKI, write=SetAuthKI };
|
||||
__property bool AuthKIPassword = { read=FAuthKIPassword, write=SetAuthKIPassword };
|
||||
__property bool AuthGSSAPI = { read=FAuthGSSAPI, write=SetAuthGSSAPI };
|
||||
@@ -565,7 +558,6 @@ public:
|
||||
__property bool GSSAPIFwdTGT = { read=FGSSAPIFwdTGT, write=SetGSSAPIFwdTGT };
|
||||
__property bool ChangeUsername = { read=FChangeUsername, write=SetChangeUsername };
|
||||
__property bool Compression = { read=FCompression, write=SetCompression };
|
||||
__property TSshProt SshProt = { read=FSshProt, write=SetSshProt };
|
||||
__property bool UsesSsh = { read = GetUsesSsh };
|
||||
__property bool Ssh2DES = { read=FSsh2DES, write=SetSsh2DES };
|
||||
__property bool SshNoUserAuth = { read=FSshNoUserAuth, write=SetSshNoUserAuth };
|
||||
@@ -623,7 +615,6 @@ public:
|
||||
__property UnicodeString SourceAddress = { read=FSourceAddress, write=SetSourceAddress };
|
||||
__property UnicodeString ProtocolFeatures = { read=FProtocolFeatures, write=SetProtocolFeatures };
|
||||
__property bool SshSimple = { read=FSshSimple, write=SetSshSimple };
|
||||
__property UnicodeString SshProtStr = { read=GetSshProtStr };
|
||||
__property UnicodeString CipherList = { read=GetCipherList, write=SetCipherList };
|
||||
__property UnicodeString KexList = { read=GetKexList, write=SetKexList };
|
||||
__property UnicodeString HostKeyList = { read=GetHostKeyList, write=SetHostKeyList };
|
||||
|
||||
@@ -1272,12 +1272,11 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
|
||||
}
|
||||
if (Data->UsesSsh)
|
||||
{
|
||||
ADF(L"SSH protocol version: %s; Compression: %s",
|
||||
(Data->SshProtStr, BooleanToEngStr(Data->Compression)));
|
||||
ADF(L"Compression: %s", (BooleanToEngStr(Data->Compression)));
|
||||
ADF(L"Bypass authentication: %s",
|
||||
(BooleanToEngStr(Data->SshNoUserAuth)));
|
||||
ADF(L"Try agent: %s; Agent forwarding: %s; TIS/CryptoCard: %s; KI: %s; GSSAPI: %s",
|
||||
(BooleanToEngStr(Data->TryAgent), BooleanToEngStr(Data->AgentFwd), BooleanToEngStr(Data->AuthTIS),
|
||||
ADF(L"Try agent: %s; Agent forwarding: %s; KI: %s; GSSAPI: %s",
|
||||
(BooleanToEngStr(Data->TryAgent), BooleanToEngStr(Data->AgentFwd),
|
||||
BooleanToEngStr(Data->AuthKI), BooleanToEngStr(Data->AuthGSSAPI)));
|
||||
if (Data->AuthGSSAPI)
|
||||
{
|
||||
|
||||
@@ -1534,7 +1534,6 @@ void __fastcall TTerminal::OpenTunnel()
|
||||
|
||||
// inherit most SSH options of the main session (except for private key and bugs)
|
||||
FTunnelData->Compression = FSessionData->Compression;
|
||||
FTunnelData->SshProt = FSessionData->SshProt;
|
||||
FTunnelData->CipherList = FSessionData->CipherList;
|
||||
FTunnelData->Ssh2DES = FSessionData->Ssh2DES;
|
||||
|
||||
@@ -1548,7 +1547,6 @@ void __fastcall TTerminal::OpenTunnel()
|
||||
FTunnelData->GSSAPIFwdTGT = FSessionData->GSSAPIFwdTGT;
|
||||
FTunnelData->TryAgent = FSessionData->TryAgent;
|
||||
FTunnelData->AgentFwd = FSessionData->AgentFwd;
|
||||
FTunnelData->AuthTIS = FSessionData->AuthTIS;
|
||||
FTunnelData->AuthKI = FSessionData->AuthKI;
|
||||
FTunnelData->AuthKIPassword = FSessionData->AuthKIPassword;
|
||||
|
||||
|
||||
@@ -63,9 +63,6 @@ void __fastcall TSiteAdvancedDialog::InitControls()
|
||||
{
|
||||
ComboAutoSwitchInitialize(UtfCombo);
|
||||
|
||||
ComboAutoSwitchInitialize(BugIgnore1Combo);
|
||||
ComboAutoSwitchInitialize(BugPlainPW1Combo);
|
||||
ComboAutoSwitchInitialize(BugRSA1Combo);
|
||||
ComboAutoSwitchInitialize(BugHMAC2Combo);
|
||||
ComboAutoSwitchInitialize(BugDeriveKey2Combo);
|
||||
ComboAutoSwitchInitialize(BugRSAPad2Combo);
|
||||
@@ -243,7 +240,6 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
|
||||
// Authentication page
|
||||
SshNoUserAuthCheck->Checked = FSessionData->SshNoUserAuth;
|
||||
TryAgentCheck->Checked = FSessionData->TryAgent;
|
||||
AuthTISCheck->Checked = FSessionData->AuthTIS;
|
||||
AuthKICheck->Checked = FSessionData->AuthKI;
|
||||
AuthKIPasswordCheck->Checked = FSessionData->AuthKIPassword;
|
||||
AuthGSSAPICheck3->Checked = FSessionData->AuthGSSAPI;
|
||||
@@ -254,14 +250,6 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
|
||||
// SSH page
|
||||
Ssh2LegacyDESCheck->Checked = FSessionData->Ssh2DES;
|
||||
CompressionCheck->Checked = FSessionData->Compression;
|
||||
if (FSessionData->SshProt == ssh1only)
|
||||
{
|
||||
SshProtCombo2->ItemIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
SshProtCombo2->ItemIndex = 1;
|
||||
}
|
||||
|
||||
CipherListBox->Items->Clear();
|
||||
DebugAssert(CIPHER_NAME_WARN+CIPHER_COUNT-1 == CIPHER_NAME_CHACHA20);
|
||||
@@ -388,9 +376,6 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
|
||||
// Bugs page
|
||||
#define LOAD_BUG_COMBO(BUG) \
|
||||
ComboAutoSwitchLoad(Bug ## BUG ## Combo, FSessionData->Bug[sb ## BUG])
|
||||
LOAD_BUG_COMBO(Ignore1);
|
||||
LOAD_BUG_COMBO(PlainPW1);
|
||||
LOAD_BUG_COMBO(RSA1);
|
||||
LOAD_BUG_COMBO(HMAC2);
|
||||
LOAD_BUG_COMBO(DeriveKey2);
|
||||
LOAD_BUG_COMBO(RSAPad2);
|
||||
@@ -444,11 +429,6 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
|
||||
UpdateControls();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
TSshProt __fastcall TSiteAdvancedDialog::GetSshProt()
|
||||
{
|
||||
return (SshProtCombo2->ItemIndex == 0) ? ssh1only : ssh2only;
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
bool TSiteAdvancedDialog::IsDefaultSftpServer()
|
||||
{
|
||||
return
|
||||
@@ -466,8 +446,6 @@ void __fastcall TSiteAdvancedDialog::SaveSession(TSessionData * SessionData)
|
||||
SessionData->Compression = CompressionCheck->Checked;
|
||||
SessionData->Ssh2DES = Ssh2LegacyDESCheck->Checked;
|
||||
|
||||
SessionData->SshProt = GetSshProt();
|
||||
|
||||
for (int Index = 0; Index < CIPHER_COUNT; Index++)
|
||||
{
|
||||
SessionData->Cipher[Index] = (TCipher)CipherListBox->Items->Objects[Index];
|
||||
@@ -488,7 +466,6 @@ void __fastcall TSiteAdvancedDialog::SaveSession(TSessionData * SessionData)
|
||||
// Authentication page
|
||||
SessionData->SshNoUserAuth = SshNoUserAuthCheck->Checked;
|
||||
SessionData->TryAgent = TryAgentCheck->Checked;
|
||||
SessionData->AuthTIS = AuthTISCheck->Checked;
|
||||
SessionData->AuthKI = AuthKICheck->Checked;
|
||||
SessionData->AuthKIPassword = AuthKIPasswordCheck->Checked;
|
||||
SessionData->AuthGSSAPI = AuthGSSAPICheck3->Checked;
|
||||
@@ -674,9 +651,6 @@ void __fastcall TSiteAdvancedDialog::SaveSession(TSessionData * SessionData)
|
||||
|
||||
// Bugs page
|
||||
#define SAVE_BUG_COMBO(BUG) SessionData->Bug[sb ## BUG] = ComboAutoSwitchSave(Bug ## BUG ## Combo)
|
||||
SAVE_BUG_COMBO(Ignore1);
|
||||
SAVE_BUG_COMBO(PlainPW1);
|
||||
SAVE_BUG_COMBO(RSA1);
|
||||
SAVE_BUG_COMBO(HMAC2);
|
||||
SAVE_BUG_COMBO(DeriveKey2);
|
||||
SAVE_BUG_COMBO(RSAPad2);
|
||||
@@ -872,20 +846,14 @@ void __fastcall TSiteAdvancedDialog::UpdateControls()
|
||||
|
||||
// ssh/authentication sheet
|
||||
AuthSheet->Enabled = SshProtocol;
|
||||
EnableControl(SshNoUserAuthCheck, (GetSshProt() == ssh2only));
|
||||
EnableControl(AuthenticationGroup,
|
||||
!SshNoUserAuthCheck->Enabled || !SshNoUserAuthCheck->Checked);
|
||||
EnableControl(AuthTISCheck, AuthenticationGroup->Enabled && (GetSshProt() == ssh1only));
|
||||
EnableControl(AuthKICheck, AuthenticationGroup->Enabled && (GetSshProt() == ssh2only));
|
||||
EnableControl(AuthKIPasswordCheck,
|
||||
AuthenticationGroup->Enabled &&
|
||||
((AuthTISCheck->Enabled && AuthTISCheck->Checked) ||
|
||||
(AuthKICheck->Enabled && AuthKICheck->Checked)));
|
||||
AuthenticationGroup->Enabled && (AuthKICheck->Enabled && AuthKICheck->Checked));
|
||||
EnableControl(AuthenticationParamsGroup, AuthenticationGroup->Enabled);
|
||||
EnableControl(AgentFwdCheck, AuthenticationParamsGroup->Enabled && TryAgentCheck->Checked);
|
||||
EnableControl(PrivateKeyViewButton, PrivateKeyEdit3->Enabled && !PrivateKeyEdit3->Text.IsEmpty());
|
||||
EnableControl(AuthGSSAPICheck3,
|
||||
AuthenticationGroup->Enabled && (GetSshProt() == ssh2only));
|
||||
EnableControl(AuthGSSAPICheck3, AuthenticationGroup->Enabled);
|
||||
EnableControl(GSSAPIFwdTGTCheck,
|
||||
AuthGSSAPICheck3->Enabled && AuthGSSAPICheck3->Checked);
|
||||
|
||||
@@ -894,39 +862,15 @@ void __fastcall TSiteAdvancedDialog::UpdateControls()
|
||||
EnableControl(CipherUpButton, CipherListBox->ItemIndex > 0);
|
||||
EnableControl(CipherDownButton, CipherListBox->ItemIndex >= 0 &&
|
||||
CipherListBox->ItemIndex < CipherListBox->Items->Count-1);
|
||||
EnableControl(Ssh2LegacyDESCheck, (GetSshProt() == ssh2only));
|
||||
|
||||
// ssh/kex sheet
|
||||
KexSheet->Enabled = SshProtocol && (GetSshProt() == ssh2only) &&
|
||||
(BugRekey2Combo->ItemIndex != 2);
|
||||
KexSheet->Enabled = SshProtocol && (BugRekey2Combo->ItemIndex != 2);
|
||||
EnableControl(KexUpButton, KexListBox->ItemIndex > 0);
|
||||
EnableControl(KexDownButton, KexListBox->ItemIndex >= 0 &&
|
||||
KexListBox->ItemIndex < KexListBox->Items->Count-1);
|
||||
|
||||
// ssh/bugs sheet
|
||||
BugsSheet->Enabled = SshProtocol;
|
||||
EnableControl(BugIgnore1Combo, (GetSshProt() == ssh1only));
|
||||
EnableControl(BugIgnore1Label, BugIgnore1Combo->Enabled);
|
||||
EnableControl(BugPlainPW1Combo, (GetSshProt() == ssh1only));
|
||||
EnableControl(BugPlainPW1Label, BugPlainPW1Combo->Enabled);
|
||||
EnableControl(BugRSA1Combo, (GetSshProt() == ssh1only));
|
||||
EnableControl(BugRSA1Label, BugRSA1Combo->Enabled);
|
||||
EnableControl(BugHMAC2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugHMAC2Label, BugHMAC2Combo->Enabled);
|
||||
EnableControl(BugDeriveKey2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugDeriveKey2Label, BugDeriveKey2Combo->Enabled);
|
||||
EnableControl(BugRSAPad2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugRSAPad2Label, BugRSAPad2Combo->Enabled);
|
||||
EnableControl(BugPKSessID2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugPKSessID2Label, BugPKSessID2Combo->Enabled);
|
||||
EnableControl(BugRekey2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugRekey2Label, BugRekey2Combo->Enabled);
|
||||
EnableControl(BugMaxPkt2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugMaxPkt2Label, BugMaxPkt2Combo->Enabled);
|
||||
EnableControl(BugIgnore2Combo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugIgnore2Label, BugIgnore2Combo->Enabled);
|
||||
EnableControl(BugWinAdjCombo, (GetSshProt() == ssh2only));
|
||||
EnableControl(BugWinAdjLabel, BugWinAdjCombo->Enabled);
|
||||
|
||||
// connection/proxy sheet
|
||||
// this is probaqbly overkill, now we do not allow changing protocol on
|
||||
@@ -1368,7 +1312,7 @@ void __fastcall TSiteAdvancedDialog::PrivateKeyEdit3AfterDialog(TObject * Sender
|
||||
TFilenameEdit * Edit = dynamic_cast<TFilenameEdit *>(Sender);
|
||||
if (Name != Edit->Text)
|
||||
{
|
||||
VerifyAndConvertKey(Name, GetSshProt(), true);
|
||||
VerifyAndConvertKey(Name, true);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -1378,9 +1322,9 @@ void __fastcall TSiteAdvancedDialog::FormCloseQuery(TObject * /*Sender*/,
|
||||
if (ModalResult == DefaultResult(this))
|
||||
{
|
||||
// StripPathQuotes should not be needed as we do not feed quotes anymore
|
||||
VerifyKey(StripPathQuotes(PrivateKeyEdit3->Text), GetSshProt());
|
||||
VerifyKey(StripPathQuotes(PrivateKeyEdit3->Text));
|
||||
// for tunnel SSH version is not configurable
|
||||
VerifyKey(StripPathQuotes(TunnelPrivateKeyEdit3->Text), ssh2only);
|
||||
VerifyKey(StripPathQuotes(TunnelPrivateKeyEdit3->Text));
|
||||
VerifyCertificate(StripPathQuotes(TlsCertificateFileEdit->Text));
|
||||
// Particularly for EncryptKey*Edit's
|
||||
ExitActiveControl(this);
|
||||
@@ -1630,7 +1574,7 @@ void __fastcall TSiteAdvancedDialog::PrivateKeyToolsButtonClick(TObject * /*Send
|
||||
{
|
||||
UnicodeString Dummy;
|
||||
PrivateKeyGenerateItem->Enabled = FindTool(PuttygenTool, Dummy);
|
||||
PrivateKeyUploadItem->Enabled = (GetSshProt() == ssh2only) && (NormalizeFSProtocol(FSessionData->FSProtocol) == fsSFTP);
|
||||
PrivateKeyUploadItem->Enabled = (NormalizeFSProtocol(FSessionData->FSProtocol) == fsSFTP);
|
||||
MenuPopup(PrivateKeyMenu, PrivateKeyToolsButton);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -1660,7 +1604,7 @@ void __fastcall TSiteAdvancedDialog::PrivateKeyUploadItemClick(TObject * /*Sende
|
||||
void __fastcall TSiteAdvancedDialog::PrivateKeyViewButtonClick(TObject * /*Sender*/)
|
||||
{
|
||||
UnicodeString FileName = PrivateKeyEdit3->Text;
|
||||
VerifyAndConvertKey(FileName, GetSshProt(), false);
|
||||
VerifyAndConvertKey(FileName, false);
|
||||
PrivateKeyEdit3->Text = FileName;
|
||||
UnicodeString CommentDummy;
|
||||
UnicodeString Line = GetPublicKeyLine(FileName, CommentDummy);
|
||||
|
||||
@@ -1988,21 +1988,13 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
Left = 0
|
||||
Top = 6
|
||||
Width = 393
|
||||
Height = 71
|
||||
Height = 46
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Protocol options'
|
||||
TabOrder = 0
|
||||
DesignSize = (
|
||||
393
|
||||
71)
|
||||
object Label37: TLabel
|
||||
Left = 12
|
||||
Top = 42
|
||||
Width = 103
|
||||
Height = 13
|
||||
Caption = 'SSH protocol version:'
|
||||
FocusControl = SshProtCombo2
|
||||
end
|
||||
46)
|
||||
object CompressionCheck: TCheckBox
|
||||
Left = 16
|
||||
Top = 19
|
||||
@@ -2013,23 +2005,10 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
TabOrder = 0
|
||||
OnClick = DataChange
|
||||
end
|
||||
object SshProtCombo2: TComboBox
|
||||
Left = 303
|
||||
Top = 37
|
||||
Width = 80
|
||||
Height = 21
|
||||
Style = csDropDownList
|
||||
Anchors = [akTop, akRight]
|
||||
TabOrder = 1
|
||||
OnChange = DataChange
|
||||
Items.Strings = (
|
||||
'1 (insecure)'
|
||||
'2')
|
||||
end
|
||||
end
|
||||
object EncryptionGroup: TGroupBox
|
||||
Left = 0
|
||||
Top = 83
|
||||
Top = 58
|
||||
Width = 393
|
||||
Height = 171
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
@@ -2066,7 +2045,7 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
Width = 367
|
||||
Height = 17
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Enable legacy use of single-&DES in SSH-2'
|
||||
Caption = 'Enable legacy use of single-&DES'
|
||||
TabOrder = 3
|
||||
end
|
||||
object CipherUpButton: TButton
|
||||
@@ -2243,13 +2222,13 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
Left = 0
|
||||
Top = 32
|
||||
Width = 393
|
||||
Height = 117
|
||||
Height = 94
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Authentication options'
|
||||
TabOrder = 1
|
||||
DesignSize = (
|
||||
393
|
||||
117)
|
||||
94)
|
||||
object TryAgentCheck: TCheckBox
|
||||
Left = 12
|
||||
Top = 19
|
||||
@@ -2260,16 +2239,6 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
TabOrder = 0
|
||||
OnClick = DataChange
|
||||
end
|
||||
object AuthTISCheck: TCheckBox
|
||||
Left = 12
|
||||
Top = 88
|
||||
Width = 373
|
||||
Height = 17
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Atte&mpt TIS or CryptoCard authentication (SSH-1)'
|
||||
TabOrder = 3
|
||||
OnClick = DataChange
|
||||
end
|
||||
object AuthKICheck: TCheckBox
|
||||
Left = 12
|
||||
Top = 42
|
||||
@@ -2293,7 +2262,7 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
end
|
||||
object AuthenticationParamsGroup: TGroupBox
|
||||
Left = 0
|
||||
Top = 154
|
||||
Top = 132
|
||||
Width = 393
|
||||
Height = 120
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
@@ -2360,7 +2329,7 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
end
|
||||
object GSSAPIGroup: TGroupBox
|
||||
Left = 0
|
||||
Top = 279
|
||||
Top = 258
|
||||
Width = 393
|
||||
Height = 71
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
@@ -2405,131 +2374,77 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
|
||||
Left = 0
|
||||
Top = 6
|
||||
Width = 393
|
||||
Height = 289
|
||||
Height = 217
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Caption = 'Detection of known bugs in SSH servers'
|
||||
TabOrder = 0
|
||||
DesignSize = (
|
||||
393
|
||||
289)
|
||||
object BugIgnore1Label: TLabel
|
||||
Left = 12
|
||||
Top = 212
|
||||
Width = 169
|
||||
Height = 13
|
||||
Caption = 'Chokes on SSH-1 &ignore messages:'
|
||||
FocusControl = BugIgnore1Combo
|
||||
end
|
||||
object BugPlainPW1Label: TLabel
|
||||
Left = 12
|
||||
Top = 236
|
||||
Width = 195
|
||||
Height = 13
|
||||
Caption = 'Refuses all SSH-1 pass&word camouflage:'
|
||||
FocusControl = BugPlainPW1Combo
|
||||
end
|
||||
object BugRSA1Label: TLabel
|
||||
Left = 12
|
||||
Top = 260
|
||||
Width = 181
|
||||
Height = 13
|
||||
Caption = 'Chokes on SSH-1 &RSA authentication:'
|
||||
FocusControl = BugRSA1Combo
|
||||
end
|
||||
217)
|
||||
object BugHMAC2Label: TLabel
|
||||
Left = 12
|
||||
Top = 68
|
||||
Width = 154
|
||||
Width = 144
|
||||
Height = 13
|
||||
Caption = 'Miscomputes SSH-2 H&MAC keys:'
|
||||
Caption = 'Miscomputes SSH H&MAC keys:'
|
||||
FocusControl = BugHMAC2Combo
|
||||
end
|
||||
object BugDeriveKey2Label: TLabel
|
||||
Left = 12
|
||||
Top = 92
|
||||
Width = 176
|
||||
Width = 166
|
||||
Height = 13
|
||||
Caption = 'Miscomputes SSH-2 &encryption keys:'
|
||||
Caption = 'Miscomputes SSH &encryption keys:'
|
||||
FocusControl = BugDeriveKey2Combo
|
||||
end
|
||||
object BugRSAPad2Label: TLabel
|
||||
Left = 12
|
||||
Top = 116
|
||||
Width = 210
|
||||
Width = 200
|
||||
Height = 13
|
||||
Caption = 'Requires &padding on SSH-2 RSA signatures:'
|
||||
Caption = 'Requires &padding on SSH RSA signatures:'
|
||||
FocusControl = BugRSAPad2Combo
|
||||
end
|
||||
object BugPKSessID2Label: TLabel
|
||||
Left = 12
|
||||
Top = 140
|
||||
Width = 195
|
||||
Width = 185
|
||||
Height = 13
|
||||
Caption = 'Misuses the sessio&n ID in SSH-2 PK auth:'
|
||||
Caption = 'Misuses the sessio&n ID in SSH PK auth:'
|
||||
FocusControl = BugPKSessID2Combo
|
||||
end
|
||||
object BugRekey2Label: TLabel
|
||||
Left = 12
|
||||
Top = 164
|
||||
Width = 187
|
||||
Width = 177
|
||||
Height = 13
|
||||
Caption = 'Handles SSH-2 &key re-exchange badly:'
|
||||
Caption = 'Handles SSH &key re-exchange badly:'
|
||||
FocusControl = BugRekey2Combo
|
||||
end
|
||||
object BugMaxPkt2Label: TLabel
|
||||
Left = 12
|
||||
Top = 188
|
||||
Width = 176
|
||||
Width = 166
|
||||
Height = 13
|
||||
Caption = 'Ignores SSH-2 ma&ximum packet size:'
|
||||
Caption = 'Ignores SSH ma&ximum packet size:'
|
||||
FocusControl = BugMaxPkt2Combo
|
||||
end
|
||||
object BugIgnore2Label: TLabel
|
||||
Left = 12
|
||||
Top = 20
|
||||
Width = 169
|
||||
Width = 159
|
||||
Height = 13
|
||||
Caption = 'Chokes on SSH-&2 ignore messages:'
|
||||
Caption = 'Chokes on SSH i&gnore messages:'
|
||||
FocusControl = BugIgnore2Combo
|
||||
end
|
||||
object BugWinAdjLabel: TLabel
|
||||
Left = 12
|
||||
Top = 44
|
||||
Width = 212
|
||||
Width = 202
|
||||
Height = 13
|
||||
Caption = 'Chokes on WinSCP'#39's SSH-2 '#39'winadj'#39' requests'
|
||||
Caption = 'Chokes on WinSCP'#39's SSH '#39'&winadj'#39' requests'
|
||||
FocusControl = BugWinAdjCombo
|
||||
end
|
||||
object BugIgnore1Combo: TComboBox
|
||||
Left = 320
|
||||
Top = 207
|
||||
Width = 61
|
||||
Height = 21
|
||||
Style = csDropDownList
|
||||
Anchors = [akTop, akRight]
|
||||
TabOrder = 8
|
||||
OnChange = DataChange
|
||||
end
|
||||
object BugPlainPW1Combo: TComboBox
|
||||
Left = 320
|
||||
Top = 231
|
||||
Width = 61
|
||||
Height = 21
|
||||
Style = csDropDownList
|
||||
Anchors = [akTop, akRight]
|
||||
TabOrder = 9
|
||||
OnChange = DataChange
|
||||
end
|
||||
object BugRSA1Combo: TComboBox
|
||||
Left = 320
|
||||
Top = 255
|
||||
Width = 61
|
||||
Height = 21
|
||||
Style = csDropDownList
|
||||
Anchors = [akTop, akRight]
|
||||
TabOrder = 10
|
||||
OnChange = DataChange
|
||||
end
|
||||
object BugHMAC2Combo: TComboBox
|
||||
Left = 320
|
||||
Top = 63
|
||||
|
||||
@@ -29,7 +29,6 @@ __published:
|
||||
TPageControl *PageControl;
|
||||
TTabSheet *AdvancedSheet;
|
||||
TGroupBox *ProtocolGroup;
|
||||
TLabel *Label37;
|
||||
TCheckBox *CompressionCheck;
|
||||
TTabSheet *EnvironmentSheet;
|
||||
TTabSheet *ScpSheet;
|
||||
@@ -62,12 +61,6 @@ __published:
|
||||
TEdit *ProxyTelnetCommandEdit;
|
||||
TTabSheet *BugsSheet;
|
||||
TGroupBox *BugsGroupBox;
|
||||
TLabel *BugIgnore1Label;
|
||||
TComboBox *BugIgnore1Combo;
|
||||
TLabel *BugPlainPW1Label;
|
||||
TComboBox *BugPlainPW1Combo;
|
||||
TLabel *BugRSA1Label;
|
||||
TComboBox *BugRSA1Combo;
|
||||
TLabel *BugHMAC2Label;
|
||||
TComboBox *BugHMAC2Combo;
|
||||
TLabel *BugDeriveKey2Label;
|
||||
@@ -76,7 +69,6 @@ __published:
|
||||
TComboBox *BugRSAPad2Combo;
|
||||
TTabSheet *AuthSheet;
|
||||
TGroupBox *AuthenticationGroup;
|
||||
TCheckBox *AuthTISCheck;
|
||||
TCheckBox *AuthKICheck;
|
||||
TGroupBox *EncryptionGroup;
|
||||
TListBox *CipherListBox;
|
||||
@@ -252,7 +244,6 @@ __published:
|
||||
TLabel *Label4;
|
||||
TFilenameEdit *TlsCertificateFileEdit;
|
||||
TCheckBox *TrimVMSVersionsCheck;
|
||||
TComboBox *SshProtCombo2;
|
||||
TCheckBox *FollowDirectorySymlinksCheck;
|
||||
TImageList *ColorImageList120;
|
||||
TImageList *ColorImageList144;
|
||||
@@ -371,7 +362,6 @@ private:
|
||||
TProxyMethod __fastcall GetProxyMethod();
|
||||
int __fastcall GetFtpProxyLogonType();
|
||||
void __fastcall UpdateNavigationTree();
|
||||
TSshProt __fastcall GetSshProt();
|
||||
void __fastcall SessionColorChange(TColor Color);
|
||||
TTlsVersion __fastcall IndexToTlsVersion(int Index);
|
||||
int __fastcall TlsVersionToIndex(TTlsVersion TlsVersion);
|
||||
|
||||
1
source/putty/puttyexp.h
vendored
1
source/putty/puttyexp.h
vendored
@@ -9,7 +9,6 @@ int is_ssh(Plug * plug);
|
||||
int get_ssh_version(Backend * be);
|
||||
Seat * get_ssh_seat(Plug * plug);
|
||||
#ifdef WINSCP_SSH
|
||||
const ssh_cipher * get_cipher(Backend * be);
|
||||
const ssh_cipher * get_cscipher(Backend * be);
|
||||
const ssh_cipher * get_sccipher(Backend * be);
|
||||
#endif
|
||||
|
||||
34
source/putty/ssh.c
vendored
34
source/putty/ssh.c
vendored
@@ -187,12 +187,13 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
|
||||
* connect_to_host().
|
||||
*/
|
||||
assert(ssh->version == major_version);
|
||||
assert(ssh->version == 2);
|
||||
|
||||
old_bpp = ssh->bpp;
|
||||
ssh->remote_bugs = ssh_verstring_get_bugs(old_bpp);
|
||||
|
||||
if (!ssh->bare_connection) {
|
||||
if (ssh->version == 2) {
|
||||
/*WINSCP if (ssh->version == 2)*/ {
|
||||
PacketProtocolLayer *userauth_layer, *transport_child_layer;
|
||||
|
||||
/*
|
||||
@@ -294,19 +295,7 @@ static void ssh_got_ssh_version(struct ssh_version_receiver *rcv,
|
||||
ssh2_userauth_set_transport_layer(userauth_layer,
|
||||
ssh->base_layer);
|
||||
|
||||
} else {
|
||||
|
||||
ssh->bpp = ssh1_bpp_new(ssh->logctx);
|
||||
ssh_connect_bpp(ssh);
|
||||
|
||||
connection_layer = ssh1_connection_new(ssh, ssh->conf, &ssh->cl);
|
||||
ssh_connect_ppl(ssh, connection_layer);
|
||||
|
||||
ssh->base_layer = ssh1_login_new(
|
||||
ssh->conf, ssh->savedhost, ssh->savedport, connection_layer);
|
||||
ssh_connect_ppl(ssh, ssh->base_layer);
|
||||
|
||||
}
|
||||
} // WINSCP
|
||||
|
||||
} else {
|
||||
ssh->bpp = ssh2_bare_bpp_new(ssh->logctx);
|
||||
@@ -734,7 +723,7 @@ static char *connect_to_host(
|
||||
SockAddr *addr;
|
||||
const char *err;
|
||||
char *loghost;
|
||||
int addressfamily, sshprot;
|
||||
int addressfamily;
|
||||
|
||||
ssh_hostport_setup(host, port, ssh->conf,
|
||||
&ssh->savedhost, &ssh->savedport, &loghost);
|
||||
@@ -811,15 +800,8 @@ static char *connect_to_host(
|
||||
* The SSH version number is always fixed (since we no longer support
|
||||
* fallback between versions), so set it now.
|
||||
*/
|
||||
sshprot = conf_get_int(ssh->conf, CONF_sshprot);
|
||||
assert(sshprot == 0 || sshprot == 3);
|
||||
if (sshprot == 0)
|
||||
/* SSH-1 only */
|
||||
ssh->version = 1;
|
||||
if (sshprot == 3 || ssh->bare_connection) {
|
||||
/* SSH-2 only */
|
||||
ssh->version = 2;
|
||||
}
|
||||
ssh->version = 2; // WINSCP
|
||||
|
||||
/*
|
||||
* Set up the initial BPP that will do the version string
|
||||
@@ -1296,12 +1278,6 @@ Seat * get_ssh_seat(Plug * plug)
|
||||
return container_of(plug, Ssh, plug)->seat;
|
||||
}
|
||||
|
||||
const ssh_cipher * get_cipher(Backend * be)
|
||||
{
|
||||
Ssh * ssh = container_of(be, Ssh, backend);
|
||||
return ssh1_bpp_get_cipher(ssh->bpp);
|
||||
}
|
||||
|
||||
const ssh_cipher * get_cscipher(Backend * be)
|
||||
{
|
||||
Ssh * ssh = container_of(be, Ssh, backend);
|
||||
|
||||
395
source/putty/ssh1bpp.c
vendored
395
source/putty/ssh1bpp.c
vendored
@@ -1,395 +0,0 @@
|
||||
/*
|
||||
* Binary packet protocol for SSH-1.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbpp.h"
|
||||
#include "sshcr.h"
|
||||
|
||||
struct ssh1_bpp_state {
|
||||
int crState;
|
||||
long len, pad, biglen, length, maxlen;
|
||||
unsigned char *data;
|
||||
uint32_t realcrc, gotcrc;
|
||||
int chunk;
|
||||
PktIn *pktin;
|
||||
|
||||
ssh_cipher *cipher_in, *cipher_out;
|
||||
|
||||
struct crcda_ctx *crcda_ctx;
|
||||
uint8_t iv[8]; /* for crcda */
|
||||
|
||||
bool pending_compression_request;
|
||||
ssh_compressor *compctx;
|
||||
ssh_decompressor *decompctx;
|
||||
|
||||
BinaryPacketProtocol bpp;
|
||||
};
|
||||
|
||||
static void ssh1_bpp_free(BinaryPacketProtocol *bpp);
|
||||
static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp);
|
||||
static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp);
|
||||
static void ssh1_bpp_queue_disconnect(BinaryPacketProtocol *bpp,
|
||||
const char *msg, int category);
|
||||
static PktOut *ssh1_bpp_new_pktout(int type);
|
||||
|
||||
static const BinaryPacketProtocolVtable ssh1_bpp_vtable = {
|
||||
// WINSCP
|
||||
/*.free =*/ ssh1_bpp_free,
|
||||
/*.handle_input =*/ ssh1_bpp_handle_input,
|
||||
/*.handle_output =*/ ssh1_bpp_handle_output,
|
||||
/*.new_pktout =*/ ssh1_bpp_new_pktout,
|
||||
/*.queue_disconnect =*/ ssh1_bpp_queue_disconnect,
|
||||
/*.packet_size_limit =*/ 0xFFFFFFFF, /* no special limit for this bpp */
|
||||
};
|
||||
|
||||
BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx)
|
||||
{
|
||||
struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state);
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->bpp.vt = &ssh1_bpp_vtable;
|
||||
s->bpp.logctx = logctx;
|
||||
ssh_bpp_common_setup(&s->bpp);
|
||||
return &s->bpp;
|
||||
}
|
||||
|
||||
static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
if (s->cipher_in)
|
||||
ssh_cipher_free(s->cipher_in);
|
||||
if (s->cipher_out)
|
||||
ssh_cipher_free(s->cipher_out);
|
||||
if (s->compctx)
|
||||
ssh_compressor_free(s->compctx);
|
||||
if (s->decompctx)
|
||||
ssh_decompressor_free(s->decompctx);
|
||||
if (s->crcda_ctx)
|
||||
crcda_free_context(s->crcda_ctx);
|
||||
sfree(s->pktin);
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
|
||||
const ssh_cipheralg *cipher,
|
||||
const void *session_key)
|
||||
{
|
||||
struct ssh1_bpp_state *s;
|
||||
assert(bpp->vt == &ssh1_bpp_vtable);
|
||||
s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
assert(!s->cipher_in);
|
||||
assert(!s->cipher_out);
|
||||
|
||||
if (cipher) {
|
||||
s->cipher_in = ssh_cipher_new(cipher);
|
||||
s->cipher_out = ssh_cipher_new(cipher);
|
||||
ssh_cipher_setkey(s->cipher_in, session_key);
|
||||
ssh_cipher_setkey(s->cipher_out, session_key);
|
||||
|
||||
assert(!s->crcda_ctx);
|
||||
s->crcda_ctx = crcda_make_context();
|
||||
|
||||
bpp_logevent("Initialised %s encryption", cipher->text_name);
|
||||
|
||||
memset(s->iv, 0, sizeof(s->iv));
|
||||
|
||||
assert(cipher->blksize <= sizeof(s->iv));
|
||||
ssh_cipher_setiv(s->cipher_in, s->iv);
|
||||
ssh_cipher_setiv(s->cipher_out, s->iv);
|
||||
}
|
||||
}
|
||||
|
||||
void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s;
|
||||
assert(bpp->vt == &ssh1_bpp_vtable);
|
||||
s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
assert(!s->compctx);
|
||||
assert(!s->decompctx);
|
||||
|
||||
s->compctx = ssh_compressor_new(&ssh_zlib);
|
||||
s->decompctx = ssh_decompressor_new(&ssh_zlib);
|
||||
|
||||
bpp_logevent("Started zlib (RFC1950) compression");
|
||||
}
|
||||
|
||||
#define BPP_READ(ptr, len) do \
|
||||
{ \
|
||||
bool success; \
|
||||
crMaybeWaitUntilV((success = bufchain_try_fetch_consume( \
|
||||
s->bpp.in_raw, ptr, len)) || \
|
||||
s->bpp.input_eof); \
|
||||
if (!success) \
|
||||
goto eof; \
|
||||
ssh_check_frozen(s->bpp.ssh); \
|
||||
} while (0)
|
||||
|
||||
static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
|
||||
crBegin(s->crState);
|
||||
|
||||
while (1) {
|
||||
s->maxlen = 0;
|
||||
s->length = 0;
|
||||
|
||||
{
|
||||
unsigned char lenbuf[4];
|
||||
BPP_READ(lenbuf, 4);
|
||||
s->len = toint(GET_32BIT_MSB_FIRST(lenbuf));
|
||||
}
|
||||
|
||||
if (s->len < 5 || s->len > 262144) { /* SSH1.5-mandated max size */
|
||||
ssh_sw_abort(s->bpp.ssh,
|
||||
"Out-of-range packet length from remote suggests"
|
||||
" data stream corruption");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
s->pad = 8 - (s->len % 8);
|
||||
s->biglen = s->len + s->pad;
|
||||
s->length = s->len - 5;
|
||||
|
||||
/*
|
||||
* Allocate the packet to return, now we know its length.
|
||||
*/
|
||||
s->pktin = snew_plus(PktIn, s->biglen);
|
||||
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
||||
s->pktin->qnode.on_free_queue = false;
|
||||
s->pktin->type = 0;
|
||||
|
||||
s->maxlen = s->biglen;
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
|
||||
BPP_READ(s->data, s->biglen);
|
||||
|
||||
if (s->cipher_in && detect_attack(s->crcda_ctx,
|
||||
s->data, s->biglen, s->iv)) {
|
||||
ssh_sw_abort(s->bpp.ssh,
|
||||
"Network attack (CRC compensation) detected!");
|
||||
crStopV;
|
||||
}
|
||||
/* Save the last cipher block, to be passed to the next call
|
||||
* to detect_attack */
|
||||
assert(s->biglen >= 8);
|
||||
memcpy(s->iv, s->data + s->biglen - 8, sizeof(s->iv));
|
||||
|
||||
if (s->cipher_in)
|
||||
ssh_cipher_decrypt(s->cipher_in, s->data, s->biglen);
|
||||
|
||||
s->realcrc = crc32_ssh1(make_ptrlen(s->data, s->biglen - 4));
|
||||
s->gotcrc = GET_32BIT_MSB_FIRST(s->data + s->biglen - 4);
|
||||
if (s->gotcrc != s->realcrc) {
|
||||
ssh_sw_abort(s->bpp.ssh, "Incorrect CRC received on packet");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
if (s->decompctx) {
|
||||
unsigned char *decompblk;
|
||||
int decomplen;
|
||||
if (!ssh_decompressor_decompress(
|
||||
s->decompctx, s->data + s->pad, s->length + 1,
|
||||
&decompblk, &decomplen)) {
|
||||
ssh_sw_abort(s->bpp.ssh,
|
||||
"Zlib decompression encountered invalid data");
|
||||
crStopV;
|
||||
}
|
||||
|
||||
if (s->maxlen < s->pad + decomplen) {
|
||||
PktIn *old_pktin = s->pktin;
|
||||
|
||||
s->maxlen = s->pad + decomplen;
|
||||
s->pktin = snew_plus(PktIn, s->maxlen);
|
||||
*s->pktin = *old_pktin; /* structure copy */
|
||||
s->data = snew_plus_get_aux(s->pktin);
|
||||
|
||||
smemclr(old_pktin, s->biglen);
|
||||
sfree(old_pktin);
|
||||
}
|
||||
|
||||
memcpy(s->data + s->pad, decompblk, decomplen);
|
||||
sfree(decompblk);
|
||||
s->length = decomplen - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can find the bounds of the semantic content of the
|
||||
* packet, and the initial type byte.
|
||||
*/
|
||||
s->data += s->pad;
|
||||
s->pktin->type = *s->data++;
|
||||
BinarySource_INIT(s->pktin, s->data, s->length);
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh1_censor_packet(
|
||||
s->bpp.pls, s->pktin->type, false,
|
||||
make_ptrlen(s->data, s->length), blanks);
|
||||
log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
|
||||
ssh1_pkt_type(s->pktin->type),
|
||||
get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
s->pktin->qnode.formal_size = get_avail(s->pktin);
|
||||
pq_push(&s->bpp.in_pq, s->pktin);
|
||||
|
||||
{
|
||||
int type = s->pktin->type;
|
||||
s->pktin = NULL;
|
||||
|
||||
switch (type) {
|
||||
case SSH1_SMSG_SUCCESS:
|
||||
case SSH1_SMSG_FAILURE:
|
||||
if (s->pending_compression_request) {
|
||||
/*
|
||||
* This is the response to
|
||||
* SSH1_CMSG_REQUEST_COMPRESSION.
|
||||
*/
|
||||
if (type == SSH1_SMSG_SUCCESS) {
|
||||
/*
|
||||
* If the response was positive, start
|
||||
* compression.
|
||||
*/
|
||||
ssh1_bpp_start_compression(&s->bpp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Either way, cancel the pending flag, and
|
||||
* schedule a run of our output side in case we
|
||||
* had any packets queued up in the meantime.
|
||||
*/
|
||||
s->pending_compression_request = false;
|
||||
queue_idempotent_callback(&s->bpp.ic_out_pq);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eof:
|
||||
if (!s->bpp.expect_close) {
|
||||
ssh_remote_error(s->bpp.ssh,
|
||||
"Remote side unexpectedly closed network connection");
|
||||
} else {
|
||||
ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection");
|
||||
}
|
||||
return; /* avoid touching s now it's been freed */
|
||||
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static PktOut *ssh1_bpp_new_pktout(int pkt_type)
|
||||
{
|
||||
PktOut *pkt = ssh_new_packet();
|
||||
pkt->length = 4 + 8; /* space for length + max padding */
|
||||
put_byte(pkt, pkt_type);
|
||||
pkt->prefix = pkt->length;
|
||||
pkt->type = pkt_type;
|
||||
pkt->downstream_id = 0;
|
||||
pkt->additional_log_text = NULL;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt)
|
||||
{
|
||||
int pad, biglen, pktoffs;
|
||||
uint32_t crc;
|
||||
int len;
|
||||
|
||||
if (s->bpp.logctx) {
|
||||
ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix,
|
||||
pkt->length - pkt->prefix);
|
||||
logblank_t blanks[MAX_BLANKS];
|
||||
int nblanks = ssh1_censor_packet(
|
||||
s->bpp.pls, pkt->type, true, pktdata, blanks);
|
||||
log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
|
||||
ssh1_pkt_type(pkt->type),
|
||||
pktdata.ptr, pktdata.len, nblanks, blanks,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (s->compctx) {
|
||||
unsigned char *compblk;
|
||||
int complen;
|
||||
ssh_compressor_compress(s->compctx, pkt->data + 12, pkt->length - 12,
|
||||
&compblk, &complen, 0);
|
||||
/* Replace the uncompressed packet data with the compressed
|
||||
* version. */
|
||||
pkt->length = 12;
|
||||
put_data(pkt, compblk, complen);
|
||||
sfree(compblk);
|
||||
}
|
||||
|
||||
put_uint32(pkt, 0); /* space for CRC */
|
||||
len = pkt->length - 4 - 8; /* len(type+data+CRC) */
|
||||
pad = 8 - (len % 8);
|
||||
pktoffs = 8 - pad;
|
||||
biglen = len + pad; /* len(padding+type+data+CRC) */
|
||||
|
||||
random_read(pkt->data + pktoffs, 4+8 - pktoffs);
|
||||
crc = crc32_ssh1(
|
||||
make_ptrlen(pkt->data + pktoffs + 4, biglen - 4)); /* all ex len */
|
||||
PUT_32BIT_MSB_FIRST(pkt->data + pktoffs + 4 + biglen - 4, crc);
|
||||
PUT_32BIT_MSB_FIRST(pkt->data + pktoffs, len);
|
||||
|
||||
if (s->cipher_out)
|
||||
ssh_cipher_encrypt(s->cipher_out, pkt->data + pktoffs + 4, biglen);
|
||||
|
||||
bufchain_add(s->bpp.out_raw, pkt->data + pktoffs,
|
||||
biglen + 4); /* len(length+padding+type+data+CRC) */
|
||||
}
|
||||
|
||||
static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
|
||||
PktOut *pkt;
|
||||
|
||||
if (s->pending_compression_request) {
|
||||
/*
|
||||
* Don't send any output packets while we're awaiting a
|
||||
* response to SSH1_CMSG_REQUEST_COMPRESSION, because if they
|
||||
* cross over in transit with the responding SSH1_CMSG_SUCCESS
|
||||
* then the other end could decode them with the wrong
|
||||
* compression settings.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) {
|
||||
int type = pkt->type;
|
||||
ssh1_bpp_format_packet(s, pkt);
|
||||
ssh_free_pktout(pkt);
|
||||
|
||||
if (type == SSH1_CMSG_REQUEST_COMPRESSION) {
|
||||
/*
|
||||
* When we see the actual compression request go past, set
|
||||
* the pending flag, and stop processing packets this
|
||||
* time.
|
||||
*/
|
||||
s->pending_compression_request = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh1_bpp_queue_disconnect(BinaryPacketProtocol *bpp,
|
||||
const char *msg, int category)
|
||||
{
|
||||
PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH1_MSG_DISCONNECT);
|
||||
put_stringz(pkt, msg);
|
||||
pq_push(&bpp->out_pq, pkt);
|
||||
}
|
||||
|
||||
#ifdef MPEXT
|
||||
const ssh_cipher * ssh1_bpp_get_cipher(BinaryPacketProtocol *bpp)
|
||||
{
|
||||
return container_of(bpp, struct ssh1_bpp_state, bpp)->cipher_in; // cipher_out should be the same
|
||||
}
|
||||
#endif
|
||||
76
source/putty/ssh1censor.c
vendored
76
source/putty/ssh1censor.c
vendored
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Packet-censoring code for SSH-1, used to identify sensitive fields
|
||||
* like passwords so that the logging system can avoid writing them
|
||||
* into log files.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
|
||||
int ssh1_censor_packet(
|
||||
const PacketLogSettings *pls, int type, bool sender_is_client,
|
||||
ptrlen pkt, logblank_t *blanks)
|
||||
{
|
||||
int nblanks = 0;
|
||||
ptrlen str;
|
||||
BinarySource src[1];
|
||||
|
||||
BinarySource_BARE_INIT_PL(src, pkt);
|
||||
|
||||
if (pls->omit_data &&
|
||||
(type == SSH1_SMSG_STDOUT_DATA ||
|
||||
type == SSH1_SMSG_STDERR_DATA ||
|
||||
type == SSH1_CMSG_STDIN_DATA ||
|
||||
type == SSH1_MSG_CHANNEL_DATA)) {
|
||||
/* "Session data" packets - omit the data string. */
|
||||
if (type == SSH1_MSG_CHANNEL_DATA)
|
||||
get_uint32(src); /* skip channel id */
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_OMIT;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sender_is_client && pls->omit_passwords) {
|
||||
if (type == SSH1_CMSG_AUTH_PASSWORD ||
|
||||
type == SSH1_CMSG_AUTH_TIS_RESPONSE ||
|
||||
type == SSH1_CMSG_AUTH_CCARD_RESPONSE) {
|
||||
/* If this is a password or similar packet, blank the
|
||||
* password(s). */
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = 0;
|
||||
blanks[nblanks].len = pkt.len;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
nblanks++;
|
||||
} else if (type == SSH1_CMSG_X11_REQUEST_FORWARDING) {
|
||||
/*
|
||||
* If this is an X forwarding request packet, blank the
|
||||
* fake auth data.
|
||||
*
|
||||
* Note that while we blank the X authentication data
|
||||
* here, we don't take any special action to blank the
|
||||
* start of an X11 channel, so using MIT-MAGIC-COOKIE-1
|
||||
* and actually opening an X connection without having
|
||||
* session blanking enabled is likely to leak your cookie
|
||||
* into the log.
|
||||
*/
|
||||
get_string(src); /* skip protocol name */
|
||||
str = get_string(src);
|
||||
if (!get_err(src)) {
|
||||
assert(nblanks < MAX_BLANKS);
|
||||
blanks[nblanks].offset = src->pos - str.len;
|
||||
blanks[nblanks].type = PKTLOG_BLANK;
|
||||
blanks[nblanks].len = str.len;
|
||||
nblanks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nblanks;
|
||||
}
|
||||
558
source/putty/ssh1connection-client.c
vendored
558
source/putty/ssh1connection-client.c
vendored
@@ -1,558 +0,0 @@
|
||||
/*
|
||||
* Client-specific parts of the SSH-1 connection layer.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbpp.h"
|
||||
#include "sshppl.h"
|
||||
#include "sshchan.h"
|
||||
#include "sshcr.h"
|
||||
#include "ssh1connection.h"
|
||||
|
||||
// WINSCP
|
||||
#define queue_toplevel_callback(FN, CTX) queue_toplevel_callback(get_log_callback_set(CTX->cl.logctx), FN, CTX)
|
||||
|
||||
void ssh1_connection_direction_specific_setup(
|
||||
struct ssh1_connection_state *s)
|
||||
{
|
||||
if (!s->mainchan) {
|
||||
/*
|
||||
* Start up the main session, by telling mainchan.c to do it
|
||||
* all just as it would in SSH-2, and translating those
|
||||
* concepts to SSH-1's non-channel-shaped idea of the main
|
||||
* session.
|
||||
*/
|
||||
s->mainchan = mainchan_new(
|
||||
&s->ppl, &s->cl, s->conf, s->term_width, s->term_height,
|
||||
false /* is_simple */, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s,
|
||||
bool success, void *ctx);
|
||||
|
||||
struct outstanding_succfail {
|
||||
sf_handler_fn_t handler;
|
||||
void *ctx;
|
||||
struct outstanding_succfail *next;
|
||||
|
||||
/*
|
||||
* The 'trivial' flag is set if this handler is in response to a
|
||||
* request for which the SSH-1 protocol doesn't actually specify a
|
||||
* response packet. The client of this system (mainchan.c) will
|
||||
* expect to get an acknowledgment regardless, so we arrange to
|
||||
* send that ack immediately after the rest of the queue empties.
|
||||
*/
|
||||
bool trivial;
|
||||
};
|
||||
|
||||
static void ssh1_connection_process_trivial_succfails(void *vs);
|
||||
|
||||
static void ssh1_queue_succfail_handler(
|
||||
struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx,
|
||||
bool trivial)
|
||||
{
|
||||
struct outstanding_succfail *osf = snew(struct outstanding_succfail);
|
||||
osf->handler = handler;
|
||||
osf->ctx = ctx;
|
||||
osf->trivial = trivial;
|
||||
osf->next = NULL;
|
||||
if (s->succfail_tail)
|
||||
s->succfail_tail->next = osf;
|
||||
else
|
||||
s->succfail_head = osf;
|
||||
s->succfail_tail = osf;
|
||||
|
||||
/* In case this one was trivial and the queue was already empty,
|
||||
* we should make sure we run the handler promptly, and the
|
||||
* easiest way is to queue it anyway and then run a trivials pass
|
||||
* by callback. */
|
||||
queue_toplevel_callback(ssh1_connection_process_trivial_succfails, s);
|
||||
}
|
||||
|
||||
static void ssh1_connection_process_succfail(
|
||||
struct ssh1_connection_state *s, bool success)
|
||||
{
|
||||
struct outstanding_succfail *prevhead = s->succfail_head;
|
||||
s->succfail_head = s->succfail_head->next;
|
||||
if (!s->succfail_head)
|
||||
s->succfail_tail = NULL;
|
||||
prevhead->handler(s, success, prevhead->ctx);
|
||||
sfree(prevhead);
|
||||
}
|
||||
|
||||
static void ssh1_connection_process_trivial_succfails(void *vs)
|
||||
{
|
||||
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs;
|
||||
while (s->succfail_head && s->succfail_head->trivial)
|
||||
ssh1_connection_process_succfail(s, true);
|
||||
}
|
||||
|
||||
bool ssh1_handle_direction_specific_packet(
|
||||
struct ssh1_connection_state *s, PktIn *pktin)
|
||||
{
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
|
||||
PktOut *pktout;
|
||||
struct ssh1_channel *c;
|
||||
unsigned remid;
|
||||
struct ssh_rportfwd pf, *pfp;
|
||||
ptrlen host, data;
|
||||
int port;
|
||||
|
||||
switch (pktin->type) {
|
||||
case SSH1_SMSG_SUCCESS:
|
||||
case SSH1_SMSG_FAILURE:
|
||||
if (!s->succfail_head) {
|
||||
ssh_remote_error(s->ppl.ssh,
|
||||
"Received %s with no outstanding request",
|
||||
ssh1_pkt_type(pktin->type));
|
||||
return true;
|
||||
}
|
||||
|
||||
ssh1_connection_process_succfail(
|
||||
s, pktin->type == SSH1_SMSG_SUCCESS);
|
||||
queue_toplevel_callback(
|
||||
ssh1_connection_process_trivial_succfails, s);
|
||||
|
||||
return true;
|
||||
|
||||
case SSH1_SMSG_X11_OPEN:
|
||||
remid = get_uint32(pktin);
|
||||
|
||||
/* Refuse if X11 forwarding is disabled. */
|
||||
if (!s->X11_fwd_enabled) {
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
ppl_logevent("Rejected X11 connect request");
|
||||
} else {
|
||||
c = snew(struct ssh1_channel);
|
||||
c->connlayer = s;
|
||||
ssh1_channel_init(c);
|
||||
c->remoteid = remid;
|
||||
c->chan = x11_new_channel(s->x11authtree, &c->sc,
|
||||
NULL, -1, false);
|
||||
c->remoteid = remid;
|
||||
c->halfopen = false;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_uint32(pktout, c->localid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
ppl_logevent("Opened X11 forward channel");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case SSH1_SMSG_AGENT_OPEN:
|
||||
remid = get_uint32(pktin);
|
||||
|
||||
/* Refuse if agent forwarding is disabled. */
|
||||
if (!ssh_agent_forwarding_permitted(&s->cl)) {
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} else {
|
||||
c = snew(struct ssh1_channel);
|
||||
c->connlayer = s;
|
||||
ssh1_channel_init(c);
|
||||
c->remoteid = remid;
|
||||
c->halfopen = false;
|
||||
|
||||
/*
|
||||
* If possible, make a stream-oriented connection to the
|
||||
* agent and set up an ordinary port-forwarding type
|
||||
* channel over it.
|
||||
*/
|
||||
{ // WINSCP
|
||||
Plug *plug;
|
||||
Channel *ch = portfwd_raw_new(&s->cl, &plug, true);
|
||||
Socket *skt = agent_connect(plug);
|
||||
if (!sk_socket_error(skt)) {
|
||||
portfwd_raw_setup(ch, skt, &c->sc);
|
||||
c->chan = ch;
|
||||
} else {
|
||||
portfwd_raw_free(ch);
|
||||
|
||||
/*
|
||||
* Otherwise, fall back to the old-fashioned system of
|
||||
* parsing the forwarded data stream ourselves for
|
||||
* message boundaries, and passing each individual
|
||||
* message to the one-off agent_query().
|
||||
*/
|
||||
c->chan = agentf_new(&c->sc);
|
||||
}
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_uint32(pktout, c->localid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} // WINSCP
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case SSH1_MSG_PORT_OPEN:
|
||||
remid = get_uint32(pktin);
|
||||
host = get_string(pktin);
|
||||
port = toint(get_uint32(pktin));
|
||||
|
||||
pf.dhost = mkstr(host);
|
||||
pf.dport = port;
|
||||
pfp = find234(s->rportfwds, &pf, NULL);
|
||||
|
||||
if (!pfp) {
|
||||
ppl_logevent("Rejected remote port open request for %s:%d",
|
||||
pf.dhost, port);
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} else {
|
||||
char *err;
|
||||
|
||||
c = snew(struct ssh1_channel);
|
||||
c->connlayer = s;
|
||||
ppl_logevent("Received remote port open request for %s:%d",
|
||||
pf.dhost, port);
|
||||
err = portfwdmgr_connect(
|
||||
s->portfwdmgr, &c->chan, pf.dhost, port,
|
||||
&c->sc, pfp->addressfamily);
|
||||
|
||||
if (err) {
|
||||
ppl_logevent("Port open failed: %s", err);
|
||||
sfree(err);
|
||||
ssh1_channel_free(c);
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} else {
|
||||
ssh1_channel_init(c);
|
||||
c->remoteid = remid;
|
||||
c->halfopen = false;
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_uint32(pktout, c->localid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
ppl_logevent("Forwarded port opened successfully");
|
||||
}
|
||||
}
|
||||
|
||||
sfree(pf.dhost);
|
||||
|
||||
return true;
|
||||
|
||||
case SSH1_SMSG_STDOUT_DATA:
|
||||
case SSH1_SMSG_STDERR_DATA:
|
||||
data = get_string(pktin);
|
||||
if (!get_err(pktin)) {
|
||||
int bufsize = seat_output(
|
||||
s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA,
|
||||
data.ptr, data.len);
|
||||
if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
|
||||
s->stdout_throttling = true;
|
||||
ssh_throttle_conn(s->ppl.ssh, +1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case SSH1_SMSG_EXIT_STATUS: {
|
||||
int exitcode = get_uint32(pktin);
|
||||
ppl_logevent("Server sent command exit status %d", exitcode);
|
||||
ssh_got_exitcode(s->ppl.ssh, exitcode);
|
||||
|
||||
s->session_terminated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s,
|
||||
bool success, void *ctx)
|
||||
{
|
||||
chan_request_response(s->mainchan_chan, success);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s,
|
||||
bool success, void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static void ssh1mainchan_queue_response(struct ssh1_connection_state *s,
|
||||
bool want_reply, bool trivial)
|
||||
{
|
||||
sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply :
|
||||
ssh1mainchan_succfail_nowantreply);
|
||||
ssh1_queue_succfail_handler(s, handler, NULL, trivial);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_request_x11_forwarding(
|
||||
SshChannel *sc, bool want_reply, const char *authproto,
|
||||
const char *authdata, int screen_number, bool oneshot)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING);
|
||||
put_stringz(pktout, authproto);
|
||||
put_stringz(pktout, authdata);
|
||||
if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER)
|
||||
put_uint32(pktout, screen_number);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, false);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_request_agent_forwarding(
|
||||
SshChannel *sc, bool want_reply)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, false);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_request_pty(
|
||||
SshChannel *sc, bool want_reply, Conf *conf, int w, int h)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY);
|
||||
put_stringz(pktout, conf_get_str(s->conf, CONF_termtype));
|
||||
put_uint32(pktout, h);
|
||||
put_uint32(pktout, w);
|
||||
put_uint32(pktout, 0); /* width in pixels */
|
||||
put_uint32(pktout, 0); /* height in pixels */
|
||||
write_ttymodes_to_packet(
|
||||
BinarySink_UPCAST(pktout), 1,
|
||||
get_ttymodes_from_conf(s->ppl.seat, conf));
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, false);
|
||||
}
|
||||
|
||||
static bool ssh1mainchan_send_env_var(
|
||||
SshChannel *sc, bool want_reply, const char *var, const char *value)
|
||||
{
|
||||
return false; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static void ssh1mainchan_start_shell(SshChannel *sc, bool want_reply)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, true);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_start_command(
|
||||
SshChannel *sc, bool want_reply, const char *command)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD);
|
||||
put_stringz(pktout, command);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, true);
|
||||
}
|
||||
|
||||
static bool ssh1mainchan_start_subsystem(
|
||||
SshChannel *sc, bool want_reply, const char *subsystem)
|
||||
{
|
||||
return false; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static bool ssh1mainchan_send_serial_break(
|
||||
SshChannel *sc, bool want_reply, int length)
|
||||
{
|
||||
return false; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static bool ssh1mainchan_send_signal(
|
||||
SshChannel *sc, bool want_reply, const char *signame)
|
||||
{
|
||||
return false; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static void ssh1mainchan_send_terminal_size_change(
|
||||
SshChannel *sc, int w, int h)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE);
|
||||
put_uint32(pktout, h);
|
||||
put_uint32(pktout, w);
|
||||
put_uint32(pktout, 0); /* width in pixels */
|
||||
put_uint32(pktout, 0); /* height in pixels */
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc)
|
||||
{
|
||||
}
|
||||
|
||||
static size_t ssh1mainchan_write(
|
||||
SshChannel *sc, bool is_stderr, const void *data, size_t len)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA);
|
||||
put_string(pktout, data, len);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssh1mainchan_write_eof(SshChannel *sc)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
}
|
||||
|
||||
static const SshChannelVtable ssh1mainchan_vtable = {
|
||||
// WINSCP
|
||||
/*.write =*/ ssh1mainchan_write,
|
||||
/*.write_eof =*/ ssh1mainchan_write_eof,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // WINSCP
|
||||
/*.request_x11_forwarding =*/ ssh1mainchan_request_x11_forwarding,
|
||||
/*.request_agent_forwarding =*/ ssh1mainchan_request_agent_forwarding,
|
||||
/*.request_pty =*/ ssh1mainchan_request_pty,
|
||||
/*.send_env_var =*/ ssh1mainchan_send_env_var,
|
||||
/*.start_shell =*/ ssh1mainchan_start_shell,
|
||||
/*.start_command =*/ ssh1mainchan_start_command,
|
||||
/*.start_subsystem =*/ ssh1mainchan_start_subsystem,
|
||||
/*.send_serial_break =*/ ssh1mainchan_send_serial_break,
|
||||
/*.send_signal =*/ ssh1mainchan_send_signal,
|
||||
/*.send_terminal_size_change =*/ ssh1mainchan_send_terminal_size_change,
|
||||
/*.hint_channel_is_simple =*/ ssh1mainchan_hint_channel_is_simple,
|
||||
/* other methods are NULL */
|
||||
};
|
||||
|
||||
static void ssh1_session_confirm_callback(void *vctx)
|
||||
{
|
||||
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx;
|
||||
chan_open_confirmation(s->mainchan_chan);
|
||||
}
|
||||
|
||||
SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
s->mainchan_sc.vt = &ssh1mainchan_vtable;
|
||||
s->mainchan_sc.cl = &s->cl;
|
||||
s->mainchan_chan = chan;
|
||||
queue_toplevel_callback(ssh1_session_confirm_callback, s);
|
||||
return &s->mainchan_sc;
|
||||
}
|
||||
|
||||
static void ssh1_rportfwd_response(struct ssh1_connection_state *s,
|
||||
bool success, void *ctx)
|
||||
{
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx;
|
||||
|
||||
if (success) {
|
||||
ppl_logevent("Remote port forwarding from %s enabled",
|
||||
rpf->log_description);
|
||||
} else {
|
||||
ppl_logevent("Remote port forwarding from %s refused",
|
||||
rpf->log_description);
|
||||
|
||||
{ // WINSCP
|
||||
struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
|
||||
assert(realpf == rpf);
|
||||
portfwdmgr_close(s->portfwdmgr, rpf->pfr);
|
||||
free_rportfwd(rpf);
|
||||
} // WINSCP
|
||||
}
|
||||
}
|
||||
|
||||
struct ssh_rportfwd *ssh1_rportfwd_alloc(
|
||||
ConnectionLayer *cl,
|
||||
const char *shost, int sport, const char *dhost, int dport,
|
||||
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
||||
ssh_sharing_connstate *share_ctx)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd);
|
||||
|
||||
rpf->shost = dupstr(shost);
|
||||
rpf->sport = sport;
|
||||
rpf->dhost = dupstr(dhost);
|
||||
rpf->dport = dport;
|
||||
rpf->addressfamily = addressfamily;
|
||||
rpf->log_description = dupstr(log_description);
|
||||
rpf->pfr = pfr;
|
||||
|
||||
if (add234(s->rportfwds, rpf) != rpf) {
|
||||
free_rportfwd(rpf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{ // WINSCP
|
||||
PktOut *pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
|
||||
put_uint32(pktout, rpf->sport);
|
||||
put_stringz(pktout, rpf->dhost);
|
||||
put_uint32(pktout, rpf->dport);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} // WINSCP
|
||||
|
||||
ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, false);
|
||||
|
||||
return rpf;
|
||||
}
|
||||
|
||||
SshChannel *ssh1_serverside_x11_open(
|
||||
ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi)
|
||||
{
|
||||
unreachable("Should never be called in the client");
|
||||
}
|
||||
|
||||
SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan)
|
||||
{
|
||||
unreachable("Should never be called in the client");
|
||||
}
|
||||
|
||||
bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s)
|
||||
{
|
||||
return !seat_set_trust_status(s->ppl.seat, false);
|
||||
}
|
||||
851
source/putty/ssh1connection.c
vendored
851
source/putty/ssh1connection.c
vendored
@@ -1,851 +0,0 @@
|
||||
/*
|
||||
* Packet protocol layer for the SSH-1 'connection protocol', i.e.
|
||||
* everything after authentication finishes.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbpp.h"
|
||||
#include "sshppl.h"
|
||||
#include "sshchan.h"
|
||||
#include "sshcr.h"
|
||||
#include "ssh1connection.h"
|
||||
|
||||
// WINSCP
|
||||
#define queue_toplevel_callback(FN, CTX) queue_toplevel_callback(get_log_callback_set(CTX->cl.logctx), FN, CTX)
|
||||
|
||||
static int ssh1_rportfwd_cmp(void *av, void *bv)
|
||||
{
|
||||
struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
|
||||
struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
|
||||
int i;
|
||||
if ( (i = strcmp(a->dhost, b->dhost)) != 0)
|
||||
return i < 0 ? -1 : +1;
|
||||
if (a->dport > b->dport)
|
||||
return +1;
|
||||
if (a->dport < b->dport)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssh1_connection_free(PacketProtocolLayer *);
|
||||
static void ssh1_connection_process_queue(PacketProtocolLayer *);
|
||||
static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl,
|
||||
SessionSpecialCode code, int arg);
|
||||
static bool ssh1_connection_want_user_input(PacketProtocolLayer *ppl);
|
||||
static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl);
|
||||
static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf);
|
||||
static unsigned int ssh1_connection_winscp_query(PacketProtocolLayer *ppl, int query);
|
||||
|
||||
static const PacketProtocolLayerVtable ssh1_connection_vtable = {
|
||||
// WINSCP
|
||||
/*.free =*/ ssh1_connection_free,
|
||||
/*.process_queue =*/ ssh1_connection_process_queue,
|
||||
/*.get_specials =*/ ssh1_common_get_specials,
|
||||
/*.special_cmd =*/ ssh1_connection_special_cmd,
|
||||
/*.want_user_input =*/ ssh1_connection_want_user_input,
|
||||
/*.got_user_input =*/ ssh1_connection_got_user_input,
|
||||
/*.reconfigure =*/ ssh1_connection_reconfigure,
|
||||
/*.queued_data_size =*/ ssh_ppl_default_queued_data_size,
|
||||
/*.name =*/ NULL, /* no layer names in SSH-1 */
|
||||
ssh1_connection_winscp_query,
|
||||
};
|
||||
|
||||
static void ssh1_rportfwd_remove(
|
||||
ConnectionLayer *cl, struct ssh_rportfwd *rpf);
|
||||
static SshChannel *ssh1_lportfwd_open(
|
||||
ConnectionLayer *cl, const char *hostname, int port,
|
||||
const char *description, const SocketPeerInfo *pi, Channel *chan);
|
||||
static struct X11FakeAuth *ssh1_add_x11_display(
|
||||
ConnectionLayer *cl, int authtype, struct X11Display *disp);
|
||||
static bool ssh1_agent_forwarding_permitted(ConnectionLayer *cl);
|
||||
static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height);
|
||||
static void ssh1_stdout_unthrottle(ConnectionLayer *cl, size_t bufsize);
|
||||
static size_t ssh1_stdin_backlog(ConnectionLayer *cl);
|
||||
static void ssh1_throttle_all_channels(ConnectionLayer *cl, bool throttled);
|
||||
static bool ssh1_ldisc_option(ConnectionLayer *cl, int option);
|
||||
static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, bool value);
|
||||
static void ssh1_enable_x_fwd(ConnectionLayer *cl);
|
||||
static void ssh1_set_wants_user_input(ConnectionLayer *cl, bool wanted);
|
||||
|
||||
static const ConnectionLayerVtable ssh1_connlayer_vtable = {
|
||||
// WINSCP
|
||||
/*.rportfwd_alloc =*/ ssh1_rportfwd_alloc,
|
||||
/*.rportfwd_remove =*/ ssh1_rportfwd_remove,
|
||||
/*.lportfwd_open =*/ ssh1_lportfwd_open,
|
||||
/*.session_open =*/ ssh1_session_open,
|
||||
/*.serverside_x11_open =*/ ssh1_serverside_x11_open,
|
||||
/*.serverside_agent_open =*/ ssh1_serverside_agent_open,
|
||||
/*.add_x11_display =*/ ssh1_add_x11_display,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, // WINSCP
|
||||
/*.agent_forwarding_permitted =*/ ssh1_agent_forwarding_permitted,
|
||||
/*.terminal_size =*/ ssh1_terminal_size,
|
||||
/*.stdout_unthrottle =*/ ssh1_stdout_unthrottle,
|
||||
/*.stdin_backlog =*/ ssh1_stdin_backlog,
|
||||
/*.throttle_all_channels =*/ ssh1_throttle_all_channels,
|
||||
/*.ldisc_option =*/ ssh1_ldisc_option,
|
||||
/*.set_ldisc_option =*/ ssh1_set_ldisc_option,
|
||||
/*.enable_x_fwd =*/ ssh1_enable_x_fwd,
|
||||
/*.set_wants_user_input =*/ ssh1_set_wants_user_input,
|
||||
/* other methods are NULL */
|
||||
};
|
||||
|
||||
static size_t ssh1channel_write(
|
||||
SshChannel *c, bool is_stderr, const void *buf, size_t len);
|
||||
static void ssh1channel_write_eof(SshChannel *c);
|
||||
static void ssh1channel_initiate_close(SshChannel *c, const char *err);
|
||||
static void ssh1channel_unthrottle(SshChannel *c, size_t bufsize);
|
||||
static Conf *ssh1channel_get_conf(SshChannel *c);
|
||||
static void ssh1channel_window_override_removed(SshChannel *c) { /* ignore */ }
|
||||
|
||||
static const SshChannelVtable ssh1channel_vtable = {
|
||||
// WINSCP
|
||||
/*.write =*/ ssh1channel_write,
|
||||
/*.write_eof =*/ ssh1channel_write_eof,
|
||||
/*.initiate_close =*/ ssh1channel_initiate_close,
|
||||
/*.unthrottle =*/ ssh1channel_unthrottle,
|
||||
/*.get_conf =*/ ssh1channel_get_conf,
|
||||
/*.window_override_removed =*/ ssh1channel_window_override_removed,
|
||||
/* everything else is NULL */
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // WINSCP
|
||||
};
|
||||
|
||||
static void ssh1_channel_try_eof(struct ssh1_channel *c);
|
||||
static void ssh1_channel_close_local(struct ssh1_channel *c,
|
||||
const char *reason);
|
||||
static void ssh1_channel_destroy(struct ssh1_channel *c);
|
||||
static void ssh1_channel_check_close(struct ssh1_channel *c);
|
||||
|
||||
static int ssh1_channelcmp(void *av, void *bv)
|
||||
{
|
||||
const struct ssh1_channel *a = (const struct ssh1_channel *) av;
|
||||
const struct ssh1_channel *b = (const struct ssh1_channel *) bv;
|
||||
if (a->localid < b->localid)
|
||||
return -1;
|
||||
if (a->localid > b->localid)
|
||||
return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssh1_channelfind(void *av, void *bv)
|
||||
{
|
||||
const unsigned *a = (const unsigned *) av;
|
||||
const struct ssh1_channel *b = (const struct ssh1_channel *) bv;
|
||||
if (*a < b->localid)
|
||||
return -1;
|
||||
if (*a > b->localid)
|
||||
return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssh1_channel_free(struct ssh1_channel *c)
|
||||
{
|
||||
if (c->chan)
|
||||
chan_free(c->chan);
|
||||
sfree(c);
|
||||
}
|
||||
|
||||
PacketProtocolLayer *ssh1_connection_new(
|
||||
Ssh *ssh, Conf *conf, ConnectionLayer **cl_out)
|
||||
{
|
||||
struct ssh1_connection_state *s = snew(struct ssh1_connection_state);
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->ppl.vt = &ssh1_connection_vtable;
|
||||
|
||||
s->conf = conf_copy(conf);
|
||||
|
||||
s->channels = newtree234(ssh1_channelcmp);
|
||||
|
||||
s->x11authtree = newtree234(x11_authcmp);
|
||||
|
||||
/* Need to get the log context for s->cl now, because we won't be
|
||||
* helpfully notified when a copy is written into s->ppl by our
|
||||
* owner. */
|
||||
s->cl.vt = &ssh1_connlayer_vtable;
|
||||
s->cl.logctx = ssh_get_logctx(ssh);
|
||||
|
||||
s->portfwdmgr = portfwdmgr_new(&s->cl);
|
||||
s->rportfwds = newtree234(ssh1_rportfwd_cmp);
|
||||
|
||||
*cl_out = &s->cl;
|
||||
return &s->ppl;
|
||||
}
|
||||
|
||||
static void ssh1_connection_free(PacketProtocolLayer *ppl)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
struct X11FakeAuth *auth;
|
||||
struct ssh1_channel *c;
|
||||
struct ssh_rportfwd *rpf;
|
||||
|
||||
conf_free(s->conf);
|
||||
|
||||
while ((c = delpos234(s->channels, 0)) != NULL)
|
||||
ssh1_channel_free(c);
|
||||
freetree234(s->channels);
|
||||
if (s->mainchan_chan)
|
||||
chan_free(s->mainchan_chan);
|
||||
|
||||
if (s->x11disp)
|
||||
x11_free_display(s->x11disp);
|
||||
while ((auth = delpos234(s->x11authtree, 0)) != NULL)
|
||||
x11_free_fake_auth(auth);
|
||||
freetree234(s->x11authtree);
|
||||
|
||||
while ((rpf = delpos234(s->rportfwds, 0)) != NULL)
|
||||
free_rportfwd(rpf);
|
||||
freetree234(s->rportfwds);
|
||||
portfwdmgr_free(s->portfwdmgr);
|
||||
|
||||
if (s->antispoof_prompt)
|
||||
free_prompts(s->antispoof_prompt);
|
||||
|
||||
delete_callbacks_for_context(get_seat_callback_set(ppl->seat), s);
|
||||
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
void ssh1_connection_set_protoflags(PacketProtocolLayer *ppl,
|
||||
int local, int remote)
|
||||
{
|
||||
pinitassert(ppl->vt == &ssh1_connection_vtable);
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
s->local_protoflags = local;
|
||||
s->remote_protoflags = remote;
|
||||
}
|
||||
|
||||
static bool ssh1_connection_filter_queue(struct ssh1_connection_state *s)
|
||||
{
|
||||
PktIn *pktin;
|
||||
ptrlen data;
|
||||
struct ssh1_channel *c;
|
||||
unsigned localid;
|
||||
bool expect_halfopen;
|
||||
|
||||
while (1) {
|
||||
if (ssh1_common_filter_queue(&s->ppl))
|
||||
return true;
|
||||
if ((pktin = pq_peek(s->ppl.in_pq)) == NULL)
|
||||
return false;
|
||||
|
||||
switch (pktin->type) {
|
||||
case SSH1_MSG_CHANNEL_DATA:
|
||||
case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
case SSH1_MSG_CHANNEL_OPEN_FAILURE:
|
||||
case SSH1_MSG_CHANNEL_CLOSE:
|
||||
case SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION:
|
||||
/*
|
||||
* Common preliminary code for all the messages from the
|
||||
* server that cite one of our channel ids: look up that
|
||||
* channel id, check it exists, and if it's for a sharing
|
||||
* downstream, pass it on.
|
||||
*/
|
||||
localid = get_uint32(pktin);
|
||||
c = find234(s->channels, &localid, ssh1_channelfind);
|
||||
|
||||
expect_halfopen = (
|
||||
pktin->type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION ||
|
||||
pktin->type == SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
|
||||
if (!c || c->halfopen != expect_halfopen) {
|
||||
ssh_remote_error(
|
||||
s->ppl.ssh, "Received %s for %s channel %u",
|
||||
ssh1_pkt_type(pktin->type),
|
||||
!c ? "nonexistent" : c->halfopen ? "half-open" : "open",
|
||||
localid);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (pktin->type) {
|
||||
case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
assert(c->halfopen);
|
||||
c->remoteid = get_uint32(pktin);
|
||||
c->halfopen = false;
|
||||
c->throttling_conn = false;
|
||||
|
||||
chan_open_confirmation(c->chan);
|
||||
|
||||
/*
|
||||
* Now that the channel is fully open, it's possible
|
||||
* in principle to immediately close it. Check whether
|
||||
* it wants us to!
|
||||
*
|
||||
* This can occur if a local socket error occurred
|
||||
* between us sending out CHANNEL_OPEN and receiving
|
||||
* OPEN_CONFIRMATION. If that happens, all we can do
|
||||
* is immediately initiate close proceedings now that
|
||||
* we know the server's id to put in the close
|
||||
* message. We'll have handled that in this code by
|
||||
* having already turned c->chan into a zombie, so its
|
||||
* want_close method (which ssh1_channel_check_close
|
||||
* will consult) will already be returning true.
|
||||
*/
|
||||
ssh1_channel_check_close(c);
|
||||
|
||||
if (c->pending_eof)
|
||||
ssh1_channel_try_eof(c); /* in case we had a pending EOF */
|
||||
break;
|
||||
|
||||
case SSH1_MSG_CHANNEL_OPEN_FAILURE:
|
||||
assert(c->halfopen);
|
||||
|
||||
chan_open_failed(c->chan, NULL);
|
||||
chan_free(c->chan);
|
||||
|
||||
del234(s->channels, c);
|
||||
ssh1_channel_free(c);
|
||||
break;
|
||||
|
||||
case SSH1_MSG_CHANNEL_DATA:
|
||||
data = get_string(pktin);
|
||||
if (!get_err(pktin)) {
|
||||
int bufsize = chan_send(
|
||||
c->chan, false, data.ptr, data.len);
|
||||
|
||||
if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {
|
||||
c->throttling_conn = true;
|
||||
ssh_throttle_conn(s->ppl.ssh, +1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SSH1_MSG_CHANNEL_CLOSE:
|
||||
if (!(c->closes & CLOSES_RCVD_CLOSE)) {
|
||||
c->closes |= CLOSES_RCVD_CLOSE;
|
||||
chan_send_eof(c->chan);
|
||||
ssh1_channel_check_close(c);
|
||||
}
|
||||
break;
|
||||
|
||||
case SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION:
|
||||
if (!(c->closes & CLOSES_RCVD_CLOSECONF)) {
|
||||
if (!(c->closes & CLOSES_SENT_CLOSE)) {
|
||||
ssh_remote_error(
|
||||
s->ppl.ssh,
|
||||
"Received CHANNEL_CLOSE_CONFIRMATION for channel"
|
||||
" %u for which we never sent CHANNEL_CLOSE\n",
|
||||
c->localid);
|
||||
return true;
|
||||
}
|
||||
|
||||
c->closes |= CLOSES_RCVD_CLOSECONF;
|
||||
ssh1_channel_check_close(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ssh1_handle_direction_specific_packet(s, pktin)) {
|
||||
pq_pop(s->ppl.in_pq);
|
||||
if (ssh1_check_termination(s))
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PktIn *ssh1_connection_pop(struct ssh1_connection_state *s)
|
||||
{
|
||||
ssh1_connection_filter_queue(s);
|
||||
return pq_pop(s->ppl.in_pq);
|
||||
}
|
||||
|
||||
static void ssh1_connection_process_queue(PacketProtocolLayer *ppl)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
PktIn *pktin;
|
||||
|
||||
if (ssh1_connection_filter_queue(s)) /* no matter why we were called */
|
||||
return;
|
||||
|
||||
crBegin(s->crState);
|
||||
|
||||
/*
|
||||
* Signal the seat that authentication is done, so that it can
|
||||
* deploy spoofing defences. If it doesn't have any, deploy our
|
||||
* own fallback one.
|
||||
*
|
||||
* We do this here rather than at the end of userauth, because we
|
||||
* might not have gone through userauth at all (if we're a
|
||||
* connection-sharing downstream).
|
||||
*/
|
||||
if (ssh1_connection_need_antispoof_prompt(s)) {
|
||||
s->antispoof_prompt = new_prompts();
|
||||
s->antispoof_prompt->to_server = true;
|
||||
s->antispoof_prompt->from_server = false;
|
||||
s->antispoof_prompt->name = dupstr("Authentication successful");
|
||||
add_prompt(
|
||||
s->antispoof_prompt,
|
||||
dupstr("Access granted. Press Return to begin session. "), false);
|
||||
s->antispoof_ret = seat_get_userpass_input(
|
||||
s->ppl.seat, s->antispoof_prompt, NULL);
|
||||
while (1) {
|
||||
while (s->antispoof_ret < 0 &&
|
||||
bufchain_size(s->ppl.user_input) > 0)
|
||||
s->antispoof_ret = seat_get_userpass_input(
|
||||
s->ppl.seat, s->antispoof_prompt, s->ppl.user_input);
|
||||
|
||||
if (s->antispoof_ret >= 0)
|
||||
break;
|
||||
|
||||
s->want_user_input = true;
|
||||
crReturnV;
|
||||
s->want_user_input = false;
|
||||
}
|
||||
free_prompts(s->antispoof_prompt);
|
||||
s->antispoof_prompt = NULL;
|
||||
}
|
||||
|
||||
portfwdmgr_config(s->portfwdmgr, s->conf);
|
||||
s->portfwdmgr_configured = true;
|
||||
|
||||
while (!s->finished_setup) {
|
||||
ssh1_connection_direction_specific_setup(s);
|
||||
crReturnV;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
/*
|
||||
* By this point, most incoming packets are already being
|
||||
* handled by filter_queue, and we need only pay attention to
|
||||
* the unusual ones.
|
||||
*/
|
||||
|
||||
if ((pktin = ssh1_connection_pop(s)) != NULL) {
|
||||
ssh_proto_error(s->ppl.ssh, "Unexpected packet received, "
|
||||
"type %d (%s)", pktin->type,
|
||||
ssh1_pkt_type(pktin->type));
|
||||
return;
|
||||
}
|
||||
crReturnV;
|
||||
}
|
||||
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static void ssh1_channel_check_close(struct ssh1_channel *c)
|
||||
{
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
PktOut *pktout;
|
||||
|
||||
if (c->halfopen) {
|
||||
/*
|
||||
* If we've sent out our own CHANNEL_OPEN but not yet seen
|
||||
* either OPEN_CONFIRMATION or OPEN_FAILURE in response, then
|
||||
* it's too early to be sending close messages of any kind.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes) ||
|
||||
chan_want_close(c->chan, (c->closes & CLOSES_SENT_CLOSE),
|
||||
(c->closes & CLOSES_RCVD_CLOSE))) &&
|
||||
!(c->closes & CLOSES_SENT_CLOSECONF)) {
|
||||
/*
|
||||
* We have both sent and received CLOSE (or the channel type
|
||||
* doesn't need us to), which means the channel is in final
|
||||
* wind-up. Send CLOSE and/or CLOSE_CONFIRMATION, whichever we
|
||||
* haven't sent yet.
|
||||
*/
|
||||
if (!(c->closes & CLOSES_SENT_CLOSE)) {
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
c->closes |= CLOSES_SENT_CLOSE;
|
||||
}
|
||||
if (c->closes & CLOSES_RCVD_CLOSE) {
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
c->closes |= CLOSES_SENT_CLOSECONF;
|
||||
}
|
||||
}
|
||||
|
||||
if (!((CLOSES_SENT_CLOSECONF | CLOSES_RCVD_CLOSECONF) & ~c->closes)) {
|
||||
/*
|
||||
* We have both sent and received CLOSE_CONFIRMATION, which
|
||||
* means we're completely done with the channel.
|
||||
*/
|
||||
ssh1_channel_destroy(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh1_channel_try_eof(struct ssh1_channel *c)
|
||||
{
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
PktOut *pktout;
|
||||
assert(c->pending_eof); /* precondition for calling us */
|
||||
if (c->halfopen)
|
||||
return; /* can't close: not even opened yet */
|
||||
|
||||
c->pending_eof = false; /* we're about to send it */
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_CLOSE);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
c->closes |= CLOSES_SENT_CLOSE;
|
||||
|
||||
ssh1_channel_check_close(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close any local socket and free any local resources associated with
|
||||
* a channel. This converts the channel into a zombie.
|
||||
*/
|
||||
static void ssh1_channel_close_local(struct ssh1_channel *c,
|
||||
const char *reason)
|
||||
{
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
char *msg = chan_log_close_msg(c->chan);
|
||||
|
||||
if (msg != NULL) {
|
||||
ppl_logevent("%s%s%s", msg, reason ? " " : "", reason ? reason : "");
|
||||
sfree(msg);
|
||||
}
|
||||
|
||||
chan_free(c->chan);
|
||||
c->chan = zombiechan_new();
|
||||
}
|
||||
|
||||
static void ssh1_check_termination_callback(void *vctx)
|
||||
{
|
||||
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx;
|
||||
ssh1_check_termination(s);
|
||||
}
|
||||
|
||||
static void ssh1_channel_destroy(struct ssh1_channel *c)
|
||||
{
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
|
||||
ssh1_channel_close_local(c, NULL);
|
||||
del234(s->channels, c);
|
||||
ssh1_channel_free(c);
|
||||
|
||||
/*
|
||||
* If that was the last channel left open, we might need to
|
||||
* terminate. But we'll be a bit cautious, by doing that in a
|
||||
* toplevel callback, just in case anything on the current call
|
||||
* stack objects to this entire PPL being freed.
|
||||
*/
|
||||
queue_toplevel_callback(ssh1_check_termination_callback, s);
|
||||
}
|
||||
|
||||
bool ssh1_check_termination(struct ssh1_connection_state *s)
|
||||
{
|
||||
/*
|
||||
* Decide whether we should terminate the SSH connection now.
|
||||
* Called after a channel goes away, or when the main session
|
||||
* returns SSH1_SMSG_EXIT_STATUS; we terminate when none of either
|
||||
* is left.
|
||||
*/
|
||||
if (s->session_terminated && count234(s->channels) == 0) {
|
||||
PktOut *pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_EXIT_CONFIRMATION);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh_user_close(s->ppl.ssh, "Session finished");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up most of a new ssh1_channel. Leaves chan untouched (since it
|
||||
* will sometimes have been filled in before calling this).
|
||||
*/
|
||||
void ssh1_channel_init(struct ssh1_channel *c)
|
||||
{
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
c->closes = 0;
|
||||
c->pending_eof = false;
|
||||
c->throttling_conn = false;
|
||||
c->sc.vt = &ssh1channel_vtable;
|
||||
c->sc.cl = &s->cl;
|
||||
c->localid = alloc_channel_id(s->channels, struct ssh1_channel);
|
||||
add234(s->channels, c);
|
||||
}
|
||||
|
||||
static Conf *ssh1channel_get_conf(SshChannel *sc)
|
||||
{
|
||||
struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
return s->conf;
|
||||
}
|
||||
|
||||
static void ssh1channel_write_eof(SshChannel *sc)
|
||||
{
|
||||
struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
|
||||
|
||||
if (c->closes & CLOSES_SENT_CLOSE)
|
||||
return;
|
||||
|
||||
c->pending_eof = true;
|
||||
ssh1_channel_try_eof(c);
|
||||
}
|
||||
|
||||
static void ssh1channel_initiate_close(SshChannel *sc, const char *err)
|
||||
{
|
||||
struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
|
||||
char *reason;
|
||||
|
||||
reason = err ? dupprintf("due to local error: %s", err) : NULL;
|
||||
ssh1_channel_close_local(c, reason);
|
||||
sfree(reason);
|
||||
c->pending_eof = false; /* this will confuse a zombie channel */
|
||||
|
||||
ssh1_channel_check_close(c);
|
||||
}
|
||||
|
||||
static void ssh1channel_unthrottle(SshChannel *sc, size_t bufsize)
|
||||
{
|
||||
struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
|
||||
if (c->throttling_conn && bufsize <= SSH1_BUFFER_LIMIT) {
|
||||
c->throttling_conn = false;
|
||||
ssh_throttle_conn(s->ppl.ssh, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ssh1channel_write(
|
||||
SshChannel *sc, bool is_stderr, const void *buf, size_t len)
|
||||
{
|
||||
struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
|
||||
pinitassert(!(c->closes & CLOSES_SENT_CLOSE));
|
||||
|
||||
PktOut *pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_CHANNEL_DATA);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_string(pktout, buf, len);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
/*
|
||||
* In SSH-1 we can return 0 here - implying that channels are
|
||||
* never individually throttled - because the only circumstance
|
||||
* that can cause throttling will be the whole SSH connection
|
||||
* backing up, in which case _everything_ will be throttled as a
|
||||
* whole.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct X11FakeAuth *ssh1_add_x11_display(
|
||||
ConnectionLayer *cl, int authtype, struct X11Display *disp)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
struct X11FakeAuth *auth = x11_invent_fake_auth(s->x11authtree, authtype);
|
||||
auth->disp = disp;
|
||||
return auth;
|
||||
}
|
||||
|
||||
static SshChannel *ssh1_lportfwd_open(
|
||||
ConnectionLayer *cl, const char *hostname, int port,
|
||||
const char *description, const SocketPeerInfo *pi, Channel *chan)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
struct ssh1_channel *c = snew(struct ssh1_channel);
|
||||
PktOut *pktout;
|
||||
|
||||
c->connlayer = s;
|
||||
ssh1_channel_init(c);
|
||||
c->halfopen = true;
|
||||
c->chan = chan;
|
||||
|
||||
ppl_logevent("Opening connection to %s:%d for %s",
|
||||
hostname, port, description);
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_PORT_OPEN);
|
||||
put_uint32(pktout, c->localid);
|
||||
put_stringz(pktout, hostname);
|
||||
put_uint32(pktout, port);
|
||||
/* originator string would go here, but we didn't specify
|
||||
* SSH_PROTOFLAG_HOST_IN_FWD_OPEN */
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
return &c->sc;
|
||||
}
|
||||
|
||||
static void ssh1_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf)
|
||||
{
|
||||
/*
|
||||
* We cannot cancel listening ports on the server side in SSH-1!
|
||||
* There's no message to support it.
|
||||
*/
|
||||
}
|
||||
|
||||
static bool ssh1_agent_forwarding_permitted(ConnectionLayer *cl)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
return conf_get_bool(s->conf, CONF_agentfwd) && agent_exists();
|
||||
}
|
||||
|
||||
static void ssh1_connection_special_cmd(PacketProtocolLayer *ppl,
|
||||
SessionSpecialCode code, int arg)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
PktOut *pktout;
|
||||
|
||||
if (code == SS_PING || code == SS_NOP) {
|
||||
if (!(s->ppl.remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) {
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_IGNORE);
|
||||
put_stringz(pktout, "");
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
}
|
||||
} else if (s->mainchan) {
|
||||
mainchan_special_cmd(s->mainchan, code, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh1_terminal_size(ConnectionLayer *cl, int width, int height)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
|
||||
s->term_width = width;
|
||||
s->term_height = height;
|
||||
if (s->mainchan)
|
||||
mainchan_terminal_size(s->mainchan, width, height);
|
||||
}
|
||||
|
||||
static void ssh1_stdout_unthrottle(ConnectionLayer *cl, size_t bufsize)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
|
||||
if (s->stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) {
|
||||
s->stdout_throttling = false;
|
||||
ssh_throttle_conn(s->ppl.ssh, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ssh1_stdin_backlog(ConnectionLayer *cl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssh1_throttle_all_channels(ConnectionLayer *cl, bool throttled)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
struct ssh1_channel *c;
|
||||
int i;
|
||||
|
||||
for (i = 0; NULL != (c = index234(s->channels, i)); i++)
|
||||
chan_set_input_wanted(c->chan, !throttled);
|
||||
}
|
||||
|
||||
static bool ssh1_ldisc_option(ConnectionLayer *cl, int option)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
|
||||
return s->ldisc_opts[option];
|
||||
}
|
||||
|
||||
static void ssh1_set_ldisc_option(ConnectionLayer *cl, int option, bool value)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
|
||||
s->ldisc_opts[option] = value;
|
||||
}
|
||||
|
||||
static void ssh1_enable_x_fwd(ConnectionLayer *cl)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
|
||||
s->X11_fwd_enabled = true;
|
||||
}
|
||||
|
||||
static void ssh1_set_wants_user_input(ConnectionLayer *cl, bool wanted)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
|
||||
s->want_user_input = wanted;
|
||||
s->finished_setup = true;
|
||||
}
|
||||
|
||||
static bool ssh1_connection_want_user_input(PacketProtocolLayer *ppl)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
|
||||
return s->want_user_input;
|
||||
}
|
||||
|
||||
static void ssh1_connection_got_user_input(PacketProtocolLayer *ppl)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
|
||||
while (s->mainchan && bufchain_size(s->ppl.user_input) > 0) {
|
||||
/*
|
||||
* Add user input to the main channel's buffer.
|
||||
*/
|
||||
ptrlen data = bufchain_prefix(s->ppl.user_input);
|
||||
if (data.len > 512)
|
||||
data.len = 512;
|
||||
sshfwd_write(&s->mainchan_sc, data.ptr, data.len);
|
||||
bufchain_consume(s->ppl.user_input, data.len);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh1_connection_reconfigure(PacketProtocolLayer *ppl, Conf *conf)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
|
||||
conf_free(s->conf);
|
||||
s->conf = conf_copy(conf);
|
||||
|
||||
if (s->portfwdmgr_configured)
|
||||
portfwdmgr_config(s->portfwdmgr, s->conf);
|
||||
}
|
||||
|
||||
#include <puttyexp.h>
|
||||
|
||||
static unsigned int ssh1_connection_winscp_query(PacketProtocolLayer *ppl, int query)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(ppl, struct ssh1_connection_state, ppl);
|
||||
|
||||
if (query == WINSCP_QUERY_TIMER)
|
||||
{
|
||||
return 0; // dummy
|
||||
}
|
||||
else if (query == WINSCP_QUERY_REMMAXPKT)
|
||||
{
|
||||
return 0; // dummy
|
||||
}
|
||||
else if (query == WINSCP_QUERY_MAIN_CHANNEL)
|
||||
{
|
||||
return s->finished_setup;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
123
source/putty/ssh1connection.h
vendored
123
source/putty/ssh1connection.h
vendored
@@ -1,123 +0,0 @@
|
||||
struct ssh1_channel;
|
||||
|
||||
struct outstanding_succfail;
|
||||
|
||||
struct ssh1_connection_state {
|
||||
int crState;
|
||||
|
||||
Conf *conf;
|
||||
int local_protoflags, remote_protoflags;
|
||||
|
||||
tree234 *channels; /* indexed by local id */
|
||||
|
||||
/* In SSH-1, the main session doesn't take the form of a 'channel'
|
||||
* according to the wire protocol. But we want to use the same API
|
||||
* for it, so we define an SshChannel here - but one that uses a
|
||||
* separate vtable from the usual one, so it doesn't map to a
|
||||
* struct ssh1_channel as all the others do. */
|
||||
SshChannel mainchan_sc;
|
||||
Channel *mainchan_chan; /* the other end of mainchan_sc */
|
||||
mainchan *mainchan; /* and its subtype */
|
||||
|
||||
bool got_pty;
|
||||
bool ldisc_opts[LD_N_OPTIONS];
|
||||
bool stdout_throttling;
|
||||
bool want_user_input;
|
||||
bool session_terminated;
|
||||
int term_width, term_height, term_width_orig, term_height_orig;
|
||||
|
||||
bool X11_fwd_enabled;
|
||||
struct X11Display *x11disp;
|
||||
struct X11FakeAuth *x11auth;
|
||||
tree234 *x11authtree;
|
||||
|
||||
tree234 *rportfwds;
|
||||
PortFwdManager *portfwdmgr;
|
||||
bool portfwdmgr_configured;
|
||||
|
||||
bool finished_setup;
|
||||
|
||||
/*
|
||||
* These store the list of requests that we're waiting for
|
||||
* SSH_SMSG_{SUCCESS,FAILURE} replies to. (Those messages don't
|
||||
* come with any indication of what they're in response to, so we
|
||||
* have to keep track of the queue ourselves.)
|
||||
*/
|
||||
struct outstanding_succfail *succfail_head, *succfail_tail;
|
||||
|
||||
bool compressing; /* used in server mode only */
|
||||
bool sent_exit_status; /* also for server mode */
|
||||
|
||||
prompts_t *antispoof_prompt;
|
||||
int antispoof_ret;
|
||||
|
||||
const SshServerConfig *ssc;
|
||||
|
||||
ConnectionLayer cl;
|
||||
PacketProtocolLayer ppl;
|
||||
};
|
||||
|
||||
struct ssh1_channel {
|
||||
struct ssh1_connection_state *connlayer;
|
||||
|
||||
unsigned remoteid, localid;
|
||||
int type;
|
||||
/* True if we opened this channel but server hasn't confirmed. */
|
||||
bool halfopen;
|
||||
|
||||
/* Bitmap of whether we've sent/received CHANNEL_CLOSE and
|
||||
* CHANNEL_CLOSE_CONFIRMATION. */
|
||||
#define CLOSES_SENT_CLOSE 1
|
||||
#define CLOSES_SENT_CLOSECONF 2
|
||||
#define CLOSES_RCVD_CLOSE 4
|
||||
#define CLOSES_RCVD_CLOSECONF 8
|
||||
int closes;
|
||||
|
||||
/*
|
||||
* This flag indicates that an EOF is pending on the outgoing side
|
||||
* of the channel: that is, wherever we're getting the data for
|
||||
* this channel has sent us some data followed by EOF. We can't
|
||||
* actually send the EOF until we've finished sending the data, so
|
||||
* we set this flag instead to remind us to do so once our buffer
|
||||
* is clear.
|
||||
*/
|
||||
bool pending_eof;
|
||||
|
||||
/*
|
||||
* True if this channel is causing the underlying connection to be
|
||||
* throttled.
|
||||
*/
|
||||
bool throttling_conn;
|
||||
|
||||
/*
|
||||
* True if we currently have backed-up data on the direction of
|
||||
* this channel pointing out of the SSH connection, and therefore
|
||||
* would prefer the 'Channel' implementation not to read further
|
||||
* local input if possible.
|
||||
*/
|
||||
bool throttled_by_backlog;
|
||||
|
||||
Channel *chan; /* handle the client side of this channel, if not */
|
||||
SshChannel sc; /* entry point for chan to talk back to */
|
||||
};
|
||||
|
||||
SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan);
|
||||
void ssh1_channel_init(struct ssh1_channel *c);
|
||||
void ssh1_channel_free(struct ssh1_channel *c);
|
||||
struct ssh_rportfwd *ssh1_rportfwd_alloc(
|
||||
ConnectionLayer *cl,
|
||||
const char *shost, int sport, const char *dhost, int dport,
|
||||
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
||||
ssh_sharing_connstate *share_ctx);
|
||||
SshChannel *ssh1_serverside_x11_open(
|
||||
ConnectionLayer *cl, Channel *chan, const SocketPeerInfo *pi);
|
||||
SshChannel *ssh1_serverside_agent_open(ConnectionLayer *cl, Channel *chan);
|
||||
|
||||
void ssh1_connection_direction_specific_setup(
|
||||
struct ssh1_connection_state *s);
|
||||
bool ssh1_handle_direction_specific_packet(
|
||||
struct ssh1_connection_state *s, PktIn *pktin);
|
||||
|
||||
bool ssh1_check_termination(struct ssh1_connection_state *s);
|
||||
|
||||
bool ssh1_connection_need_antispoof_prompt(struct ssh1_connection_state *s);
|
||||
1284
source/putty/ssh1login.c
vendored
1284
source/putty/ssh1login.c
vendored
File diff suppressed because it is too large
Load Diff
1
source/putty/sshbpp.h
vendored
1
source/putty/sshbpp.h
vendored
@@ -177,7 +177,6 @@ const char *ssh_verstring_get_local(BinaryPacketProtocol *);
|
||||
int ssh_verstring_get_bugs(BinaryPacketProtocol *);
|
||||
|
||||
#ifdef MPEXT
|
||||
const ssh_cipher * ssh1_bpp_get_cipher(BinaryPacketProtocol *bpp);
|
||||
const ssh_cipher * ssh2_bpp_get_cscipher(BinaryPacketProtocol *bpp);
|
||||
const ssh_cipher * ssh2_bpp_get_sccipher(BinaryPacketProtocol *bpp);
|
||||
const struct ssh_compressor * ssh2_bpp_get_cscomp(BinaryPacketProtocol *bpp);
|
||||
|
||||
109
source/putty/sshcrc.c
vendored
109
source/putty/sshcrc.c
vendored
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* CRC32 implementation, as used in SSH-1.
|
||||
*
|
||||
* This particular form of the CRC uses the polynomial
|
||||
* P(x) = x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+1
|
||||
* and represents polynomials in bit-reversed form, so that the x^0
|
||||
* coefficient (constant term) appears in the bit with place value
|
||||
* 2^31, and the x^31 coefficient in the bit with place value 2^0. In
|
||||
* this representation, (x^32 mod P) = 0xEDB88320, so multiplying the
|
||||
* current state by x is done by shifting right by one bit, and XORing
|
||||
* that constant into the result if the bit shifted out was 1.
|
||||
*
|
||||
* There's a bewildering array of subtly different variants of CRC out
|
||||
* there, using different polynomials, both bit orders, and varying
|
||||
* the start and end conditions. There are catalogue websites such as
|
||||
* http://reveng.sourceforge.net/crc-catalogue/ , which generally seem
|
||||
* to have the convention of indexing CRCs by their 'check value',
|
||||
* defined as whatever you get if you hash the 9-byte test string
|
||||
* "123456789".
|
||||
*
|
||||
* The crc32_rfc1662() function below, which starts off the CRC state
|
||||
* at 0xFFFFFFFF and complements it after feeding all the data, gives
|
||||
* the check value 0xCBF43926, and matches the hash function that the
|
||||
* above catalogue refers to as "CRC-32/ISO-HDLC"; among other things,
|
||||
* it's also the "FCS-32" checksum described in RFC 1662 section C.3
|
||||
* (hence the name I've given it here).
|
||||
*
|
||||
* The crc32_ssh1() function implements the variant form used by
|
||||
* SSH-1, which uses the same update function, but starts the state at
|
||||
* zero and doesn't complement it at the end of the computation. The
|
||||
* check value for that version is 0x2DFD2D88, which that CRC
|
||||
* catalogue doesn't list at all.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
/*
|
||||
* Multiply a CRC value by x^4. This implementation strategy avoids
|
||||
* using a lookup table (which would be a side-channel hazard, since
|
||||
* SSH-1 applies this CRC to decrypted session data).
|
||||
*
|
||||
* The basic idea is that you'd like to "multiply" the shifted-out 4
|
||||
* bits by the CRC polynomial value 0xEDB88320, or rather by that
|
||||
* value shifted right 3 bits (since you want the _last_ bit shifted
|
||||
* out, i.e. the one originally at the 2^3 position, to generate
|
||||
* 0xEDB88320 itself). But the scare-quoted "multiply" would have to
|
||||
* be a multiplication of polynomials over GF(2), which differs from
|
||||
* integer multiplication in that you don't have any carries. In other
|
||||
* words, you make a copy of one input shifted left by the index of
|
||||
* each set bit in the other, so that adding them all together would
|
||||
* give you the ordinary integer product, and then you XOR them
|
||||
* together instead.
|
||||
*
|
||||
* With a 4-bit multiplier, the two kinds of multiplication coincide
|
||||
* provided the multiplicand has no two set bits at positions
|
||||
* differing by less than 4, because then no two copies of the
|
||||
* multiplier can overlap to generate a carry. So I break up the
|
||||
* intended multiplicand K = 0xEDB88320 >> 3 into three sub-constants
|
||||
* a,b,c with that property, such that a^b^c = K. Then I can multiply
|
||||
* m by each of them separately, and XOR together the results.
|
||||
*/
|
||||
static inline uint32_t crc32_shift_4(uint32_t v)
|
||||
{
|
||||
const uint32_t a = 0x11111044, b = 0x08840020, c = 0x04220000;
|
||||
uint32_t m = v & 0xF;
|
||||
return (v >> 4) ^ (a*m) ^ (b*m) ^ (c*m);
|
||||
}
|
||||
|
||||
/*
|
||||
* The 8-bit shift you need every time you absorb an input byte,
|
||||
* implemented simply by iterating the 4-bit shift twice.
|
||||
*/
|
||||
static inline uint32_t crc32_shift_8(uint32_t v)
|
||||
{
|
||||
return crc32_shift_4(crc32_shift_4(v));
|
||||
}
|
||||
|
||||
/*
|
||||
* Update an existing hash value with extra bytes of data.
|
||||
*/
|
||||
uint32_t crc32_update(uint32_t crc, ptrlen data)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)data.ptr;
|
||||
size_t len; // WINSCP
|
||||
for (len = data.len; len-- > 0 ;)
|
||||
crc = crc32_shift_8(crc ^ *p++);
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The SSH-1 variant of CRC-32.
|
||||
*/
|
||||
uint32_t crc32_ssh1(ptrlen data)
|
||||
{
|
||||
return crc32_update(0, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* The official version of CRC-32. Nothing in PuTTY proper uses this,
|
||||
* but it's useful to expose it to testcrypt so that we can implement
|
||||
* standard test vectors.
|
||||
*/
|
||||
uint32_t crc32_rfc1662(ptrlen data)
|
||||
{
|
||||
return crc32_update(0xFFFFFFFF, data) ^ 0xFFFFFFFF;
|
||||
}
|
||||
171
source/putty/sshcrcda.c
vendored
171
source/putty/sshcrcda.c
vendored
@@ -1,171 +0,0 @@
|
||||
/* $OpenBSD: deattack.c,v 1.14 2001/06/23 15:12:18 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - source code
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
*
|
||||
* All rights reserved. Redistribution and use in source and binary
|
||||
* forms, with or without modification, are permitted provided that
|
||||
* this copyright notice is retained.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com>
|
||||
*
|
||||
* Modified for use in PuTTY by Simon Tatham
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "misc.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* SSH Constants */
|
||||
#define SSH_MAXBLOCKS (32 * 1024)
|
||||
#define SSH_BLOCKSIZE (8)
|
||||
|
||||
/* Hashing constants */
|
||||
#define HASH_MINSIZE (8 * 1024)
|
||||
#define HASH_ENTRYSIZE (sizeof(uint16_t))
|
||||
#define HASH_FACTOR(x) ((x)*3/2)
|
||||
#define HASH_UNUSEDCHAR (0xff)
|
||||
#define HASH_UNUSED (0xffff)
|
||||
#define HASH_IV (0xfffe)
|
||||
|
||||
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
|
||||
|
||||
/* Hash function (Input keys are cipher results) */
|
||||
#define HASH(x) GET_32BIT_MSB_FIRST(x)
|
||||
|
||||
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
|
||||
|
||||
static const uint8_t ONE[4] = { 1, 0, 0, 0 };
|
||||
static const uint8_t ZERO[4] = { 0, 0, 0, 0 };
|
||||
|
||||
struct crcda_ctx {
|
||||
uint16_t *h;
|
||||
uint32_t n;
|
||||
};
|
||||
|
||||
struct crcda_ctx *crcda_make_context(void)
|
||||
{
|
||||
struct crcda_ctx *ret = snew(struct crcda_ctx);
|
||||
ret->h = NULL;
|
||||
ret->n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void crcda_free_context(struct crcda_ctx *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
sfree(ctx->h);
|
||||
ctx->h = NULL;
|
||||
sfree(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void crc_update(uint32_t *a, const void *b)
|
||||
{
|
||||
*a = crc32_update(*a, make_ptrlen(b, 4));
|
||||
}
|
||||
|
||||
/* detect if a block is used in a particular pattern */
|
||||
static bool check_crc(const uint8_t *S, const uint8_t *buf,
|
||||
uint32_t len, const uint8_t *IV)
|
||||
{
|
||||
uint32_t crc;
|
||||
const uint8_t *c;
|
||||
|
||||
crc = 0;
|
||||
if (IV && !CMP(S, IV)) {
|
||||
crc_update(&crc, ONE);
|
||||
crc_update(&crc, ZERO);
|
||||
}
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (!CMP(S, c)) {
|
||||
crc_update(&crc, ONE);
|
||||
crc_update(&crc, ZERO);
|
||||
} else {
|
||||
crc_update(&crc, ZERO);
|
||||
crc_update(&crc, ZERO);
|
||||
}
|
||||
}
|
||||
return (crc == 0);
|
||||
}
|
||||
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
bool detect_attack(struct crcda_ctx *ctx,
|
||||
const unsigned char *buf, uint32_t len,
|
||||
const unsigned char *IV)
|
||||
{
|
||||
register uint32_t i, j;
|
||||
uint32_t l;
|
||||
register const uint8_t *c;
|
||||
const uint8_t *d;
|
||||
|
||||
assert(!(len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0));
|
||||
for (l = ctx->n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
;
|
||||
|
||||
if (ctx->h == NULL) {
|
||||
ctx->n = l;
|
||||
ctx->h = snewn(ctx->n, uint16_t);
|
||||
} else {
|
||||
if (l > ctx->n) {
|
||||
ctx->n = l;
|
||||
ctx->h = sresize(ctx->h, ctx->n, uint16_t);
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= HASH_MINBLOCKS) {
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (IV && (!CMP(c, IV))) {
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return true; /* attack detected */
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (d = buf; d < c; d += SSH_BLOCKSIZE) {
|
||||
if (!CMP(c, d)) {
|
||||
if ((check_crc(c, buf, len, IV)))
|
||||
return true; /* attack detected */
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; /* ok */
|
||||
}
|
||||
memset(ctx->h, HASH_UNUSEDCHAR, ctx->n * HASH_ENTRYSIZE);
|
||||
|
||||
if (IV)
|
||||
ctx->h[HASH(IV) & (ctx->n - 1)] = HASH_IV;
|
||||
|
||||
for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
|
||||
for (i = HASH(c) & (ctx->n - 1); ctx->h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (ctx->n - 1)) {
|
||||
if (ctx->h[i] == HASH_IV) {
|
||||
assert(IV); /* or we wouldn't have stored HASH_IV above */
|
||||
if (!CMP(c, IV)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return true; /* attack detected */
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else if (!CMP(c, buf + ctx->h[i] * SSH_BLOCKSIZE)) {
|
||||
if (check_crc(c, buf, len, IV))
|
||||
return true; /* attack detected */
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->h[i] = j;
|
||||
}
|
||||
return false; /* ok */
|
||||
}
|
||||
@@ -170,7 +170,7 @@
|
||||
#define SFTP_STATUS_FILE_CORRUPT 242
|
||||
#define KEY_TYPE_UNKNOWN2 243
|
||||
#define KEY_TYPE_UNSUPPORTED2 244
|
||||
#define KEY_TYPE_DIFFERENT_SSH 245
|
||||
#define KEY_TYPE_SSH1 245
|
||||
#define SFTP_OVERWRITE_FILE_ERROR2 246
|
||||
#define SFTP_OVERWRITE_DELETE_BUTTON 247
|
||||
#define SPACE_AVAILABLE_ERROR 248
|
||||
|
||||
@@ -139,7 +139,7 @@ BEGIN
|
||||
SFTP_STATUS_FILE_CORRUPT, "The file is corrupt; an filesystem integrity check should be run."
|
||||
KEY_TYPE_UNKNOWN2, "File '%s' does not contain private key in known format."
|
||||
KEY_TYPE_UNSUPPORTED2, "**Private key file '%s' contains key in %s format. WinSCP supports only PuTTY format.**"
|
||||
KEY_TYPE_DIFFERENT_SSH, "Private key file '%s' contains key in %s format. It does not follow your preferred SSH protocol version."
|
||||
KEY_TYPE_SSH1, "Private key file '%s' contains key in deprecated SSH-1 format."
|
||||
SFTP_OVERWRITE_FILE_ERROR2, "Cannot overwrite remote file '%s'.$$\n \nPress 'Delete' to delete the file and create new one instead of overwriting it.$$"
|
||||
SFTP_OVERWRITE_DELETE_BUTTON, "&Delete"
|
||||
SPACE_AVAILABLE_ERROR, "Error checking space available for path '%s'."
|
||||
|
||||
@@ -229,8 +229,7 @@ void __fastcall OpenSessionInPutty(const UnicodeString PuttyPath,
|
||||
{
|
||||
AddToList(PuttyParams, L"-C", L" ");
|
||||
}
|
||||
AddToList(PuttyParams,
|
||||
((SessionData->SshProt == ssh1only || SessionData->SshProt == ssh1deprecated) ? L"-1" : L"-2"), L" ");
|
||||
AddToList(PuttyParams, L"-2", L" ");
|
||||
if (!SessionData->LogicalHostName.IsEmpty())
|
||||
{
|
||||
AddToList(PuttyParams, FORMAT(L"-loghost \"%s\"", (SessionData->LogicalHostName)), L" ");
|
||||
|
||||
@@ -1895,7 +1895,7 @@ bool __fastcall TTerminalManager::UploadPublicKey(
|
||||
const UnicodeString AuthorizedKeysFile = L"authorized_keys";
|
||||
UnicodeString AuthorizedKeysFilePath = FORMAT(L"%s/%s", (SshFolder, AuthorizedKeysFile));
|
||||
|
||||
VerifyAndConvertKey(FileName, ssh2only, false);
|
||||
VerifyAndConvertKey(FileName, false);
|
||||
|
||||
UnicodeString Comment;
|
||||
UnicodeString Line = GetPublicKeyLine(FileName, Comment);
|
||||
|
||||
@@ -1285,8 +1285,7 @@ static void __fastcall ConvertKey(UnicodeString & FileName, TKeyType Type)
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
static void __fastcall DoVerifyKey(
|
||||
UnicodeString & FileName, TSshProt SshProt, bool Convert, bool CanIgnore)
|
||||
static void __fastcall DoVerifyKey(UnicodeString & FileName, bool Convert, bool CanIgnore)
|
||||
{
|
||||
if (!FileName.Trim().IsEmpty())
|
||||
{
|
||||
@@ -1330,14 +1329,7 @@ static void __fastcall DoVerifyKey(
|
||||
break;
|
||||
|
||||
case ktSSH1:
|
||||
case ktSSH2:
|
||||
if ((Type == ktSSH1) != (SshProt == ssh1only))
|
||||
{
|
||||
Message =
|
||||
MainInstructions(
|
||||
FMTLOAD(KEY_TYPE_DIFFERENT_SSH,
|
||||
(FileName, (Type == ktSSH1 ? L"SSH-1" : L"PuTTY SSH-2"))));
|
||||
}
|
||||
Message = MainInstructions(LoadStr(KEY_TYPE_SSH1));
|
||||
break;
|
||||
|
||||
case ktSSH1Public:
|
||||
@@ -1375,14 +1367,15 @@ static void __fastcall DoVerifyKey(
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall VerifyAndConvertKey(UnicodeString & FileName, TSshProt SshProt, bool CanIgnore)
|
||||
void __fastcall VerifyAndConvertKey(UnicodeString & FileName, bool CanIgnore)
|
||||
{
|
||||
DoVerifyKey(FileName, SshProt, true, CanIgnore);
|
||||
DoVerifyKey(FileName, true, CanIgnore);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall VerifyKey(UnicodeString FileName, TSshProt SshProt)
|
||||
void __fastcall VerifyKey(const UnicodeString & FileName)
|
||||
{
|
||||
DoVerifyKey(FileName, SshProt, false, true);
|
||||
UnicodeString AFileName(FileName);
|
||||
DoVerifyKey(AFileName, false, true);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall VerifyCertificate(const UnicodeString & FileName)
|
||||
|
||||
@@ -71,8 +71,8 @@ void __fastcall CopyToClipboard(TStrings * Strings);
|
||||
void __fastcall ShutDownWindows();
|
||||
void __fastcall SuspendWindows();
|
||||
void __fastcall EditSelectBaseName(HWND Edit);
|
||||
void __fastcall VerifyAndConvertKey(UnicodeString & FileName, TSshProt SshProt, bool CanIgnore);
|
||||
void __fastcall VerifyKey(UnicodeString FileName, TSshProt SshProt);
|
||||
void __fastcall VerifyAndConvertKey(UnicodeString & FileName, bool CanIgnore);
|
||||
void __fastcall VerifyKey(const UnicodeString & FileName);
|
||||
void __fastcall VerifyCertificate(const UnicodeString & FileName);
|
||||
TStrings * __fastcall GetUnwrappedMemoLines(TMemo * Memo);
|
||||
bool __fastcall DetectSystemExternalEditor(
|
||||
|
||||
Reference in New Issue
Block a user