Add support for SSH tunneled PostgreSQL connections. See issue #78

This commit is contained in:
Ansgar Becker
2019-05-14 07:57:00 +02:00
parent 927e144cce
commit f893a8de75
2 changed files with 33 additions and 10 deletions

View File

@ -1179,7 +1179,7 @@ begin
editUsername.Enabled := lblUsername.Enabled; editUsername.Enabled := lblUsername.Enabled;
lblPassword.Enabled := lblUsername.Enabled; lblPassword.Enabled := lblUsername.Enabled;
editPassword.Enabled := lblUsername.Enabled; editPassword.Enabled := lblUsername.Enabled;
lblPort.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMSSQL_TCPIP, ntPgSQL_TCPIP]; lblPort.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMSSQL_TCPIP, ntPgSQL_TCPIP, ntPgSQL_SSHtunnel];
if (Params.NetType = ntMSSQL_TCPIP) and (Pos('\', editHost.Text) > 0) then if (Params.NetType = ntMSSQL_TCPIP) and (Pos('\', editHost.Text) > 0) then
lblPort.Enabled := False; // Named instance without port lblPort.Enabled := False; // Named instance without port
editPort.Enabled := lblPort.Enabled; editPort.Enabled := lblPort.Enabled;
@ -1197,7 +1197,7 @@ begin
editSSLCertificate.Enabled := Params.WantSSL; editSSLCertificate.Enabled := Params.WantSSL;
lblSSLcipher.Enabled := Params.WantSSL; lblSSLcipher.Enabled := Params.WantSSL;
editSSLcipher.Enabled := Params.WantSSL; editSSLcipher.Enabled := Params.WantSSL;
tabSSHtunnel.TabVisible := Params.NetType = ntMySQL_SSHtunnel; tabSSHtunnel.TabVisible := Params.NetType in [ntMySQL_SSHtunnel, ntPgSQL_SSHtunnel];
lblQueryTimeout.Enabled := Params.NetTypeGroup in [ngMSSQL, ngPgSQL]; lblQueryTimeout.Enabled := Params.NetTypeGroup in [ngMSSQL, ngPgSQL];
editQueryTimeout.Enabled := lblQueryTimeout.Enabled; editQueryTimeout.Enabled := lblQueryTimeout.Enabled;
updownQueryTimeout.Enabled := lblQueryTimeout.Enabled; updownQueryTimeout.Enabled := lblQueryTimeout.Enabled;

View File

@ -205,7 +205,7 @@ type
TNetType = (ntMySQL_TCPIP, ntMySQL_NamedPipe, ntMySQL_SSHtunnel, TNetType = (ntMySQL_TCPIP, ntMySQL_NamedPipe, ntMySQL_SSHtunnel,
ntMSSQL_NamedPipe, ntMSSQL_TCPIP, ntMSSQL_SPX, ntMSSQL_VINES, ntMSSQL_RPC, ntMSSQL_NamedPipe, ntMSSQL_TCPIP, ntMSSQL_SPX, ntMSSQL_VINES, ntMSSQL_RPC,
ntPgSQL_TCPIP); ntPgSQL_TCPIP, ntPgSQL_SSHtunnel);
TNetTypeGroup = (ngMySQL, ngMSSQL, ngPgSQL); TNetTypeGroup = (ngMySQL, ngMSSQL, ngPgSQL);
TConnectionParameters = class(TObject) TConnectionParameters = class(TObject)
@ -304,6 +304,7 @@ type
FServerUptime: Integer; FServerUptime: Integer;
FServerDateTimeOnStartup: String; FServerDateTimeOnStartup: String;
FParameters: TConnectionParameters; FParameters: TConnectionParameters;
FPlink: TPlink;
FLoginPromptDone: Boolean; FLoginPromptDone: Boolean;
FDatabase: String; FDatabase: String;
FAllDatabases: TStringList; FAllDatabases: TStringList;
@ -469,7 +470,6 @@ type
private private
FHandle: PMYSQL; FHandle: PMYSQL;
FLastRawResults: TMySQLRawResults; FLastRawResults: TMySQLRawResults;
FPlink: TPlink;
procedure SetActive(Value: Boolean); override; procedure SetActive(Value: Boolean); override;
procedure DoBeforeConnect; override; procedure DoBeforeConnect; override;
procedure DoAfterConnect; override; procedure DoAfterConnect; override;
@ -1342,13 +1342,15 @@ begin
ntMSSQL_RPC: ntMSSQL_RPC:
Result := 'Microsoft SQL Server (Windows RPC)'; Result := 'Microsoft SQL Server (Windows RPC)';
ntPgSQL_TCPIP: ntPgSQL_TCPIP:
Result := 'PostgreSQL ('+_('experimental')+')'; Result := 'PostgreSQL (TCP/IP)';
ntPgSQL_SSHtunnel:
Result := 'PostgreSQL (SSH tunnel)';
end else case NetType of end else case NetType of
ntMySQL_TCPIP, ntMySQL_NamedPipe, ntMySQL_SSHtunnel: ntMySQL_TCPIP, ntMySQL_NamedPipe, ntMySQL_SSHtunnel:
Result := My; Result := My;
ntMSSQL_NamedPipe, ntMSSQL_TCPIP: ntMSSQL_NamedPipe, ntMSSQL_TCPIP:
Result := 'MS SQL'; Result := 'MS SQL';
ntPgSQL_TCPIP: ntPgSQL_TCPIP, ntPgSQL_SSHtunnel:
Result := 'PostgreSQL'; Result := 'PostgreSQL';
end; end;
end; end;
@ -1357,7 +1359,7 @@ end;
class function TConnectionParameters.IsCompatibleToWin10S(NetType: TNetType): Boolean; class function TConnectionParameters.IsCompatibleToWin10S(NetType: TNetType): Boolean;
begin begin
// Using plink on 10S is not possible // Using plink on 10S is not possible
Result := NetType <> ntMySQL_SSHtunnel; Result := (NetType <> ntMySQL_SSHtunnel) and (NetType <> ntPgSQL_SSHtunnel);
end; end;
@ -1368,7 +1370,7 @@ begin
Result := ngMySQL; Result := ngMySQL;
ntMSSQL_NamedPipe, ntMSSQL_TCPIP, ntMSSQL_SPX, ntMSSQL_VINES, ntMSSQL_RPC: ntMSSQL_NamedPipe, ntMSSQL_TCPIP, ntMSSQL_SPX, ntMSSQL_VINES, ntMSSQL_RPC:
Result := ngMSSQL; Result := ngMSSQL;
ntPgSQL_TCPIP: ntPgSQL_TCPIP, ntPgSQL_SSHtunnel:
Result := ngPgSQL; Result := ngPgSQL;
else else
raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]);
@ -2072,6 +2074,8 @@ end;
procedure TPgConnection.SetActive(Value: Boolean); procedure TPgConnection.SetActive(Value: Boolean);
var var
dbname, ConnInfo, Error, tmpdb: String; dbname, ConnInfo, Error, tmpdb: String;
FinalHost: String;
FinalPort: Integer;
begin begin
if Value then begin if Value then begin
DoBeforeConnect; DoBeforeConnect;
@ -2080,8 +2084,23 @@ begin
dbname := FParameters.AllDatabasesStr; dbname := FParameters.AllDatabasesStr;
if dbname = '' then if dbname = '' then
dbname := 'postgres'; dbname := 'postgres';
ConnInfo := 'host='''+FParameters.Hostname+''' '+
'port='''+IntToStr(FParameters.Port)+''' '+ // Prepare special stuff for SSH tunnel
FinalHost := FParameters.Hostname;
FinalPort := FParameters.Port;
case FParameters.NetType of
ntPgSQL_SSHtunnel: begin
// Create plink.exe process
FPlink := TPlink.Create(Self);
FPlink.Connect;
FinalHost := '127.0.0.1';
FinalPort := FParameters.SSHLocalPort;
end;
end;
ConnInfo := 'host='''+FinalHost+''' '+
'port='''+IntToStr(FinalPort)+''' '+
'user='''+FParameters.Username+''' ' + 'user='''+FParameters.Username+''' ' +
'password='''+FParameters.Password+''' '+ 'password='''+FParameters.Password+''' '+
'dbname='''+dbname+''' '+ 'dbname='''+dbname+''' '+
@ -2093,6 +2112,8 @@ begin
FConnectionStarted := 0; FConnectionStarted := 0;
PQfinish(FHandle); // free the memory PQfinish(FHandle); // free the memory
FHandle := nil; FHandle := nil;
if FPlink <> nil then
FPlink.Free;
raise EDatabaseError.Create(Error); raise EDatabaseError.Create(Error);
end; end;
FActive := True; FActive := True;
@ -2129,6 +2150,8 @@ begin
FActive := False; FActive := False;
ClearCache(False); ClearCache(False);
FConnectionStarted := 0; FConnectionStarted := 0;
if FPlink <> nil then
FPlink.Free;
Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)]));
end; end;
end; end;