Issue #1986: do not set CLIENT_SSL flag with libmariadb, which seems to cause a "bad handshake" in mysql_real_connect()

This commit is contained in:
Ansgar Becker
2025-03-16 13:40:52 +01:00
parent 888a021d39
commit 09edb5448a
2 changed files with 33 additions and 24 deletions

View File

@ -663,7 +663,7 @@ type
FLastRawResults: TMySQLRawResults; FLastRawResults: TMySQLRawResults;
FStatementNum: Cardinal; FStatementNum: Cardinal;
procedure SetActive(Value: Boolean); override; procedure SetActive(Value: Boolean); override;
procedure SetOption(Option: Integer; Arg: PAnsiChar); procedure SetOption(Option: Integer; Arg: Pointer);
procedure DoBeforeConnect; override; procedure DoBeforeConnect; override;
procedure DoAfterConnect; override; procedure DoAfterConnect; override;
function GetThreadId: Int64; override; function GetThreadId: Int64; override;
@ -2434,7 +2434,7 @@ procedure TMySQLConnection.SetActive( Value: Boolean );
var var
Connected: PMYSQL; Connected: PMYSQL;
ClientFlags, FinalPort, SSLoption: Integer; ClientFlags, FinalPort, SSLoption: Integer;
VerifyServerCert: Byte; VerifyServerCert: Integer;
Error, StatusName: String; Error, StatusName: String;
FinalHost, FinalSocket, FinalUsername, FinalPassword: String; FinalHost, FinalSocket, FinalUsername, FinalPassword: String;
ErrorHint: String; ErrorHint: String;
@ -2473,7 +2473,7 @@ begin
SetOption(FLib.MYSQL_OPT_SSL_CA, PAnsiChar(AnsiString(FParameters.SSLCACertificate))); SetOption(FLib.MYSQL_OPT_SSL_CA, PAnsiChar(AnsiString(FParameters.SSLCACertificate)));
if FParameters.SSLCipher <> '' then if FParameters.SSLCipher <> '' then
SetOption(FLib.MYSQL_OPT_SSL_CIPHER, PAnsiChar(AnsiString(FParameters.SSLCipher))); SetOption(FLib.MYSQL_OPT_SSL_CIPHER, PAnsiChar(AnsiString(FParameters.SSLCipher)));
if FLib.MYSQL_OPT_SSL_MODE <> TMySQLLib.INVALID_OPT then begin if not FLib.IsLibMariadb then begin
// MySQL // MySQL
Log(lcInfo, 'SSL parameters for MySQL'); Log(lcInfo, 'SSL parameters for MySQL');
case FParameters.SSLVerification of case FParameters.SSLVerification of
@ -2539,7 +2539,7 @@ begin
or CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA; or CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA;
if Parameters.Compressed then if Parameters.Compressed then
ClientFlags := ClientFlags or CLIENT_COMPRESS; ClientFlags := ClientFlags or CLIENT_COMPRESS;
if Parameters.WantSSL then if Parameters.WantSSL and (not FLib.IsLibMariadb) then
ClientFlags := ClientFlags or CLIENT_SSL; ClientFlags := ClientFlags or CLIENT_SSL;
// Point libmysql to the folder with client plugins // Point libmysql to the folder with client plugins
@ -3206,7 +3206,7 @@ begin
end; end;
procedure TMySQLConnection.SetOption(Option: Integer; Arg: PAnsiChar); procedure TMySQLConnection.SetOption(Option: Integer; Arg: Pointer);
var var
SetOptionResult: Integer; SetOptionResult: Integer;
RttiContext: TRttiContext; RttiContext: TRttiContext;
@ -3215,23 +3215,25 @@ var
FieldName: String; FieldName: String;
begin begin
// Set one of the MYSQL_* option and log a warning if that failed // Set one of the MYSQL_* option and log a warning if that failed
SetOptionResult := FLib.mysql_options(FHandle, Option, Arg); FieldName := Option.ToString;
if SetOptionResult <> 0 then begin // Attempt to find readable name of option constant
FieldName := Option.ToString; RttiContext := TRttiContext.Create;
// Attempt to find readable name of option constant LibType := RttiContext.GetType(TypeInfo(TMySQLLib));
RttiContext := TRttiContext.Create; for LibField in LibType.GetFields do begin
LibType := RttiContext.GetType(TypeInfo(TMySQLLib)); // Skip assigned procedures
for LibField in LibType.GetFields do begin if LibField.FieldType = nil then
// Skip assigned procedures Continue;
if LibField.FieldType = nil then if LibField.DataType.TypeKind = tkInteger then begin
Continue; if LibField.GetValue(FLib).AsInteger = Option then begin
if LibField.DataType.TypeKind = tkInteger then begin FieldName := LibField.Name;
if LibField.GetValue(FLib).AsInteger = Option then begin
FieldName := LibField.Name;
end;
end; end;
end; end;
RttiContext.Free; end;
RttiContext.Free;
Log(lcDebug, Format('Calling mysql_options(%s, ...)', [FieldName]));
SetOptionResult := FLib.mysql_options(FHandle, Option, Arg);
if SetOptionResult <> 0 then begin
Log(lcError, _(SLogPrefixWarning) + ': mysql_options(' + FieldName + ', ...) failed!'); Log(lcError, _(SLogPrefixWarning) + ': mysql_options(' + FieldName + ', ...) failed!');
end; end;
end; end;

