1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00

- mysql_load_plugin_v supports now the environment variable MARIADB_PLUGIN_DIR

to load plugins from a different destination than PLUGINDIR.

- added dialog plugin for authentication (e.g. PAM). If an application provides
  it's own dialog function, the name must be mariadb_auth_dialog (or for libmysql
  compatibility mysql_authentication_dialog_ask).
  Windows-Todo: 
  1. provide a simple GUI dialog on windows, in case opening the console failed.
  2. convert data from console code page to character set of current connection
This commit is contained in:
Georg Richter
2014-12-11 09:47:49 +01:00
parent 6bfad6e025
commit cd16280a3f
12 changed files with 344 additions and 50 deletions

View File

@@ -76,7 +76,7 @@ SET(BIN_INSTALL_DIR_DEFAULT "bin")
SET(LIB_INSTALL_DIR_DEFAULT "lib")
SET(INCLUDE_INSTALL_DIR_DEFAULT "include")
SET(DOCS_INSTALL_DIR_DEFAULT "docs")
SET(LIB_INSTALL_PLUGIN_DIR_DEFAULT "lib/plugins")
SET(PLUGIN_INSTALL_DIR_DEFAULT "lib/plugin")
#
# RPM layout
@@ -85,15 +85,15 @@ SET(SUFFIX_INSTALL_DIR_RPM "mariadb")
SET(BIN_INSTALL_DIR_RPM "bin")
IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
SET(LIB_INSTALL_DIR_RPM "lib64")
SET(LIB_INSTALL_PLUGINDIR_RPM "lib64/plugins")
SET(PLUGIN_INSTALL_DIRDIR_RPM "lib64/plugin")
ELSE()
SET(LIB_INSTALL_DIR_RPM "lib")
SET(LIB_INSTALL_PLUGINDIR_RPM "lib/plugins")
SET(PLUGIN_INSTALL_DIRDIR_RPM "lib/plugin")
ENDIF()
SET(INCLUDE_INSTALL_DIR_RPM "include")
SET(DOCS_INSTALL_DIR_RPM "docs")
SET(LIB_INSTALL_PLUGIN_DIR_RPM "lib/plugins")
SET(PLUGIN_INSTALL_DIR_RPM "lib/plugin")
#
# Overwrite defaults
@@ -102,6 +102,10 @@ IF(LIB_INSTALL_DIR)
SET(LIB_INSTALL_DIR_${INSTALL_LAYOUT} ${LIB_INSTALL_DIR})
ENDIF()
IF(PLUGIN_INSTALL_DIR)
SET(PLUGIN_INSTALL_DIR_${INSTALL_LAYOUT} ${PLUGIN_INSTALL_DIR})
ENDIF()
IF(INCLUDE_INSTALL_DIR)
SET(INCLUDE_INSTALL_DIR_${INSTALL_LAYOUT} ${INCLUDE_INSTALL_DIR})
ENDIF()
@@ -118,7 +122,7 @@ IF(NOT SUFFIX_INSTALL_DIR)
SET(SUFFIX_INSTALL_DIR_${INSTALL_LAYOUT} "mariadb")
ENDIF()
FOREACH(dir "BIN" "LIB" "INCLUDE" "DOCS" "PREFIX" "SUFFIX")
FOREACH(dir "BIN" "LIB" "INCLUDE" "DOCS" "PREFIX" "SUFFIX" "PLUGIN")
SET(${dir}_INSTALL_DIR ${${dir}_INSTALL_DIR_${INSTALL_LAYOUT}})
MARK_AS_ADVANCED(${dir}_INSTALL_DIR)
ENDFOREACH()

View File

@@ -274,5 +274,5 @@
#cmakedefine HAVE_THREADS 1
#cmakedefine SHAREDIR "@SHAREDIR@"
#cmakedefine DEFAULT_CHARSET_HOME "@DEFAULT_CHARSET_HOME@"
#cmakedefine PLUGINDIR "@PLUGINDIR@"
#cmakedefine PLUGINDIR "@PREFIX_INSTALL_DIR@/@PLUGIN_INSTALL_DIR@"

View File

