mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
ADD: SSH - verify server fingerprint
UPD: FTP - use standard dialog for quick connection
This commit is contained in:
parent
8abc3d779b
commit
fd85eb22bc
3 changed files with 111 additions and 109 deletions
|
|
@ -71,10 +71,8 @@ procedure EnableControls(pDlg: PtrUInt);
|
|||
begin
|
||||
with gStartupInfo do
|
||||
begin
|
||||
SendDlgMsg(pDlg, 'chkOnlySCP', DM_ENABLE, PtrInt(gConnection.OpenSSH), 0);
|
||||
SendDlgMsg(pDlg, 'chkShowHidden', DM_ENABLE, PtrInt(not gConnection.OpenSSH), 0);
|
||||
SendDlgMsg(pDlg, 'chkPassiveMode', DM_ENABLE, PtrInt(not gConnection.OpenSSH), 0);
|
||||
SendDlgMsg(pDlg, 'chkKeepAliveTransfer', DM_ENABLE, PtrInt(not gConnection.OpenSSH), 0);
|
||||
SendDlgMsg(pDlg, 'gbSSH', DM_ENABLE, PtrInt(gConnection.OpenSSH), 0);
|
||||
SendDlgMsg(pDlg, 'gbFTP', DM_ENABLE, PtrInt(not gConnection.OpenSSH), 0);
|
||||
if not gConnection.OpenSSH then
|
||||
SendDlgMsg(pDlg, 'chkOnlySCP', DM_SETCHECK, 0, 0)
|
||||
else begin
|
||||
|
|
@ -293,6 +291,12 @@ begin
|
|||
Data:= PtrInt(PAnsiChar(gConnection.PrivateKey));
|
||||
SendDlgMsg(pDlg, 'fnePrivateKey', DM_SETTEXT, Data, 0);
|
||||
|
||||
if SameText(gConnection.ConnectionName, cQuickConnection) then
|
||||
begin
|
||||
SendDlgMsg(pDlg, 'edtName', DM_ENABLE, 0, 0);
|
||||
SendDlgMsg(pDlg, 'chkMasterPassword', DM_SHOWITEM, 0, 0);
|
||||
end;
|
||||
|
||||
EnableControls(pDlg);
|
||||
|
||||
LoadProxyList(pDlg);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ uses
|
|||
SysUtils, Classes,
|
||||
WfxPlugin, Extension;
|
||||
|
||||
const
|
||||
cAddConnection = '<Add connection>';
|
||||
cQuickConnection = '<Quick connection>';
|
||||
|
||||
type
|
||||
|
||||
{ TConnection }
|
||||
|
|
@ -50,6 +54,7 @@ type
|
|||
OpenSSH: Boolean;
|
||||
UseAllocate: Boolean;
|
||||
Encoding: AnsiString;
|
||||
Fingerprint: AnsiString;
|
||||
InitCommands: AnsiString;
|
||||
ShowHiddenItems: Boolean;
|
||||
PasswordChanged: Boolean;
|
||||
|
|
@ -123,15 +128,12 @@ var
|
|||
TcpKeepAlive: Boolean = True;
|
||||
ActiveConnectionList, ConnectionList: TStringList;
|
||||
IniFile: TIniFile;
|
||||
HasDialogAPI: Boolean = False;
|
||||
ListLock: TCriticalSection;
|
||||
|
||||
threadvar
|
||||
ThreadCon: TFtpSendEx;
|
||||
|
||||
const
|
||||
cAddConnection = '<Add connection>';
|
||||
cQuickConnection = '<Quick connection>';
|
||||
FS_COPYFLAGS_FORCE = FS_COPYFLAGS_OVERWRITE or FS_COPYFLAGS_RESUME;
|
||||
RootList: array [0 .. 1] of AnsiString = (cAddConnection, cQuickConnection);
|
||||
|
||||
|
|
@ -175,6 +177,7 @@ begin
|
|||
Connection.UseAllocate:= IniFile.ReadBool('FTP', 'Connection' + sIndex + 'UseAllocate', False);
|
||||
Connection.PublicKey := IniFile.ReadString('FTP', 'Connection' + sIndex + 'PublicKey', EmptyStr);
|
||||
Connection.PrivateKey := IniFile.ReadString('FTP', 'Connection' + sIndex + 'PrivateKey', EmptyStr);
|
||||
Connection.Fingerprint:= IniFile.ReadString('FTP', 'Connection' + sIndex + 'Fingerprint', EmptyStr);
|
||||
Connection.InitCommands := IniFile.ReadString('FTP', 'Connection' + sIndex + 'InitCommands', EmptyStr);
|
||||
Connection.ShowHiddenItems := IniFile.ReadBool('FTP', 'Connection' + sIndex + 'ShowHiddenItems', True);
|
||||
Connection.KeepAliveTransfer := IniFile.ReadBool('FTP', 'Connection' + sIndex + 'KeepAliveTransfer', False);
|
||||
|
|
@ -217,6 +220,7 @@ begin
|
|||
IniFile.WriteBool('FTP', 'Connection' + sIndex + 'UseAllocate', Connection.UseAllocate);
|
||||
IniFile.WriteString('FTP', 'Connection' + sIndex + 'PublicKey', Connection.PublicKey);
|
||||
IniFile.WriteString('FTP', 'Connection' + sIndex + 'PrivateKey', Connection.PrivateKey);
|
||||
IniFile.WriteString('FTP', 'Connection' + sIndex + 'Fingerprint', Connection.Fingerprint);
|
||||
IniFile.WriteString('FTP', 'Connection' + sIndex + 'InitCommands', Connection.InitCommands);
|
||||
IniFile.WriteBool('FTP', 'Connection' + sIndex + 'ShowHiddenItems', Connection.ShowHiddenItems);
|
||||
IniFile.WriteBool('FTP', 'Connection' + sIndex + 'KeepAliveTransfer', Connection.KeepAliveTransfer);
|
||||
|
|
@ -333,6 +337,7 @@ begin
|
|||
end;
|
||||
FtpSend.PublicKey:= Connection.PublicKey;
|
||||
FtpSend.PrivateKey:= Connection.PrivateKey;
|
||||
TScpSend(FtpSend).Fingerprint:= Connection.Fingerprint;
|
||||
end
|
||||
else begin
|
||||
FtpSend := TFTPSendEx.Create(Connection.Encoding);
|
||||
|
|
@ -371,6 +376,15 @@ begin
|
|||
begin
|
||||
LogProc(PluginNumber, MSGTYPE_CONNECT, PWideChar('CONNECT ' + PathDelim + UTF8Decode(ConnectionName)));
|
||||
ActiveConnectionList.AddObject(ConnectionName, FtpSend);
|
||||
if Connection.OpenSSH and (ConnectionName <> cQuickConnection) then
|
||||
begin
|
||||
// Save connection server fingerprint
|
||||
if Connection.Fingerprint <> TScpSend(FtpSend).Fingerprint then
|
||||
begin
|
||||
Connection.Fingerprint:= TScpSend(FtpSend).Fingerprint;
|
||||
WriteConnectionList;
|
||||
end;
|
||||
end;
|
||||
Result:= True;
|
||||
end
|
||||
else
|
||||
|
|
@ -383,29 +397,6 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function AddQuickConnection(const Connection: TConnection): Boolean;
|
||||
var
|
||||
Text: PWideChar;
|
||||
Temp: UnicodeString;
|
||||
begin
|
||||
Result:= False;
|
||||
SetLength(Temp, MAX_PATH + 1);
|
||||
Text:= PWideChar(Temp); Text[0]:= #0;
|
||||
if RequestProc(PluginNumber, RT_URL, nil, nil, Text, MAX_PATH) then
|
||||
begin
|
||||
Connection.Host := Text; Text[0]:= #0;
|
||||
if RequestProc(PluginNumber, RT_TargetDir, nil, nil, Text, MAX_PATH) then
|
||||
begin
|
||||
Connection.Path := Text; Text[0]:= #0;
|
||||
if RequestProc(PluginNumber, RT_UserName, nil, nil, Text, MAX_PATH) then
|
||||
begin
|
||||
Connection.UserName := Text;
|
||||
Result:= True;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function QuickConnection: Boolean;
|
||||
var
|
||||
Index: Integer;
|
||||
|
|
@ -416,16 +407,13 @@ begin
|
|||
if not Result then
|
||||
begin
|
||||
Connection := TConnection.Create;
|
||||
if AddQuickConnection(Connection) then
|
||||
Connection.ConnectionName:= cQuickConnection;
|
||||
if ShowFtpConfDlg(Connection) then
|
||||
begin
|
||||
if ShowPasswordDialog(Connection.Password) then
|
||||
begin
|
||||
Connection.PassiveMode:= True;
|
||||
Connection.ConnectionName:= cQuickConnection;
|
||||
Index:= ConnectionList.AddObject(Connection.ConnectionName, Connection);
|
||||
Result:= FtpConnect(Connection.ConnectionName, FtpSend);
|
||||
ConnectionList.Delete(Index);
|
||||
end;
|
||||
Connection.ConnectionName:= cQuickConnection;
|
||||
Index:= ConnectionList.AddObject(Connection.ConnectionName, Connection);
|
||||
Result:= FtpConnect(Connection.ConnectionName, FtpSend);
|
||||
ConnectionList.Delete(Index);
|
||||
end;
|
||||
Connection.Free;
|
||||
end;
|
||||
|
|
@ -440,37 +428,23 @@ begin
|
|||
Connection := TConnection.Create;
|
||||
Connection.PassiveMode := True;
|
||||
|
||||
if HasDialogAPI then
|
||||
if ShowFtpConfDlg(Connection) then
|
||||
begin
|
||||
if ShowFtpConfDlg(Connection) then
|
||||
with Connection do
|
||||
begin
|
||||
with Connection do
|
||||
begin
|
||||
if ConnectionList.IndexOf(ConnectionName) >= 0 then begin
|
||||
ConnectionName += '+' + IntToStr(Random(MaxInt));
|
||||
end;
|
||||
if MasterPassword then
|
||||
begin
|
||||
if Length(Password) = 0 then
|
||||
MasterPassword:= False
|
||||
else if CryptFunc(FS_CRYPT_SAVE_PASSWORD, ConnectionName, Password) = FS_FILE_OK then
|
||||
Password:= EmptyStr
|
||||
else
|
||||
MasterPassword:= False;
|
||||
end;
|
||||
Result:= ConnectionList.AddObject(ConnectionName, Connection);
|
||||
if ConnectionList.IndexOf(ConnectionName) >= 0 then begin
|
||||
ConnectionName += '+' + IntToStr(Random(MaxInt));
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
SetLength(Temp, MAX_PATH + 1); Temp[1]:= #0;
|
||||
if RequestProc(PluginNumber, RT_Other, nil, nil, PWideChar(Temp), MAX_PATH) then
|
||||
begin
|
||||
Connection.ConnectionName := PAnsiChar(Temp);
|
||||
if AddQuickConnection(Connection) then
|
||||
if MasterPassword then
|
||||
begin
|
||||
Result:= ConnectionList.AddObject(Connection.ConnectionName, Connection);
|
||||
if Length(Password) = 0 then
|
||||
MasterPassword:= False
|
||||
else if CryptFunc(FS_CRYPT_SAVE_PASSWORD, ConnectionName, Password) = FS_FILE_OK then
|
||||
Password:= EmptyStr
|
||||
else
|
||||
MasterPassword:= False;
|
||||
end;
|
||||
Result:= ConnectionList.AddObject(ConnectionName, Connection);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -487,55 +461,52 @@ var
|
|||
Connection: TConnection;
|
||||
begin
|
||||
Result:= False;
|
||||
if HasDialogAPI then
|
||||
I := ConnectionList.IndexOf(ConnectionName);
|
||||
if I >= 0 then
|
||||
begin
|
||||
I := ConnectionList.IndexOf(ConnectionName);
|
||||
if I >= 0 then
|
||||
ATemp:= TConnection.Create;
|
||||
Connection:= TConnection(ConnectionList.Objects[I]);
|
||||
ATemp.Assign(Connection);
|
||||
if ShowFtpConfDlg(ATemp) then
|
||||
begin
|
||||
ATemp:= TConnection.Create;
|
||||
Connection:= TConnection(ConnectionList.Objects[I]);
|
||||
ATemp.Assign(Connection);
|
||||
if ShowFtpConfDlg(ATemp) then
|
||||
with ATemp do
|
||||
begin
|
||||
with ATemp do
|
||||
if ConnectionName <> Connection.ConnectionName then
|
||||
begin
|
||||
if ConnectionName <> Connection.ConnectionName then
|
||||
if Connection.MasterPassword then
|
||||
begin
|
||||
if Connection.MasterPassword then
|
||||
if CryptFunc(FS_CRYPT_MOVE_PASSWORD, Connection.ConnectionName, ConnectionName) <> FS_FILE_OK then
|
||||
begin
|
||||
if CryptFunc(FS_CRYPT_MOVE_PASSWORD, Connection.ConnectionName, ConnectionName) <> FS_FILE_OK then
|
||||
begin
|
||||
gStartupInfo.MessageBox('Cannot save connection!', 'FTP', MB_OK or MB_ICONERROR);
|
||||
Exit(False);
|
||||
end;
|
||||
gStartupInfo.MessageBox('Cannot save connection!', 'FTP', MB_OK or MB_ICONERROR);
|
||||
Exit(False);
|
||||
end;
|
||||
ConnectionList[I]:= ConnectionName
|
||||
end;
|
||||
if PasswordChanged then
|
||||
begin
|
||||
// Master password enabled
|
||||
if MasterPassword then
|
||||
begin
|
||||
if Length(Password) = 0 then
|
||||
MasterPassword:= False
|
||||
else if CryptFunc(FS_CRYPT_SAVE_PASSWORD, ConnectionName, Password) = FS_FILE_OK then
|
||||
Password:= EmptyStr
|
||||
else
|
||||
MasterPassword:= False;
|
||||
end;
|
||||
// Master password disabled
|
||||
if (MasterPassword = False) and (Connection.MasterPassword <> MasterPassword) then
|
||||
begin
|
||||
DeletePassword(ConnectionName);
|
||||
end;
|
||||
end
|
||||
ConnectionList[I]:= ConnectionName
|
||||
end;
|
||||
Connection.Assign(ATemp);
|
||||
WriteConnectionList;
|
||||
Result:= True;
|
||||
if PasswordChanged then
|
||||
begin
|
||||
// Master password enabled
|
||||
if MasterPassword then
|
||||
begin
|
||||
if Length(Password) = 0 then
|
||||
MasterPassword:= False
|
||||
else if CryptFunc(FS_CRYPT_SAVE_PASSWORD, ConnectionName, Password) = FS_FILE_OK then
|
||||
Password:= EmptyStr
|
||||
else
|
||||
MasterPassword:= False;
|
||||
end;
|
||||
// Master password disabled
|
||||
if (MasterPassword = False) and (Connection.MasterPassword <> MasterPassword) then
|
||||
begin
|
||||
DeletePassword(ConnectionName);
|
||||
end;
|
||||
end
|
||||
end;
|
||||
FreeAndNil(ATemp);
|
||||
Connection.Assign(ATemp);
|
||||
WriteConnectionList;
|
||||
Result:= True;
|
||||
end;
|
||||
FreeAndNil(ATemp);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
@ -1101,8 +1072,6 @@ begin
|
|||
TcpKeepAlive := IniFile.ReadBool('General', 'TcpKeepAlive', TcpKeepAlive);
|
||||
|
||||
ReadConnectionList;
|
||||
|
||||
HasDialogAPI:= True;
|
||||
end;
|
||||
|
||||
function ReadPassword(ConnectionName: AnsiString): String;
|
||||
|
|
@ -1137,6 +1106,7 @@ begin
|
|||
Encoding:= Connection.Encoding;
|
||||
PublicKey:= Connection.PublicKey;
|
||||
PrivateKey:= Connection.PrivateKey;
|
||||
Fingerprint:= Connection.Fingerprint;
|
||||
PassiveMode:= Connection.PassiveMode;
|
||||
UseAllocate:= Connection.UseAllocate;
|
||||
InitCommands:= Connection.InitCommands;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ type
|
|||
FCurrentDir: String;
|
||||
FLastError: Integer;
|
||||
FSavedPassword: Boolean;
|
||||
FFingerprint: AnsiString;
|
||||
FSession: PLIBSSH2_SESSION;
|
||||
SourceName, TargetName: PWideChar;
|
||||
procedure DoProgress(Percent: Int64);
|
||||
|
|
@ -62,6 +63,7 @@ type
|
|||
function Login: Boolean; override;
|
||||
function Logout: Boolean; override;
|
||||
function GetCurrentDir: String; override;
|
||||
procedure CloneTo(AValue: TFTPSendEx); override;
|
||||
function FileSize(const FileName: String): Int64; override;
|
||||
function FileExists(const FileName: String): Boolean; override;
|
||||
function CreateDir(const Directory: string): Boolean; override;
|
||||
|
|
@ -78,6 +80,8 @@ type
|
|||
public
|
||||
function List(Directory: String; NameList: Boolean): Boolean; override;
|
||||
function FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PWfxFileTime): BOOL; override;
|
||||
public
|
||||
property Fingerprint: AnsiString read FFingerprint write FFingerprint;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
|
@ -290,8 +294,9 @@ function TScpSend.Connect: Boolean;
|
|||
const
|
||||
HOSTKEY_SIZE = 20;
|
||||
var
|
||||
S: String;
|
||||
I: Integer;
|
||||
S: String = '';
|
||||
Message: UnicodeString;
|
||||
userauthlist: PAnsiChar;
|
||||
FingerPrint: array [0..Pred(HOSTKEY_SIZE)] of AnsiChar;
|
||||
begin
|
||||
|
|
@ -318,12 +323,29 @@ begin
|
|||
|
||||
DoStatus(False, 'Connection established');
|
||||
FingerPrint := libssh2_hostkey_hash(FSession, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
S:= 'Server fingerprint:';
|
||||
for I:= Low(FingerPrint) to High(FingerPrint) do
|
||||
begin
|
||||
S:= S + #32 + IntToHex(Ord(FingerPrint[i]), 2);
|
||||
S+= IntToHex(Ord(FingerPrint[I]), 2) + #32;
|
||||
end;
|
||||
SetLength(S, Length(S) - 1); // Remove space
|
||||
DoStatus(False, 'Server fingerprint: ' + S);
|
||||
|
||||
// Verify server fingerprint
|
||||
if FFingerPrint <> S then
|
||||
begin
|
||||
if FFingerprint = EmptyStr then
|
||||
Message:= 'You are using this connection for the first time.' + LineEnding + 'Please verify that the following host fingerprint matches the fingerprint of your server:'
|
||||
else begin
|
||||
Message:= 'WARNING!' + LineEnding + 'The fingerprint of the host has changed!' + LineEnding + 'Please make sure that the new fingerprint matches your server:';
|
||||
end;
|
||||
Message += UnicodeString(LineEnding + LineEnding + S);
|
||||
if not RequestProc(PluginNumber, RT_MsgYesNo, nil, PWideChar(Message), nil, 0) then
|
||||
begin
|
||||
LogProc(PluginNumber, msgtype_importanterror, 'Wrong server fingerprint!');
|
||||
Exit(False);
|
||||
end;
|
||||
FFingerprint:= S;
|
||||
end;
|
||||
DoStatus(False, S);
|
||||
|
||||
//* check what authentication methods are available */
|
||||
userauthlist := libssh2_userauth_list(FSession, PAnsiChar(FUserName), Length(FUserName));
|
||||
|
|
@ -416,6 +438,12 @@ begin
|
|||
Result:= FCurrentDir;
|
||||
end;
|
||||
|
||||
procedure TScpSend.CloneTo(AValue: TFTPSendEx);
|
||||
begin
|
||||
inherited CloneTo(AValue);
|
||||
TScpSend(AValue).FFingerprint:= FFingerprint;
|
||||
end;
|
||||
|
||||
function TScpSend.FileSize(const FileName: String): Int64;
|
||||
begin
|
||||
Result:= -1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue