Skip to content

Commit

Permalink
Bug 386: Automatic upload of keys pairs + Public key can be displayed…
Browse files Browse the repository at this point in the history
… in Advanced Site Settings dialog

https://winscp.net/tracker/386

Source commit: 78d8baba92c09728ef3bccc9b49f1590a76d4ca5
  • Loading branch information
martinprikryl committed May 11, 2018
1 parent bc9622a commit 64f634d
Show file tree
Hide file tree
Showing 28 changed files with 466 additions and 46 deletions.
1 change: 1 addition & 0 deletions source/core/FileSystems.h
Expand Up @@ -81,6 +81,7 @@ class TCustomFileSystem
const TRemoteFile * File, UnicodeString Command, int Params, TCaptureOutputEvent OutputEvent) = 0;
virtual void __fastcall DoStartup() = 0;
virtual void __fastcall HomeDirectory() = 0;
virtual UnicodeString __fastcall GetHomeDirectory() { throw Exception(L"Not implemented"); };
virtual bool __fastcall IsCapable(int Capability) const = 0;
virtual void __fastcall LookupUsersGroups() = 0;
virtual void __fastcall ReadCurrentDirectory() = 0;
Expand Down
53 changes: 53 additions & 0 deletions source/core/PuttyIntf.cpp
Expand Up @@ -10,6 +10,7 @@
#include "CoreMain.h"
#include "TextsCore.h"
#include <StrUtils.hpp>
#include <Soap.EncdDecd.hpp>
//---------------------------------------------------------------------------
char sshver[50];
extern const char commitid[] = "";
Expand Down Expand Up @@ -686,6 +687,49 @@ void FreeKey(TPrivateKey * PrivateKey)
sfree(Ssh2Key);
}
//---------------------------------------------------------------------------
RawByteString LoadPublicKey(const UnicodeString & FileName, UnicodeString & Algorithm, UnicodeString & Comment)
{
RawByteString Result;
UTF8String UtfFileName = UTF8String(FileName);
Filename * KeyFile = filename_from_str(UtfFileName.c_str());
try
{
char * AlgorithmStr = NULL;
int PublicKeyLen = 0;
char * CommentStr = NULL;
const char * ErrorStr = NULL;
unsigned char * PublicKeyPtr =
ssh2_userkey_loadpub(KeyFile, &AlgorithmStr, &PublicKeyLen, &CommentStr, &ErrorStr);
if (PublicKeyPtr == NULL)
{
UnicodeString Error = UnicodeString(AnsiString(ErrorStr));
throw Exception(Error);
}
Algorithm = UnicodeString(AnsiString(AlgorithmStr));
sfree(AlgorithmStr);
Comment = UnicodeString(AnsiString(CommentStr));
sfree(CommentStr);
Result = RawByteString(reinterpret_cast<char *>(PublicKeyPtr), PublicKeyLen);
free(PublicKeyPtr);
}
__finally
{
filename_free(KeyFile);
}
return Result;
}
//---------------------------------------------------------------------------
UnicodeString GetPublicKeyLine(const UnicodeString & FileName, UnicodeString & Comment)
{
UnicodeString Algorithm;
RawByteString PublicKey = LoadPublicKey(FileName, Algorithm, Comment);
UnicodeString PublicKeyBase64 = EncodeBase64(PublicKey.c_str(), PublicKey.Length());
PublicKeyBase64 = ReplaceStr(PublicKeyBase64, L"\r", L"");
PublicKeyBase64 = ReplaceStr(PublicKeyBase64, L"\n", L"");
UnicodeString Result = FORMAT(L"%s %s %s", (Algorithm, PublicKeyBase64, Comment));
return Result;
}
//---------------------------------------------------------------------------
bool __fastcall HasGSSAPI(UnicodeString CustomPath)
{
static int has = -1;
Expand Down Expand Up @@ -879,4 +923,13 @@ UnicodeString __fastcall GetKeyTypeHuman(const UnicodeString & KeyType)
return Result;
}
//---------------------------------------------------------------------------
bool IsOpenSSH(const UnicodeString & SshImplementation)
{
return
// e.g. "OpenSSH_5.3"
(SshImplementation.Pos(L"OpenSSH") == 1) ||
// Sun SSH is based on OpenSSH (suffers the same bugs)
(SshImplementation.Pos(L"Sun_SSH") == 1);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
3 changes: 3 additions & 0 deletions source/core/PuttyTools.h
Expand Up @@ -17,6 +17,7 @@ void ChangeKeyComment(TPrivateKey * PrivateKey, const UnicodeString & Comment);
void SaveKey(TKeyType KeyType, const UnicodeString & FileName,
const UnicodeString & Passphrase, TPrivateKey * PrivateKey);
void FreeKey(TPrivateKey * PrivateKey);
UnicodeString GetPublicKeyLine(const UnicodeString & FileName, UnicodeString & Comment);
extern const UnicodeString PuttyKeyExt;
//---------------------------------------------------------------------------
bool __fastcall HasGSSAPI(UnicodeString CustomPath);
Expand All @@ -37,4 +38,6 @@ UnicodeString __fastcall ParseOpenSshPubLine(const UnicodeString & Line, const s
//---------------------------------------------------------------------------
UnicodeString __fastcall GetKeyTypeHuman(const UnicodeString & KeyType);
//---------------------------------------------------------------------------
bool IsOpenSSH(const UnicodeString & SshImplementation);
//---------------------------------------------------------------------------
#endif
5 changes: 1 addition & 4 deletions source/core/SecureShell.cpp
Expand Up @@ -455,10 +455,7 @@ void __fastcall TSecureShell::Open()
FOpened = true;

UnicodeString SshImplementation = GetSessionInfo().SshImplementation;
if (// e.g. "OpenSSH_5.3"
(SshImplementation.Pos(L"OpenSSH") == 1) ||
// Sun SSH is based on OpenSSH (suffers the same bugs)
(SshImplementation.Pos(L"Sun_SSH") == 1))
if (IsOpenSSH(SshImplementation))
{
FSshImplementation = sshiOpenSSH;
}
Expand Down
2 changes: 1 addition & 1 deletion source/core/SessionData.cpp
Expand Up @@ -509,7 +509,7 @@ bool __fastcall TSessionData::IsSame(const TSessionData * Default, bool Advanced
return IsSame(Default, AdvancedOnly, NULL);
}
//---------------------------------------------------------------------
static TFSProtocol NormalizeFSProtocol(TFSProtocol FSProtocol)
TFSProtocol NormalizeFSProtocol(TFSProtocol FSProtocol)
{
if ((FSProtocol == fsSCPonly) || (FSProtocol == fsSFTPonly))
{
Expand Down
1 change: 1 addition & 0 deletions source/core/SessionData.h
Expand Up @@ -711,5 +711,6 @@ bool __fastcall IsSshProtocol(TFSProtocol FSProtocol);
int __fastcall DefaultPort(TFSProtocol FSProtocol, TFtps Ftps);
bool __fastcall IsIPv6Literal(const UnicodeString & HostName);
UnicodeString __fastcall EscapeIPv6Literal(const UnicodeString & IP);
TFSProtocol NormalizeFSProtocol(TFSProtocol FSProtocol);
//---------------------------------------------------------------------------
#endif
2 changes: 1 addition & 1 deletion source/core/SftpFileSystem.h
Expand Up @@ -72,6 +72,7 @@ friend class TSFTPBusy;
const TRemoteFile * File, UnicodeString Command, int Params, TCaptureOutputEvent OutputEvent);
virtual void __fastcall DoStartup();
virtual void __fastcall HomeDirectory();
virtual UnicodeString __fastcall GetHomeDirectory();
virtual bool __fastcall IsCapable(int Capability) const;
virtual void __fastcall LookupUsersGroups();
virtual void __fastcall ReadCurrentDirectory();
Expand Down Expand Up @@ -132,7 +133,6 @@ friend class TSFTPBusy;
TRemoteFile *& File, unsigned char Type, TRemoteFile * ALinkedByFile = NULL,
int AllowStatus = -1);
virtual UnicodeString __fastcall GetCurrentDirectory();
UnicodeString __fastcall GetHomeDirectory();
unsigned long __fastcall GotStatusPacket(TSFTPPacket * Packet, int AllowStatus);
bool __fastcall RemoteFileExists(const UnicodeString FullPath, TRemoteFile ** File = NULL);
TRemoteFile * __fastcall LoadFile(TSFTPPacket * Packet,
Expand Down
5 changes: 5 additions & 0 deletions source/core/Terminal.cpp
Expand Up @@ -4681,6 +4681,11 @@ void __fastcall TTerminal::HomeDirectory()
}
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TTerminal::GetHomeDirectory()
{
return FFileSystem->GetHomeDirectory();
}
//---------------------------------------------------------------------------
void __fastcall TTerminal::ChangeDirectory(const UnicodeString Directory)
{
DebugAssert(FFileSystem);
Expand Down
1 change: 1 addition & 0 deletions source/core/Terminal.h
Expand Up @@ -500,6 +500,7 @@ friend class TRetryOperationLoop;
void __fastcall ChangeDirectory(const UnicodeString Directory);
void __fastcall EndTransaction();
void __fastcall HomeDirectory();
UnicodeString __fastcall GetHomeDirectory();
void __fastcall ChangeFileProperties(UnicodeString FileName,
const TRemoteFile * File, /*const TRemoteProperties */ void * Properties);
void __fastcall ChangeFilesProperties(TStrings * FileList,
Expand Down
13 changes: 13 additions & 0 deletions source/forms/CustomScpExplorer.cpp
Expand Up @@ -9486,6 +9486,19 @@ void __fastcall TCustomScpExplorerForm::ChangePassword()
}
}
//---------------------------------------------------------------------------
bool __fastcall TCustomScpExplorerForm::CanPrivateKeyUpload()
{
// No nice way to assert SSH2
return (Terminal != NULL) && Terminal->Active && (Terminal->FSProtocol == cfsSFTP);
}
//---------------------------------------------------------------------------
void __fastcall TCustomScpExplorerForm::PrivateKeyUpload()
{
TOperationVisualizer OperationVisualizer;
UnicodeString FileName = Terminal->SessionData->PublicKeyFile;
TTerminalManager::Instance()->UploadPublicKey(Terminal, NULL, FileName);
}
//---------------------------------------------------------------------------
void __fastcall TCustomScpExplorerForm::ChangeScale(int M, int D)
{
TForm::ChangeScale(M, D);
Expand Down
2 changes: 2 additions & 0 deletions source/forms/CustomScpExplorer.h
Expand Up @@ -717,6 +717,8 @@ class TCustomScpExplorerForm : public TForm
bool __fastcall CanConsole();
bool __fastcall CanChangePassword();
void __fastcall ChangePassword();
bool __fastcall CanPrivateKeyUpload();
void __fastcall PrivateKeyUpload();
bool __fastcall IsComponentPossible(Byte Component);

__property bool ComponentVisible[Byte Component] = { read = GetComponentVisible, write = SetComponentVisible };
Expand Down
2 changes: 2 additions & 0 deletions source/forms/NonVisual.cpp
Expand Up @@ -417,6 +417,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsUpdate(
UPD(NewFileAction, DirViewEnabled(osCurrent) && !WinConfiguration->DisableOpenEdit)
UPD(EditorListCustomizeAction, true)
UPD(ChangePasswordAction, ScpExplorer->CanChangePassword())
UPD(PrivateKeyUploadAction, ScpExplorer->CanPrivateKeyUpload())

// CUSTOM COMMANDS
UPD(CustomCommandsFileAction, true)
Expand Down Expand Up @@ -730,6 +731,7 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
EXE(NewFileAction, ScpExplorer->EditNew(osCurrent))
EXE(EditorListCustomizeAction, PreferencesDialog(pmEditor))
EXE(ChangePasswordAction, ScpExplorer->ChangePassword())
EXE(PrivateKeyUploadAction, ScpExplorer->PrivateKeyUpload())

// CUSTOM COMMANDS
EXE(CustomCommandsFileAction, CreateCustomCommandsMenu(CustomCommandsFileAction, ccltFile))
Expand Down
7 changes: 7 additions & 0 deletions source/forms/NonVisual.dfm
Expand Up @@ -2208,6 +2208,13 @@ object NonVisualDataModule: TNonVisualDataModule
HelpKeyword = 'task_change_password'
Hint = 'Change account password'
end
object PrivateKeyUploadAction: TAction
Tag = 15
Category = 'Session'
Caption = '&Install Public Key into Server...'
HelpKeyword = 'guide_public_key'
Hint = 'Install public key for authentication into the server'
end
object RemoteNewFileAction: TAction
Tag = 15
Category = 'Remote Selected Operation'
Expand Down
1 change: 1 addition & 0 deletions source/forms/NonVisual.h
Expand Up @@ -615,6 +615,7 @@ class TNonVisualDataModule : public TDataModule
TTBXSubmenuItem *TBXSubmenuItem4;
TTBXSubmenuItem *TBXSubmenuItem6;
TTBXSubmenuItem *TBXSubmenuItem9;
TAction *PrivateKeyUploadAction;
void __fastcall ExplorerActionsUpdate(TBasicAction *Action, bool &Handled);
void __fastcall ExplorerActionsExecute(TBasicAction *Action, bool &Handled);
void __fastcall SessionIdleTimerTimer(TObject *Sender);
Expand Down
3 changes: 3 additions & 0 deletions source/forms/ScpCommander.dfm
Expand Up @@ -429,6 +429,9 @@ inherited ScpCommanderForm: TScpCommanderForm
object TBXItem227: TTBXItem
Action = NonVisualDataModule.ChangePasswordAction
end
object TBXItem76: TTBXItem
Action = NonVisualDataModule.PrivateKeyUploadAction
end
object TBXSeparatorItem29: TTBXSeparatorItem
end
object TBXSubmenuItem21: TTBXSubmenuItem
Expand Down
1 change: 1 addition & 0 deletions source/forms/ScpCommander.h
Expand Up @@ -423,6 +423,7 @@ class TScpCommanderForm : public TCustomScpExplorerForm
TTBXItem *TBXItem248;
TTBXItem *TBXItem249;
TTBXItem *TBXItem250;
TTBXItem *TBXItem76;
void __fastcall SplitterMoved(TObject *Sender);
void __fastcall SplitterCanResize(TObject *Sender, int &NewSize,
bool &Accept);
Expand Down
3 changes: 3 additions & 0 deletions source/forms/ScpExplorer.dfm
Expand Up @@ -305,6 +305,9 @@ inherited ScpExplorerForm: TScpExplorerForm
object TBXItem160: TTBXItem
Action = NonVisualDataModule.ChangePasswordAction
end
object TBXItem14: TTBXItem
Action = NonVisualDataModule.ChangePasswordAction
end
object TBXSeparatorItem29: TTBXSeparatorItem
end
object TBXSubmenuItem21: TTBXSubmenuItem
Expand Down
1 change: 1 addition & 0 deletions source/forms/ScpExplorer.h
Expand Up @@ -313,6 +313,7 @@ class TScpExplorerForm : public TCustomScpExplorerForm
TTBXItem *TBXItem247;
TTBXItem *TBXItem244;
TTBXItem *TBXItem246;
TTBXItem *TBXItem14;
void __fastcall RemoteDirViewUpdateStatusBar(TObject *Sender,
const TStatusFileInfo &FileInfo);
void __fastcall UnixPathComboBoxBeginEdit(TTBEditItem *Sender,
Expand Down
62 changes: 55 additions & 7 deletions source/forms/SiteAdvanced.cpp
Expand Up @@ -16,6 +16,8 @@
#include "Tools.h"
#include "WinConfiguration.h"
#include "PuttyTools.h"
#include "TerminalManager.h"
#include "Authenticate.h"
//---------------------------------------------------------------------
#pragma link "ComboEdit"
#pragma link "PasswordEdit"
Expand Down Expand Up @@ -105,8 +107,7 @@ void __fastcall TSiteAdvancedDialog::InitControls()
SelectScaledImageList(ColorImageList);
SetSessionColor((TColor)0);

UnicodeString Dummy;
PrivateKeyGenerateButton->Enabled = FindTool(PuttygenTool, Dummy);
MenuButton(PrivateKeyToolsButton);
}
//---------------------------------------------------------------------
void __fastcall TSiteAdvancedDialog::LoadSession()
Expand Down Expand Up @@ -752,8 +753,7 @@ void __fastcall TSiteAdvancedDialog::UpdateControls()
TAutoNestingCounter NoUpdateCounter(NoUpdate);

bool SshProtocol = FSessionData->UsesSsh;
bool SftpProtocol =
(FSessionData->FSProtocol == fsSFTPonly) || (FSessionData->FSProtocol == fsSFTP);
bool SftpProtocol = (NormalizeFSProtocol(FSessionData->FSProtocol) == fsSFTP);
bool ScpProtocol = (FSessionData->FSProtocol == fsSCPonly);
bool FtpProtocol = (FSessionData->FSProtocol == fsFTP);
bool WebDavProtocol = (FSessionData->FSProtocol == fsWebDAV);
Expand Down Expand Up @@ -794,6 +794,7 @@ void __fastcall TSiteAdvancedDialog::UpdateControls()
((AuthTISCheck->Enabled && AuthTISCheck->Checked) ||
(AuthKICheck->Enabled && AuthKICheck->Checked)));
EnableControl(AuthenticationParamsGroup, AuthenticationGroup->Enabled);
EnableControl(PrivateKeyViewButton, PrivateKeyEdit3->Enabled && !PrivateKeyEdit3->Text.IsEmpty());
EnableControl(AuthGSSAPICheck3,
AuthenticationGroup->Enabled && (GetSshProt() == ssh2only));
EnableControl(GSSAPIFwdTGTCheck,
Expand Down Expand Up @@ -1255,7 +1256,7 @@ void __fastcall TSiteAdvancedDialog::PrivateKeyEdit3AfterDialog(TObject * Sender
TFilenameEdit * Edit = dynamic_cast<TFilenameEdit *>(Sender);
if (Name != Edit->Text)
{
VerifyAndConvertKey(Name, GetSshProt());
VerifyAndConvertKey(Name, GetSshProt(), true);
}
}
//---------------------------------------------------------------------------
Expand Down Expand Up @@ -1521,14 +1522,61 @@ void __fastcall TSiteAdvancedDialog::PrivateKeyCreatedOrModified(TObject * /*Sen
{
if (SameText(ExtractFileExt(FileName), FORMAT(L".%s", (PuttyKeyExt))))
{
PrivateKeyEdit3->FileName = FileName;
PrivateKeyEdit3->Text = FileName;
}
}
//---------------------------------------------------------------------------
void __fastcall TSiteAdvancedDialog::PrivateKeyGenerateButtonClick(TObject * /*Sender*/)
void __fastcall TSiteAdvancedDialog::PrivateKeyToolsButtonClick(TObject * /*Sender*/)
{
UnicodeString Dummy;
PrivateKeyGenerateItem->Enabled = FindTool(PuttygenTool, Dummy);
PrivateKeyUploadItem->Enabled = (GetSshProt() == ssh2only) && (NormalizeFSProtocol(FSessionData->FSProtocol) == fsSFTP);
MenuPopup(PrivateKeyMenu, PrivateKeyToolsButton);
}
//---------------------------------------------------------------------------
void __fastcall TSiteAdvancedDialog::PrivateKeyGenerateItemClick(TObject * /*Sender*/)
{
unsigned int Filters = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE;
FPrivateKeyMonitors.reset(StartCreationDirectoryMonitorsOnEachDrive(Filters, PrivateKeyCreatedOrModified));
ExecuteTool(PuttygenTool);
}
//---------------------------------------------------------------------------
void __fastcall TSiteAdvancedDialog::PrivateKeyUploadItemClick(TObject * /*Sender*/)
{
SaveSession();
FSessionData->FSProtocol = fsSFTPonly; // no SCP fallback, as SCP does not implement GetHomeDirectory
FSessionData->RemoteDirectory = UnicodeString();

UnicodeString FileName = PrivateKeyEdit3->Text;
if (TTerminalManager::Instance()->UploadPublicKey(NULL, FSessionData, FileName))
{
PrivateKeyEdit3->Text = FileName;
PrivateKeyEdit3->SetFocus();
}
}
//---------------------------------------------------------------------------
void __fastcall TSiteAdvancedDialog::PrivateKeyViewButtonClick(TObject * /*Sender*/)
{
UnicodeString FileName = PrivateKeyEdit3->Text;
VerifyAndConvertKey(FileName, GetSshProt(), false);
PrivateKeyEdit3->Text = FileName;
UnicodeString CommentDummy;
UnicodeString Line = GetPublicKeyLine(FileName, CommentDummy);
std::unique_ptr<TStrings> Messages(TextToStringList(Line));

TClipboardHandler ClipboardHandler;
ClipboardHandler.Text = Line;

TMessageParams Params;
TQueryButtonAlias Aliases[1];
Aliases[0].Button = qaRetry;
Aliases[0].Alias = LoadStr(COPY_KEY_BUTTON);
Aliases[0].OnSubmit = &ClipboardHandler.Copy;
Params.Aliases = Aliases;
Params.AliasesCount = LENOF(Aliases);

UnicodeString Message = LoadStr(LOGIN_AUTHORIZED_KEYS);
int Answers = qaOK | qaRetry;
MoreMessageDialog(Message, Messages.get(), qtInformation, Answers, HELP_LOGIN_AUTHORIZED_KEYS, &Params);
}
//---------------------------------------------------------------------------

0 comments on commit 64f634d

Please sign in to comment.