@@ -1,4 +1,5 @@
/* Copyright (C) 2010 - 2012 Sergei Golubchik and Monty Program Ab
2014 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public

View File

@@ -175,6 +175,7 @@ enum enum_server_command
CLIENT_PROGRESS |\
CLIENT_SSL_VERIFY_SERVER_CERT |\
CLIENT_REMEMBER_OPTIONS |\
CLIENT_PLUGIN_AUTH |\
CLIENT_CONNECT_ATTRS)
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD |\
@@ -384,7 +385,6 @@ char *scramble_323(char *to,const char *message,const char *password);
void my_scramble_41(const unsigned char *buffer, const char *scramble, const char *password);
my_bool check_scramble(const char *, const char *message,
unsigned long *salt,my_bool old_ver);
char *get_tty_password(char *opt_message);
void hash_password(unsigned long *result, const char *password, size_t len);
/* Some other useful functions */

View File

@@ -346,6 +346,7 @@ mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
char dlpath[FN_REFLEN+1];
void *sym, *dlhandle;
struct st_mysql_client_plugin *plugin;
char *env_plugin_dir= getenv("MARIADB_PLUGIN_DIR");
if (is_not_initialized(mysql, name))
return NULL;
@@ -362,7 +363,8 @@ mysql_load_plugin_v(MYSQL *mysql, const char *name, int type,
/* Compile dll path */
strxnmov(dlpath, sizeof(dlpath) - 1,
mysql->options.extension && mysql->options.extension->plugin_dir ?
mysql->options.extension->plugin_dir : PLUGINDIR, "/",
mysql->options.extension->plugin_dir : (env_plugin_dir) ? env_plugin_dir :
PLUGINDIR, "/",
name, SO_EXT, NullS);
/* Open new dll handle */

View File

@@ -63,42 +63,82 @@
#endif
#if defined( _WIN32) || defined(OS2)
/* were just going to fake it here and get input from the keyboard */
/* {{{ statuc char* get_password */
/*
reads password from tty/console
char *get_tty_password(char *opt_message)
SYNOPSIS
get_password()
buffer input buffer
length length of input buffer
DESCRIPTION
reads a password from console (Windows) or tty without echoing
it's characters. Input buffer must be allocated by calling function.
RETURNS
buffer pointer to input buffer
*/
char* get_tty_password(char *prompt, char *buffer, int length)
{
char to[80];
char *pos=to,*end=to+sizeof(to)-1;
int i=0;
DBUG_ENTER("get_tty_password");
fprintf(stdout,opt_message ? opt_message : "Enter password: ");
for (;;)
#ifdef _WIN32
DWORD SaveState;
HANDLE Hdl;
int Offset= 0;
DWORD CharsProcessed= 0;
char inChar;
ZeroMemory(buffer, length);
if (!(Hdl= CreateFile("CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING, 0, NULL)))
{
char tmp;
tmp=_getch();
if (tmp == '\b' || (int) tmp == 127)
{
if (pos != to)
{
_cputs("\b \b");
pos--;
continue;
/* todo: provide a graphical dialog */
return buffer;
}
}
if (tmp == '\n' || tmp == '\r' || tmp == 3)
/* Save ConsoleMode and set ENABLE_PROCESSED_INPUT:
CTRL+C is processed by the system and is not placed in the input buffer */
GetConsoleMode(Hdl, &SaveState);
SetConsoleMode(Hdl, ENABLE_PROCESSED_INPUT);
do
{
if (!ReadConsole(Hdl, &inChar, 1, &CharsProcessed, NULL) ||
!CharsProcessed)
break;
if (iscntrl(tmp) || pos == end)
continue;
_cputs("*");
*(pos++) = tmp;
}
while (pos != to && isspace(pos[-1]) == ' ')
pos--; /* Allow dummy space at end */
*pos=0;
_cputs("\n");
DBUG_RETURN(my_strdup(to,MYF(MY_FAE)));
}
switch(inChar) {
case '\b': /* backslash */
if (Offset)
{
/* cursor is always at the end */
Offset--;
buffer[Offset]= 0;
_cputs("\b \b");
}
break;
case '\n':
case '\r':
break;
default:
buffer[Offset]= inChar;
if (Offset < length - 2)
Offset++;
_cputs("*");
break;
}
} while (CharsProcessed && inChar != '\n' && inChar != '\r');
SetConsoleMode(Hdl, SaveState);
CloseHandle(Hdl);
return buffer;
#else
#endif
}
/* }}} */
#else
@@ -150,14 +190,13 @@ static void get_password(char *to,uint length,int fd,bool echo)
#endif /* ! HAVE_GETPASS */
char *get_tty_password(char *opt_message)
char *get_tty_password(char *opt_message, char *buff, int bufflen)
{
#ifdef HAVE_GETPASS
char *passbuff;
#else /* ! HAVE_GETPASS */
TERMIO org,tmp;
#endif /* HAVE_GETPASS */
char buff[80];
DBUG_ENTER("get_tty_password");
@@ -165,7 +204,7 @@ char *get_tty_password(char *opt_message)
passbuff = getpass(opt_message ? opt_message : "Enter password: ");
/* copy the password to buff and clear original (static) buffer */
strnmov(buff, passbuff, sizeof(buff) - 1);
strnmov(buff, passbuff, bufflen - 1);
#ifdef _PASSWORD_LEN
memset(passbuff, 0, _PASSWORD_LEN);
#endif
@@ -182,7 +221,7 @@ char *get_tty_password(char *opt_message)
tmp.c_cc[VMIN] = 1;
tmp.c_cc[VTIME] = 0;
tcsetattr(fileno(stdin), TCSADRAIN, &tmp);
get_password(buff, sizeof(buff)-1, fileno(stdin), isatty(fileno(stdout)));
get_password(buff, bufflen-1, fileno(stdin), isatty(fileno(stdout)));
tcsetattr(fileno(stdin), TCSADRAIN, &org);
#elif defined(HAVE_TERMIO_H)
ioctl(fileno(stdin), (int) TCGETA, &org);
@@ -191,7 +230,7 @@ char *get_tty_password(char *opt_message)
tmp.c_cc[VMIN] = 1;
tmp.c_cc[VTIME]= 0;
ioctl(fileno(stdin),(int) TCSETA, &tmp);
get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
get_password(buff,bufflen-1,fileno(stdin),isatty(fileno(stdout)));
ioctl(fileno(stdin),(int) TCSETA, &org);
#else
gtty(fileno(stdin), &org);
@@ -199,13 +238,13 @@ char *get_tty_password(char *opt_message)
tmp.sg_flags &= ~ECHO;
tmp.sg_flags |= RAW;
stty(fileno(stdin), &tmp);
get_password(buff,sizeof(buff)-1,fileno(stdin),isatty(fileno(stdout)));
get_password(buff,bufflen-1,fileno(stdin),isatty(fileno(stdout)));
stty(fileno(stdin), &org);
#endif
if (isatty(fileno(stdout)))
fputc('\n',stdout);
#endif /* HAVE_GETPASS */
DBUG_RETURN(my_strdup(buff,MYF(MY_FAE)));
DBUG_RETURN(buff);
}
#endif /*_WIN32*/

View File

@@ -8,6 +8,7 @@
"@extra_dynamic_LDFLAGS@"
#define CFLAGS INCLUDE " @CMAKE_C_FLAGS@"
#define VERSION "@MYSQL_CLIENT_VERSION@"
#define PLUGIN_DIR "@PREFIX_INSTALL_DIR@/@PLUGIN_INSTALL_DIR@"
#define SOCKET "@MYSQL_UNIX_ADDR@"
#define PORT "@MYSQL_PORT@"
@@ -21,6 +22,7 @@ static struct option long_options[]=
{"version", no_argument, 0, 'f'},
{"socket", no_argument, 0, 'g'},
{"port", no_argument, 0, 'h'},
{"plugindir", no_argument, 0, 'p'},
{NULL, 0, 0, 0}
};
@@ -33,7 +35,8 @@ static char *values[]=
LIBS,
VERSION,
SOCKET,
PORT
PORT,
PLUGIN_DIR
};
void usage(void)
@@ -90,6 +93,9 @@ int main(int argc, char **argv)
case 'h':
puts(PORT);
break;
case 'p':
puts(PLUGINDIR);
break;
default:
exit(0);
}