View File

@ -277,7 +277,7 @@ type
mysql_info: function(Handle: PMYSQL): PAnsiChar; stdcall; mysql_info: function(Handle: PMYSQL): PAnsiChar; stdcall;
mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall; mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall;
mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall; mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall;
mysql_options: function(Handle: PMYSQL; Option: Integer; arg: PAnsiChar): Integer; stdcall; mysql_options: function(Handle: PMYSQL; Option: Integer; arg: Pointer): Integer; stdcall;
mysql_optionsv: function(Handle: PMYSQL; Option: Integer; arg, val: PAnsiChar): Integer; stdcall; mysql_optionsv: function(Handle: PMYSQL; Option: Integer; arg, val: PAnsiChar): Integer; stdcall;
mysql_ping: function(Handle: PMYSQL): Integer; stdcall; mysql_ping: function(Handle: PMYSQL): Integer; stdcall;
mysql_real_connect: function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: Cardinal; const UnixSocket: PAnsiChar; ClientFlag: Cardinal): PMYSQL; stdcall; mysql_real_connect: function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: Cardinal; const UnixSocket: PAnsiChar; ClientFlag: Cardinal): PMYSQL; stdcall;
@ -292,8 +292,8 @@ type
mysql_warning_count: function(Handle: PMYSQL): Cardinal; stdcall; mysql_warning_count: function(Handle: PMYSQL): Cardinal; stdcall;
const const
INVALID_OPT = -1; INVALID_OPT = -1;
MYBOOL_FALSE: Byte = 0; MYBOOL_FALSE: Integer = 0;
MYBOOL_TRUE: Byte = 1; MYBOOL_TRUE: Integer = 1;
protected protected
procedure AssignProcedures; override; procedure AssignProcedures; override;
public public
@ -316,6 +316,7 @@ type
SSL_MODE_VERIFY_CA, SSL_MODE_VERIFY_CA,
SSL_MODE_VERIFY_IDENTITY: Integer; SSL_MODE_VERIFY_IDENTITY: Integer;
constructor Create(DllFile, DefaultDll: String); override; constructor Create(DllFile, DefaultDll: String); override;
function IsLibMariadb: Boolean;
end; end;
var var
MySQLKeywords: TStringList; MySQLKeywords: TStringList;
@ -3154,7 +3155,7 @@ begin
SSL_MODE_REQUIRED := 3; SSL_MODE_REQUIRED := 3;
SSL_MODE_VERIFY_CA := 4; SSL_MODE_VERIFY_CA := 4;
SSL_MODE_VERIFY_IDENTITY := 5; SSL_MODE_VERIFY_IDENTITY := 5;
if ExtractFileName(FDllFile).StartsWith('libmariadb', True) then begin if IsLibMariadb then begin
// Differences in libmariadb // Differences in libmariadb
MYSQL_OPT_SSL_VERIFY_SERVER_CERT := 21; MYSQL_OPT_SSL_VERIFY_SERVER_CERT := 21;
MARIADB_OPT_TLS_VERSION := 7005; MARIADB_OPT_TLS_VERSION := 7005;
@ -3173,6 +3174,12 @@ begin
end; end;
end; end;
function TMySQLLib.IsLibMariadb: Boolean;
begin
// libmariadb used (not libmysql) ?
Result := ExtractFileName(FDllFile).StartsWith('libmariadb', True);
end;
procedure TMySQLLib.AssignProcedures; procedure TMySQLLib.AssignProcedures;
begin begin
AssignProc(@mysql_affected_rows, 'mysql_affected_rows'); AssignProc(@mysql_affected_rows, 'mysql_affected_rows');