mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2026-03-13 09:24:25 +08:00
Add basic support for pluggable authentication:
* Implement and export callback function "mysql_authentication_dialog_ask" * Update libmysql.dll to the one from MariaDB 5.2.10 * Copy dialog.dll from MariaDB into plugins subfolder * Modify installer so it creates the plugins folder and its dll files * Fixes issue #2658
This commit is contained in:
@@ -62,6 +62,7 @@ Source: "readme.txt"; DestDir: "{app}"; Flags: ignoreversion isreadme
|
||||
Source: "license.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "gpl.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "libmysql.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "plugins\*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion
|
||||
Source: "Snippets\*.sql"; DestDir: "{commonappdata}\{#ProgName}\Snippets";
|
||||
|
||||
[Icons]
|
||||
|
||||
BIN
out/libmysql.dll
BIN
out/libmysql.dll
Binary file not shown.
BIN
out/plugins/dialog.dll
Normal file
BIN
out/plugins/dialog.dll
Normal file
Binary file not shown.
@@ -166,6 +166,16 @@ type
|
||||
end;
|
||||
PMYSQL_RES = ^MYSQL_RES;
|
||||
|
||||
TMySQLOption = (MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE,
|
||||
MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP,
|
||||
MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE,
|
||||
MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT,
|
||||
MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
|
||||
MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
|
||||
MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
|
||||
MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
|
||||
MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH);
|
||||
|
||||
|
||||
{ TDBObjectList and friends }
|
||||
|
||||
@@ -448,6 +458,7 @@ type
|
||||
mysql_init: function(Handle: PMYSQL): PMYSQL; stdcall;
|
||||
mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall;
|
||||
mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall;
|
||||
mysql_options: function(Handle: PMYSQL; Option: TMySQLOption; arg: PAnsiChar): 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_query: function(Handle: PMYSQL; const Query: PAnsiChar; Length: Cardinal): Integer; stdcall;
|
||||
@@ -718,6 +729,17 @@ type
|
||||
function TableName: String; override;
|
||||
end;
|
||||
|
||||
function mysql_authentication_dialog_ask(
|
||||
Handle: PMYSQL;
|
||||
_type: Integer;
|
||||
prompt: PAnsiChar;
|
||||
buf: PAnsiChar;
|
||||
buf_len: Integer
|
||||
): PAnsiChar; cdecl;
|
||||
|
||||
exports
|
||||
mysql_authentication_dialog_ask;
|
||||
|
||||
const
|
||||
MsgSQLError: String = 'SQL Error (%d): %s';
|
||||
MsgUnhandledNetType: String = 'Unhandled connection type (%d)';
|
||||
@@ -990,6 +1012,7 @@ var
|
||||
StartupInfo: TStartupInfo;
|
||||
ExitCode: LongWord;
|
||||
sslca, sslkey, sslcert: PAnsiChar;
|
||||
PluginDir: AnsiString;
|
||||
DoSSL, SSLsettingsComplete: Boolean;
|
||||
Vars: TDBQuery;
|
||||
begin
|
||||
@@ -1079,6 +1102,10 @@ begin
|
||||
if FIsSSL then
|
||||
ClientFlags := ClientFlags or CLIENT_SSL;
|
||||
|
||||
// Point libmysql to the folder with client plugins
|
||||
PluginDir := AnsiString(ExtractFilePath(ParamStr(0))+'plugins\');
|
||||
mysql_options(FHandle, MYSQL_PLUGIN_DIR, PAnsiChar(PluginDir));
|
||||
|
||||
Connected := mysql_real_connect(
|
||||
FHandle,
|
||||
PAnsiChar(Utf8Encode(FinalHost)),
|
||||
@@ -1287,6 +1314,7 @@ begin
|
||||
AssignProc(@mysql_num_fields, 'mysql_num_fields');
|
||||
AssignProc(@mysql_num_rows, 'mysql_num_rows');
|
||||
AssignProc(@mysql_ping, 'mysql_ping');
|
||||
AssignProc(@mysql_options, 'mysql_options');
|
||||
AssignProc(@mysql_real_connect, 'mysql_real_connect');
|
||||
AssignProc(@mysql_real_query, 'mysql_real_query');
|
||||
AssignProc(@mysql_ssl_set, 'mysql_ssl_set');
|
||||
@@ -4734,4 +4762,46 @@ end;
|
||||
|
||||
|
||||
|
||||
function mysql_authentication_dialog_ask;
|
||||
var
|
||||
Username, Password: String;
|
||||
begin
|
||||
{
|
||||
From client_plugin.h:
|
||||
The C function with the name "mysql_authentication_dialog_ask", if exists,
|
||||
will be used by the "dialog" client authentication plugin when user
|
||||
input is needed. This function should be of mysql_authentication_dialog_ask_t
|
||||
type. If the function does not exists, a built-in implementation will be
|
||||
used.
|
||||
@param mysql mysql
|
||||
@param type type of the input
|
||||
1 - normal string input
|
||||
2 - password string
|
||||
@param prompt prompt
|
||||
@param buf a buffer to store the use input
|
||||
@param buf_len the length of the buffer
|
||||
@retval a pointer to the user input string.
|
||||
It may be equal to 'buf' or to 'mysql->password'.
|
||||
In all other cases it is assumed to be an allocated
|
||||
string, and the "dialog" plugin will free() it.
|
||||
Test suite:
|
||||
INSTALL PLUGIN three_attempts SONAME 'dialog.dll';
|
||||
CREATE USER test_dialog IDENTIFIED VIA three_attempts USING 'SECRET';
|
||||
}
|
||||
Username := '';
|
||||
Password := '';
|
||||
case _type of
|
||||
1: Username := String(buf);
|
||||
2: Password := String(buf);
|
||||
else raise EDatabaseError.Create('Unsupported type ('+IntToStr(_type)+') in mysql_authentication_dialog_ask.');
|
||||
end;
|
||||
LoginPrompt(String(prompt), Username, Password, _type=1, _type=2);
|
||||
Result := buf;
|
||||
case _type of
|
||||
1: Result := PAnsiChar(AnsiString(Username));
|
||||
2: Result := PAnsiChar(AnsiString(Password));
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
@@ -22,7 +22,7 @@ type
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
procedure LoginPrompt(ACaption: String; var AUsername, APassword: String);
|
||||
procedure LoginPrompt(ACaption: String; var AUsername, APassword: String; UsernameEnabled: Boolean=True; PasswordEnabled: Boolean=True);
|
||||
|
||||
implementation
|
||||
|
||||
@@ -31,7 +31,7 @@ uses helpers;
|
||||
{$R *.dfm}
|
||||
{$I const.inc}
|
||||
|
||||
procedure LoginPrompt(ACaption: String; var AUsername, APassword: String);
|
||||
procedure LoginPrompt(ACaption: String; var AUsername, APassword: String; UsernameEnabled: Boolean=True; PasswordEnabled: Boolean=True);
|
||||
var
|
||||
frm: TfrmLogin;
|
||||
begin
|
||||
@@ -40,6 +40,10 @@ begin
|
||||
frm.lblPrompt.Caption := ACaption;
|
||||
frm.editUsername.Text := AUsername;
|
||||
frm.editPassword.Text := APassword;
|
||||
frm.editUsername.Enabled := UsernameEnabled;
|
||||
frm.lblUsername.Enabled := UsernameEnabled;
|
||||
frm.editPassword.Enabled := PasswordEnabled;
|
||||
frm.lblPassword.Enabled := PasswordEnabled;
|
||||
frm.ShowModal;
|
||||
AUsername := frm.editUsername.Text;
|
||||
APassword := frm.editPassword.Text;
|
||||
@@ -55,9 +59,9 @@ end;
|
||||
|
||||
procedure TfrmLogin.FormShow(Sender: TObject);
|
||||
begin
|
||||
if (editUsername.GetTextLen > 0) and (editPassword.GetTextLen = 0) then
|
||||
if editPassword.CanFocus and (editUsername.GetTextLen > 0) and (editPassword.GetTextLen = 0) then
|
||||
editPassword.SetFocus
|
||||
else
|
||||
else if editUsername.CanFocus then
|
||||
editUsername.SetFocus;
|
||||
end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user