View File

@@ -0,0 +1,13 @@
# Dialog plugin
SET(DIALOG_SOURCES dialog.c ${CMAKE_SOURCE_DIR}/libmariadb/get_password.c)
IF(WIN32)
SET(DIALOG_SOURCES ${DIALOG_SOURCES} ${CMAKE_SOURCE_DIR}/plugins/plugin.def)
ENDIF()
ADD_LIBRARY(dialog SHARED ${DIALOG_SOURCES})
SET_TARGET_PROPERTIES(dialog PROPERTIES PREFIX "")
INSTALL(TARGETS
dialog
RUNTIME DESTINATION "${PLUGIN_INSTALL_DIR}"
LIBRARY DESTINATION "${PLUGIN_INSTALL_DIR}"
ARCHIVE DESTINATION "${PLUGIN_INSTALL_DIR}")

218
plugins/auth/dialog.c Normal file
View File

@@ -0,0 +1,218 @@
/************************************************************************************
Copyright (C) 2014 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
Part of this code includes code from the PHP project which
is freely available from http://www.php.net
*************************************************************************************/
#ifndef _WIN32
#define _GNU_SOURCE 1
#endif
#include <my_global.h>
#include <mysql.h>
#include <mysql/client_plugin.h>
#include <string.h>
#include <memory.h>
#ifndef WIN32
#include <dlfcn.h>
#endif
/* function prototypes */
extern char *get_tty_password(char *opt_message, char *buff, int bufflen);
static int auth_dialog_open(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
static int auth_dialog_init(char *unused1,
size_t unused2,
int unused3,
va_list);
mysql_authentication_dialog_ask_t auth_dialog_func;
mysql_declare_client_plugin(AUTHENTICATION)
"dialog",
"Sergei Golubchik, Georg Richter",
"Dialog Client Authentication Plugin",
{0,1,0},
auth_dialog_init,
NULL,
auth_dialog_open
mysql_end_client_plugin;
/* {{{ static char *auth_dialog_native_prompt */
/*
Native dialog prompt via stdin
SYNOPSIS
auth_dialog_native_prompt
mysql connection handle
type input type
prompt prompt
buffer Input buffer
buffer_len Input buffer length
DESCRIPTION
RETURNS
Input buffer
*/
static char *auth_dialog_native_prompt(MYSQL *mysql,
int type,
const char *prompt,
char *buffer,
int buffer_len)
{
/* display prompt */
fprintf(stdout, "%s", prompt);
memset(buffer, 0, buffer_len);
/* for type 2 (password) don't display input */
if (type != 2)
{
if (fgets(buffer, buffer_len - 1, stdin))
{
/* remove trailing line break */
size_t length= strlen(buffer);
if (length && buffer[length - 1] == '\n')
buffer[length - 1]= 0;
}
}
else
{
get_tty_password("", buffer, buffer_len - 1);
}
return buffer;
}
/* }}} */
/* {{{ static int auth_dialog_open */
/*
opens dialog
SYNOPSIS
vio Vio
mysql connection handle
DESCRIPTION
reads prompt from server, waits for input and sends
input to server.
Note that first byte of prompt indicates if we have a
password which should not be echoed to stdout.
RETURN
CR_ERROR if an error occurs
CR_OK
CR_OK_HANDSHAKE_COMPLETE
*/
static int auth_dialog_open(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
{
uchar *packet;
uchar type;
char dialog_buffer[1024];
char *response;
size_t packet_length;
my_bool first_loop= TRUE;
do {
if ((packet_length= vio->read_packet(vio, &packet)) < 0)
/* read error */
return CR_ERROR;
if (packet_length > 0)
{
type= *packet;
packet++;
/* check for protocol packet */
if (!type || type == 254)
return CR_OK_HANDSHAKE_COMPLETE;
/* shift one bit */
type= type >> 1;
if (type == 2 &&
first_loop &&
mysql->passwd && mysql->passwd[0])
response= mysql->passwd;
else
response= auth_dialog_func(mysql, type,
(const char *)packet,
dialog_buffer, 1024);
}
else
{
/* in case mysql_change_user was called the client needs
to send packet first */
response= mysql->passwd;
}
if (!response ||
vio->write_packet(vio, response, strlen(response) + 1))
return CR_ERROR;
first_loop= FALSE;
} while(type != 2);
return CR_OK;
}
/* }}} */
/* {{{ static int auth_dialog_init */
/*
Initialization routine
SYNOPSIS
auth_dialog_init
unused1
unused2
unused3
unused4
DESCRIPTION
Init function checks if the caller provides own dialog function.
The function name must be mariadb_auth_dialog or
mysql_authentication_dialog_ask. If the function cannot be found,
we will use owr own simple command line input.
RETURN
0 success
*/
static int auth_dialog_init(char *unused1 __attribute__((unused)),
size_t unused2 __attribute__((unused)),
int unused3 __attribute__((unused)),
va_list unused4 __attribute__((unused)))
{
void *func;
#ifdef WIN32
if (!(func= GetProcAddress(GetModuleHandle(NULL), "mariadb_auth_dialog")))
/* for MySQL users */
func= GetProcAddress(GetModuleHandle(NULL), "mysql_authentication_dialog_ask");
#else
if (!(func= dlsym(RTLD_DEFAULT, "mariadb_auth_dialog")))
/* for MySQL users */
func= dlsym(RTLD_DEFAULT, "mysql_authentication_dialog_ask");
#endif
if (func)
auth_dialog_func= (mysql_authentication_dialog_ask_t)func;
else
auth_dialog_func= auth_dialog_native_prompt;
return 0;
}
/* }}} */

2
plugins/plugin.def Normal file
View File

@@ -0,0 +1,2 @@
EXPORTS
_mysql_client_plugin_declaration_ DATA

View File

@@ -38,8 +38,13 @@ IF (WITH_SIGNCODE)
COMMAND signtool sign ${SIGN_OPTIONS} ${CLIENT_DBG_DIR}/libmariadb.lib)
EXECUTE_PROCESS(
COMMAND signtool sign ${SIGN_OPTIONS} ${CLIENT_DBG_DIR}/mariadbclient.lib)
EXECUTE_PROCESS(
COMMAND signtool sign ${SIGN_OPTIONS} ${CMAKE_BINARY_DIR}/plugins/auth/${CMAKE_BUILD_TYPE}/dialog.dll)
ENDIF()
SET(MARIADB_PLUGINS "${MARIADB_PLUGINS} <File Id=\"dialog.dll\" Name=\"dialog.dll\" DiskId=\"1\" Source=\"${CMAKE_BINARY_DIR}/plugins/auth/${CMAKE_BUILD_TYPE}/dialog.dll\"/>\n")
FOREACH(src ${MARIADB_CLIENT_INCLUDES})
STRING(REPLACE "-" "_" src_id ${src})
SET(MARIADB_INCLUDE_FILES "${MARIADB_INCLUDE_FILES} <File Id=\"${src_id}\" Name=\"${src}\" DiskId=\"1\" Source=\"${CMAKE_SOURCE_DIR}/include/${src}\"/>\n")

View File

@@ -33,6 +33,7 @@
<Directory Id="INSTALLFOLDER" Name="@PRODUCT_NAME@" >
<Directory Id="instlib" Name="lib">
<Directory Id="instlib_debug" Name="debug"/>
<Directory Id="instlib_plugin" Name="plugin"/>
</Directory>
<Directory Id="instinclude" Name="include" />
</Directory>
@@ -58,6 +59,9 @@
<File Id="dlibdllimp" Name="libmariadb.lib" DiskId="1" Source="@CLIENT_DBG_DIR@/libmariadb.lib" />
<File Id="dlibstatic" Name="mariadbclient.lib" DiskId="1" Source="@CLIENT_DBG_DIR@/mariadbclient.lib" />
</Component>
<Component Id="Plugins" Guid="" KeyPath="yes" DiskId="1" Directory="instlib_plugin" Win64="@IS_WIN64@">
@MARIADB_PLUGINS@
</Component>
<Component Id="Debug" Guid="FFAFCCCC-4E0C-4A87-840C-53B63C8A427A" KeyPath="yes" Directory="instlib" DiskId="1" Win64="@IS_WIN64@">
<File Id="libdllpdb" Name="libmariadb.pdb" DiskId="1" Source="@CLIENT_LIB_DIR@/libmariadb.pdb" />
<File Id="libstaticpdb" Name="mariadbclient.pdb" DiskId="1" Source="@CLIENT_LIB_DIR@/mariadbclient.pdb" />