Browse Source
pluggable auth with plugin examples
pluggable auth with plugin examples
Makefile.am: add new API files to the check_abi rule, remove duplicates client/CMakeLists.txt: now a client can use dlopen too client/Makefile.am: be csh-friendly include/my_global.h: add dummy plugs for dlopen and co. for the code that needs them to work in static builds mysys/Makefile.am: be csh-friendly plugin/auth/dialog.c: typo fixedpull/843/head
81 changed files with 4440 additions and 1504 deletions
-
3.bzrignore
-
11Makefile.am
-
2client/CMakeLists.txt
-
4client/Makefile.am
-
4client/client_priv.h
-
65client/mysql.cc
-
3configure.in
-
4include/Makefile.am
-
3include/errmsg.h
-
14include/my_global.h
-
1include/my_no_pthread.h
-
6include/my_sys.h
-
54include/mysql.h
-
37include/mysql.h.pp
-
164include/mysql/client_plugin.h
-
41include/mysql/client_plugin.h.pp
-
5include/mysql/plugin.h
-
83include/mysql/plugin_auth.h
-
30include/mysql/plugin_auth.h.pp
-
105include/mysql/plugin_auth_common.h
-
15include/mysql_com.h
-
65include/sql_common.h
-
3libmysql/CMakeLists.txt
-
14libmysql/Makefile.shared
-
5libmysql/client_settings.h
-
3libmysql/errmsg.c
-
101libmysql/libmysql.c
-
10libmysqld/Makefile.am
-
2libmysqld/embedded_priv.h
-
71libmysqld/lib_sql.cc
-
14libmysqld/libmysqld.c
-
33mysql-test/r/change_user.result
-
7mysql-test/r/grant.result
-
2mysql-test/r/grant2.result
-
6mysql-test/r/ps.result
-
2mysql-test/r/sp_notembedded.result
-
2mysql-test/r/system_mysql_db.result
-
5mysql-test/suite/funcs_1/r/is_columns_mysql.result
-
22mysql-test/suite/funcs_1/r/is_user_privileges.result
-
7mysql-test/suite/pbxt/r/grant.result
-
1mysql-test/suite/rpl/r/rpl_ignore_table.result
-
1mysql-test/suite/rpl/r/rpl_stm_000001.result
-
46mysql-test/t/change_user.test
-
10mysys/Makefile.am
-
15plugin/auth/Makefile.am
-
102plugin/auth/auth_socket.c
-
302plugin/auth/dialog.c
-
15plugin/auth/plug.in
-
2scripts/mysql_system_tables.sql
-
6scripts/mysql_system_tables_data.sql
-
3scripts/mysql_system_tables_fix.sql
-
5server-tools/instance-manager/Makefile.am
-
2server-tools/instance-manager/user_map.cc
-
2sql-common/Makefile.am
-
1102sql-common/client.c
-
436sql-common/client_plugin.c
-
2sql/CMakeLists.txt
-
12sql/Makefile.am
-
4sql/client_settings.h
-
2sql/ha_ndbcluster.cc
-
2sql/ha_ndbcluster_binlog.cc
-
1sql/lex.h
-
6sql/mysql_priv.h
-
3sql/mysqld.cc
-
12sql/password.c
-
18sql/protocol.cc
-
1sql/protocol.h
-
1941sql/sql_acl.cc
-
52sql/sql_acl.h
-
4sql/sql_builtin.cc.in
-
20sql/sql_class.cc
-
3sql/sql_class.h
-
454sql/sql_connect.cc
-
4sql/sql_insert.cc
-
2sql/sql_lex.h
-
114sql/sql_parse.cc
-
23sql/sql_plugin.cc
-
22sql/sql_yacc.yy
-
2sql/structs.h
-
7sql/table.cc
-
1tests/mysql_client_test.c
@ -0,0 +1,164 @@ |
|||
#ifndef MYSQL_CLIENT_PLUGIN_INCLUDED |
|||
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
/** |
|||
@file |
|||
|
|||
MySQL Client Plugin API |
|||
|
|||
This file defines the API for plugins that work on the client side |
|||
*/ |
|||
#define MYSQL_CLIENT_PLUGIN_INCLUDED |
|||
|
|||
#include <stdarg.h> |
|||
#include <stdlib.h> |
|||
|
|||
/* known plugin types */ |
|||
#define MYSQL_CLIENT_reserved1 0 |
|||
#define MYSQL_CLIENT_reserved2 1 |
|||
#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 |
|||
|
|||
#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 |
|||
|
|||
#define MYSQL_CLIENT_MAX_PLUGINS 3 |
|||
|
|||
#define mysql_declare_client_plugin(X) \ |
|||
struct st_mysql_client_plugin_ ## X \ |
|||
_mysql_client_plugin_declaration_ = { \ |
|||
MYSQL_CLIENT_ ## X ## _PLUGIN, \ |
|||
MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION, |
|||
#define mysql_end_client_plugin } |
|||
|
|||
/* generic plugin header structure */ |
|||
#define MYSQL_CLIENT_PLUGIN_HEADER \ |
|||
int type; \ |
|||
unsigned int interface_version; \ |
|||
const char *name; \ |
|||
const char *author; \ |
|||
const char *desc; \ |
|||
unsigned int version[3]; \ |
|||
int (*init)(char *, size_t, int, va_list); \ |
|||
int (*deinit)(); |
|||
|
|||
struct st_mysql_client_plugin |
|||
{ |
|||
MYSQL_CLIENT_PLUGIN_HEADER |
|||
}; |
|||
|
|||
struct st_mysql; |
|||
|
|||
/******** authentication plugin specific declarations *********/ |
|||
#include <mysql/plugin_auth_common.h> |
|||
|
|||
struct st_mysql_client_plugin_AUTHENTICATION |
|||
{ |
|||
MYSQL_CLIENT_PLUGIN_HEADER |
|||
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); |
|||
}; |
|||
|
|||
/** |
|||
type of the mysql_authentication_dialog_ask function |
|||
|
|||
@param mysql mysql |
|||
@param type type of the input |
|||
1 - ordinary 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. |
|||
*/ |
|||
typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, |
|||
int type, const char *prompt, char *buf, int buf_len); |
|||
/******** using plugins ************/ |
|||
|
|||
/** |
|||
loads a plugin and initializes it |
|||
|
|||
@param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used, |
|||
and last_errno/last_error, for error reporting |
|||
@param name a name of the plugin to load |
|||
@param type type of plugin that should be loaded, -1 to disable type check |
|||
@param argc number of arguments to pass to the plugin initialization |
|||
function |
|||
@param ... arguments for the plugin initialization function |
|||
|
|||
@retval |
|||
a pointer to the loaded plugin, or NULL in case of a failure |
|||
*/ |
|||
struct st_mysql_client_plugin * |
|||
mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, |
|||
int argc, ...); |
|||
|
|||
/** |
|||
loads a plugin and initializes it, taking va_list as an argument |
|||
|
|||
This is the same as mysql_load_plugin, but take va_list instead of |
|||
a list of arguments. |
|||
|
|||
@param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used, |
|||
and last_errno/last_error, for error reporting |
|||
@param name a name of the plugin to load |
|||
@param type type of plugin that should be loaded, -1 to disable type check |
|||
@param argc number of arguments to pass to the plugin initialization |
|||
function |
|||
@param args arguments for the plugin initialization function |
|||
|
|||
@retval |
|||
a pointer to the loaded plugin, or NULL in case of a failure |
|||
*/ |
|||
struct st_mysql_client_plugin * |
|||
mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, |
|||
int argc, va_list args); |
|||
|
|||
/** |
|||
finds an already loaded plugin by name, or loads it, if necessary |
|||
|
|||
@param mysql MYSQL structure. only MYSQL_PLUGIN_DIR option value is used, |
|||
and last_errno/last_error, for error reporting |
|||
@param name a name of the plugin to load |
|||
@param type type of plugin that should be loaded |
|||
|
|||
@retval |
|||
a pointer to the plugin, or NULL in case of a failure |
|||
*/ |
|||
struct st_mysql_client_plugin * |
|||
mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); |
|||
|
|||
/** |
|||
adds a plugin structure to the list of loaded plugins |
|||
|
|||
This is useful if an application has the necessary functionality |
|||
(for example, a special load data handler) statically linked into |
|||
the application binary. It can use this function to register the plugin |
|||
directly, avoiding the need to factor it out into a shared object. |
|||
|
|||
@param mysql MYSQL structure. It is only used for error reporting |
|||
@param plugin an st_mysql_client_plugin structure to register |
|||
|
|||
@retval |
|||
a pointer to the plugin, or NULL in case of a failure |
|||
*/ |
|||
struct st_mysql_client_plugin * |
|||
mysql_client_register_plugin(struct st_mysql *mysql, |
|||
struct st_mysql_client_plugin *plugin); |
|||
|
|||
#endif |
|||
|
|||
@ -0,0 +1,41 @@ |
|||
#include <stdarg.h> |
|||
#include <stdlib.h> |
|||
struct st_mysql_client_plugin |
|||
{ |
|||
int type; unsigned int interface_version; const char *name; const char *author; const char *desc; unsigned int version[3]; int (*init)(char *, size_t, int, va_list); int (*deinit)(); |
|||
}; |
|||
struct st_mysql; |
|||
#include <mysql/plugin_auth_common.h> |
|||
typedef struct st_plugin_vio_info |
|||
{ |
|||
enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, |
|||
MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; |
|||
int socket; |
|||
} MYSQL_PLUGIN_VIO_INFO; |
|||
typedef struct st_plugin_vio |
|||
{ |
|||
int (*read_packet)(struct st_plugin_vio *vio, |
|||
unsigned char **buf); |
|||
int (*write_packet)(struct st_plugin_vio *vio, |
|||
const unsigned char *packet, |
|||
int packet_len); |
|||
void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); |
|||
} MYSQL_PLUGIN_VIO; |
|||
struct st_mysql_client_plugin_AUTHENTICATION |
|||
{ |
|||
int type; unsigned int interface_version; const char *name; const char *author; const char *desc; unsigned int version[3]; int (*init)(char *, size_t, int, va_list); int (*deinit)(); |
|||
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); |
|||
}; |
|||
typedef char *(*mysql_authentication_dialog_ask_t)(struct st_mysql *mysql, |
|||
int type, const char *prompt, char *buf, int buf_len); |
|||
struct st_mysql_client_plugin * |
|||
mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, |
|||
int argc, ...); |
|||
struct st_mysql_client_plugin * |
|||
mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, |
|||
int argc, va_list args); |
|||
struct st_mysql_client_plugin * |
|||
mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); |
|||
struct st_mysql_client_plugin * |
|||
mysql_client_register_plugin(struct st_mysql *mysql, |
|||
struct st_mysql_client_plugin *plugin); |
|||
@ -0,0 +1,83 @@ |
|||
#ifndef MYSQL_PLUGIN_AUTH_INCLUDED |
|||
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
/** |
|||
@file |
|||
|
|||
Authentication Plugin API. |
|||
|
|||
This file defines the API for server authentication plugins. |
|||
*/ |
|||
|
|||
#define MYSQL_PLUGIN_AUTH_INCLUDED |
|||
|
|||
#include <mysql/plugin.h> |
|||
|
|||
#define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0100 |
|||
|
|||
#include <mysql/plugin_auth_common.h> |
|||
|
|||
/** |
|||
Provides server plugin access to authentication information |
|||
*/ |
|||
typedef struct st_mysql_server_auth_info |
|||
{ |
|||
/** |
|||
User name as sent by the client and shown in USER(). |
|||
NULL if the client packet with the user name was not received yet. |
|||
*/ |
|||
const char *user_name; |
|||
/** |
|||
A corresponding column value from the mysql.user table for the |
|||
matching account name |
|||
*/ |
|||
const char *auth_string; |
|||
|
|||
/** |
|||
Matching account name as found in the mysql.user table. |
|||
A plugin can override it with another name that will be |
|||
used by MySQL for authorization, and shown in CURRENT_USER() |
|||
*/ |
|||
char authenticated_as[MYSQL_USERNAME_LENGTH+1]; |
|||
/** |
|||
This only affects the "Authentication failed. Password used: %s" |
|||
error message. If set, %s will be YES, otherwise - NO. |
|||
Set it as appropriate or ignore at will. |
|||
*/ |
|||
int password_used; |
|||
} MYSQL_SERVER_AUTH_INFO; |
|||
|
|||
/** |
|||
Server authentication plugin descriptor |
|||
*/ |
|||
struct st_mysql_auth |
|||
{ |
|||
int interface_version; /**< version plugin uses */ |
|||
/** |
|||
A plugin that a client must use for authentication with this server |
|||
plugin. Can be NULL to mean "any plugin". |
|||
*/ |
|||
const char *client_auth_plugin; |
|||
/** |
|||
Function provided by the plugin which should perform authentication (using |
|||
the vio functions if necessary) and return 0 if successful. The plugin can |
|||
also fill the info.authenticated_as field if a different username should be |
|||
used for authorization. |
|||
*/ |
|||
int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info); |
|||
}; |
|||
#endif |
|||
|
|||
@ -0,0 +1,105 @@ |
|||
#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED |
|||
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
/** |
|||
@file |
|||
|
|||
This file defines constants and data structures that are the same for |
|||
both client- and server-side authentication plugins. |
|||
*/ |
|||
#define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED |
|||
|
|||
/** the max allowed length for a user name */ |
|||
#define MYSQL_USERNAME_LENGTH 48 |
|||
|
|||
/** |
|||
return values of the plugin authenticate_user() method. |
|||
*/ |
|||
|
|||
/** |
|||
Authentication failed. Additionally, all other CR_xxx values |
|||
(libmysql error code) can be used too. |
|||
|
|||
The client plugin may set the error code and the error message directly |
|||
in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error |
|||
code was returned, an error message in the MYSQL structure will be |
|||
overwritten. If CR_ERROR is returned without setting the error in MYSQL, |
|||
CR_UNKNOWN_ERROR will be user. |
|||
*/ |
|||
#define CR_ERROR 0 |
|||
/** |
|||
Authentication (client part) was successful. It does not mean that the |
|||
authentication as a whole was successful, usually it only means |
|||
that the client was able to send the user name and the password to the |
|||
server. If CR_OK is returned, the libmysql reads the next packet expecting |
|||
it to be one of OK, ERROR, or CHANGE_PLUGIN packets. |
|||
*/ |
|||
#define CR_OK -1 |
|||
/** |
|||
Authentication was successful. |
|||
It means that the client has done its part successfully and also that |
|||
a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN). |
|||
In this case, libmysql will not read a packet from the server, |
|||
but it will use the data at mysql->net.read_pos. |
|||
|
|||
A plugin may return this value if the number of roundtrips in the |
|||
authentication protocol is not known in advance, and the client plugin |
|||
needs to read one packet more to determine if the authentication is finished |
|||
or not. |
|||
*/ |
|||
#define CR_OK_HANDSHAKE_COMPLETE -2 |
|||
|
|||
typedef struct st_plugin_vio_info |
|||
{ |
|||
enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, |
|||
MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; |
|||
int socket; /**< it's set, if the protocol is SOCKET or TCP */ |
|||
#ifdef _WIN32 |
|||
HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */ |
|||
#endif |
|||
} MYSQL_PLUGIN_VIO_INFO; |
|||
|
|||
/** |
|||
Provides plugin access to communication channel |
|||
*/ |
|||
typedef struct st_plugin_vio |
|||
{ |
|||
/** |
|||
Plugin provides a pointer reference and this function sets it to the |
|||
contents of any incoming packet. Returns the packet length, or -1 if |
|||
the plugin should terminate. |
|||
*/ |
|||
int (*read_packet)(struct st_plugin_vio *vio, |
|||
unsigned char **buf); |
|||
|
|||
/** |
|||
Plugin provides a buffer with data and the length and this |
|||
function sends it as a packet. Returns 0 on success, 1 on failure. |
|||
*/ |
|||
int (*write_packet)(struct st_plugin_vio *vio, |
|||
const unsigned char *packet, |
|||
int packet_len); |
|||
|
|||
/** |
|||
Fills in a st_plugin_vio_info structure, providing the information |
|||
about the connection. |
|||
*/ |
|||
void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); |
|||
|
|||
} MYSQL_PLUGIN_VIO; |
|||
|
|||
#endif |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
pkgplugindir=$(pkglibdir)/plugin |
|||
|
|||
AM_LDFLAGS=-module -rpath $(pkgplugindir) |
|||
AM_CPPFLAGS=-DMYSQL_DYNAMIC_PLUGIN -I$(top_srcdir)/include |
|||
|
|||
pkgplugin_LTLIBRARIES= dialog.la |
|||
dialog_la_SOURCES= dialog.c |
|||
|
|||
if HAVE_PEERCRED |
|||
pkgplugin_LTLIBRARIES+= auth_socket.la |
|||
auth_socket_la_SOURCES= auth_socket.c |
|||
endif |
|||
|
|||
EXTRA_DIST= plug.in |
|||
|
|||
@ -0,0 +1,102 @@ |
|||
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
/** |
|||
@file |
|||
|
|||
socket_peercred authentication plugin. |
|||
|
|||
Authentication is successful if the connection is done via a unix socket and |
|||
the owner of the client process matches the user name that was used when |
|||
connecting to mysqld. |
|||
*/ |
|||
#define _GNU_SOURCE /* for struct ucred */ |
|||
|
|||
#include <mysql/plugin_auth.h> |
|||
#include <sys/socket.h> |
|||
#include <pwd.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
perform the unix socket based authentication |
|||
|
|||
This authentication callback performs a unix socket based authentication - |
|||
it gets the uid of the client process and considers the user authenticated |
|||
if it uses username of this uid. That is - if the user is already |
|||
authenticated to the OS (if she is logged in) - she can use MySQL as herself |
|||
*/ |
|||
|
|||
static int socket_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) |
|||
{ |
|||
unsigned char *pkt; |
|||
MYSQL_PLUGIN_VIO_INFO vio_info; |
|||
struct ucred cred; |
|||
socklen_t cred_len= sizeof(cred); |
|||
struct passwd pwd_buf, *pwd; |
|||
char buf[1024]; |
|||
|
|||
/* no user name yet ? read the client handshake packet with the user name */ |
|||
if (info->user_name == 0) |
|||
{ |
|||
if (vio->read_packet(vio, &pkt) < 0) |
|||
return CR_ERROR; |
|||
} |
|||
|
|||
info->password_used = 0; |
|||
|
|||
vio->info(vio, &vio_info); |
|||
if (vio_info.protocol != MYSQL_VIO_SOCKET) |
|||
return CR_ERROR; |
|||
|
|||
/* get the UID of the client process */ |
|||
if (getsockopt(vio_info.socket, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len)) |
|||
return CR_ERROR; |
|||
|
|||
if (cred_len != sizeof(cred)) |
|||
return CR_ERROR; |
|||
|
|||
/* and find the username for this uid */ |
|||
getpwuid_r(cred.uid, &pwd_buf, buf, sizeof(buf), &pwd); |
|||
if (pwd == NULL) |
|||
return CR_ERROR; |
|||
|
|||
/* now it's simple as that */ |
|||
return strcmp(pwd->pw_name, info->user_name) ? CR_ERROR : CR_OK; |
|||
} |
|||
|
|||
static struct st_mysql_auth socket_auth_handler= |
|||
{ |
|||
MYSQL_AUTHENTICATION_INTERFACE_VERSION, |
|||
0, |
|||
socket_auth |
|||
}; |
|||
|
|||
mysql_declare_plugin(socket_auth) |
|||
{ |
|||
MYSQL_AUTHENTICATION_PLUGIN, |
|||
&socket_auth_handler, |
|||
"socket_peercred", |
|||
"Sergei Golubchik", |
|||
"Unix Socket based authentication", |
|||
PLUGIN_LICENSE_GPL, |
|||
NULL, |
|||
NULL, |
|||
0x0100, |
|||
NULL, |
|||
NULL, |
|||
NULL |
|||
} |
|||
mysql_declare_plugin_end; |
|||
|
|||
@ -0,0 +1,302 @@ |
|||
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
/** |
|||
@file |
|||
|
|||
dialog client authentication plugin with examples |
|||
|
|||
dialog is a general purpose client authentication plugin, it simply |
|||
asks the user the question, as provided by the server and reports |
|||
the answer back to the server. No encryption is involved, |
|||
the answers are sent in clear text. |
|||
|
|||
Two examples are provided: two_questions server plugin, that asks |
|||
the password and an "Are you sure?" question with a reply "yes, of course". |
|||
It demonstrates the usage of "password" (input is hidden) and "ordinary" |
|||
(input can be echoed) questions, and how to mark the last question, |
|||
to avoid an extra roundtrip. |
|||
|
|||
And three_attempts plugin that gives the user three attempts to enter |
|||
a correct password. It shows the situation when a number of questions |
|||
is not known in advance. |
|||
*/ |
|||
#define _GNU_SOURCE /* for RTLD_DEFAULT */ |
|||
|
|||
#include <mysql/plugin_auth.h> |
|||
#include <mysql/client_plugin.h> |
|||
#include <string.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
/** |
|||
first byte of the question string is the question "type". |
|||
It can be a "ordinary" or a "password" question. |
|||
The last bit set marks a last question in the authentication exchange. |
|||
*/ |
|||
#define ORDINARY_QUESTION "\2" |
|||
#define LAST_QUESTION "\3" |
|||
#define PASSWORD_QUESTION "\4" |
|||
#define LAST_PASSWORD "\5" |
|||
|
|||
/********************* SERVER SIDE ****************************************/ |
|||
|
|||
/** |
|||
dialog demo with two questions, one password and one ordinary. |
|||
*/ |
|||
|
|||
static int two_questions(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) |
|||
{ |
|||
unsigned char *pkt; |
|||
int pkt_len; |
|||
|
|||
/* send a password question */ |
|||
if (vio->write_packet(vio, PASSWORD_QUESTION "Password, please:", 18)) |
|||
return CR_ERROR; |
|||
|
|||
/* read the answer */ |
|||
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) |
|||
return CR_ERROR; |
|||
|
|||
info->password_used = 1; |
|||
|
|||
/* fail if the password is wrong */ |
|||
if (strcmp(pkt, info->auth_string)) |
|||
return CR_ERROR; |
|||
|
|||
/* send the last, ordinary, question */ |
|||
if (vio->write_packet(vio, LAST_QUESTION "Are you sure ?", 15)) |
|||
return CR_ERROR; |
|||
|
|||
/* read the answer */ |
|||
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) |
|||
return CR_ERROR; |
|||
|
|||
/* check the reply */ |
|||
return strcmp(pkt, "yes, of course") ? CR_ERROR : CR_OK; |
|||
} |
|||
|
|||
static struct st_mysql_auth two_handler= |
|||
{ |
|||
MYSQL_AUTHENTICATION_INTERFACE_VERSION, |
|||
"dialog", /* requires dialog client plugin */ |
|||
two_questions |
|||
}; |
|||
|
|||
|
|||
/** |
|||
dialog demo where the number of questions is not known in advance |
|||
*/ |
|||
|
|||
static int three_attempts(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) |
|||
{ |
|||
unsigned char *pkt; |
|||
int pkt_len, i; |
|||
|
|||
for (i= 0; i < 3; i++) |
|||
{ |
|||
/* send the prompt */ |
|||
if (vio->write_packet(vio, PASSWORD_QUESTION "Password, please:", 18)) |
|||
return CR_ERROR; |
|||
|
|||
/* read the password */ |
|||
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) |
|||
return CR_ERROR; |
|||
|
|||
info->password_used = 1; |
|||
|
|||
/* |
|||
finish, if the password is correct. |
|||
note, that we did not mark the prompt packet as "last" |
|||
*/ |
|||
if (strcmp(pkt, info->auth_string) == 0) |
|||
return CR_OK; |
|||
} |
|||
|
|||
return CR_ERROR; |
|||
} |
|||
|
|||
static struct st_mysql_auth three_handler= |
|||
{ |
|||
MYSQL_AUTHENTICATION_INTERFACE_VERSION, |
|||
"dialog", /* requires dialog client plugin */ |
|||
three_attempts |
|||
}; |
|||
|
|||
mysql_declare_plugin(dialog) |
|||
{ |
|||
MYSQL_AUTHENTICATION_PLUGIN, |
|||
&two_handler, |
|||
"two_questions", |
|||
"Sergei Golubchik", |
|||
"Dialog plugin demo 1", |
|||
PLUGIN_LICENSE_GPL, |
|||
NULL, |
|||
NULL, |
|||
0x0100, |
|||
NULL, |
|||
NULL, |
|||
NULL |
|||
}, |
|||
{ |
|||
MYSQL_AUTHENTICATION_PLUGIN, |
|||
&three_handler, |
|||
"three_attempts", |
|||
"Sergei Golubchik", |
|||
"Dialog plugin demo 2", |
|||
PLUGIN_LICENSE_GPL, |
|||
NULL, |
|||
NULL, |
|||
0x0100, |
|||
NULL, |
|||
NULL, |
|||
NULL |
|||
} |
|||
mysql_declare_plugin_end; |
|||
|
|||
/********************* CLIENT SIDE ***************************************/ |
|||
/* |
|||
This plugin performs a dialog with the user, asking questions and |
|||
reading answers. Depending on the client it may be desirable to do it |
|||
using GUI, or console, with or without curses, or read answers |
|||
from a smardcard, for example. |
|||
|
|||
To support all this variety, the dialog plugin has a callback function |
|||
"authentication_dialog_ask". If the client has a function of this name |
|||
dialog plugin will use it for communication with the user. Otherwise |
|||
a default gets() based implementation will be used. |
|||
*/ |
|||
#include <mysql.h> |
|||
#include <dlfcn.h> |
|||
|
|||
static mysql_authentication_dialog_ask_t ask; |
|||
|
|||
static char *builtin_ask(MYSQL *mysql __attribute__((unused)), |
|||
int type __attribute__((unused)), |
|||
const char *prompt, |
|||
char *buf, int buf_len __attribute__((unused))) |
|||
{ |
|||
fputs(prompt, stdout); |
|||
fputc(' ', stdout); |
|||
if (gets(buf) == 0) |
|||
return 0; |
|||
|
|||
return buf; |
|||
} |
|||
|
|||
|
|||
/** |
|||
The main function of the dialog plugin. |
|||
|
|||
Read the prompt, ask the question, send the reply, repeat until |
|||
the server is satisfied. |
|||
|
|||
@note |
|||
1. this plugin shows how a client authentication plugin |
|||
may read a MySQL protocol OK packet internally - which is important |
|||
where a number of packets is not known in advance. |
|||
2. the first byte of the prompt is special. it is not |
|||
shown to the user, but signals whether it is the last question |
|||
(prompt[0] & 1 == 1) or not last (prompt[0] & 1 == 0), |
|||
and whether the input is a password (not echoed). |
|||
3. the prompt is expected to be sent zero-terminated |
|||
*/ |
|||
|
|||
static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) |
|||
{ |
|||
unsigned char *pkt, cmd= 0; |
|||
int pkt_len, res; |
|||
char reply_buf[1024], *reply; |
|||
|
|||
do |
|||
{ |
|||
/* read the prompt */ |
|||
pkt_len= vio->read_packet(vio, &pkt); |
|||
if (pkt_len < 0) |
|||
return CR_ERROR; |
|||
|
|||
if (pkt == 0) |
|||
{ |
|||
/* |
|||
in mysql_change_user() the client sends the first packet, so |
|||
the first vio->read_packet() does nothing (pkt == 0). |
|||
|
|||
We send the "password", assuming the client knows what its doing. |
|||
(in other words, the dialog plugin should be only set as a default |
|||
authentication plugin on the client if the first question |
|||
asks for a password - which will be sent in clear text, by the way) |
|||
*/ |
|||
reply= mysql->passwd; |
|||
} |
|||
else |
|||
{ |
|||
cmd= *pkt++; |
|||
|
|||
/* is it MySQL protocol packet ? */ |
|||
if (cmd == 0 || cmd == 254) |
|||
return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */ |
|||
|
|||
/* |
|||
asking for a password with an empty prompt means mysql->password |
|||
otherwise we ask the user and read the reply |
|||
*/ |
|||
if ((cmd >> 1) == 2 && *pkt == 0) |
|||
reply= mysql->passwd; |
|||
else |
|||
reply= ask(mysql, cmd >> 1, pkt, reply_buf, sizeof(reply_buf)); |
|||
if (!reply) |
|||
return CR_ERROR; |
|||
} |
|||
/* send the reply to the server */ |
|||
res= vio->write_packet(vio, reply, strlen(reply)+1); |
|||
|
|||
if (reply != mysql->passwd && reply != reply_buf) |
|||
free(reply); |
|||
|
|||
if (res) |
|||
return CR_ERROR; |
|||
|
|||
/* repeat unless it was the last question */ |
|||
} while ((cmd & 1) != 1); |
|||
|
|||
/* the job of reading the ok/error packet is left to the server */ |
|||
return CR_OK; |
|||
} |
|||
|
|||
|
|||
/** |
|||
initialization function of the dialog plugin |
|||
|
|||
Pick up the client's authentication_dialog_ask() function, if exists, |
|||
or fall back to the default implementation. |
|||
*/ |
|||
|
|||
static int init_dialog() |
|||
{ |
|||
void *sym= dlsym(RTLD_DEFAULT, "mysql_authentication_dialog_ask"); |
|||
ask= sym ? (mysql_authentication_dialog_ask_t)sym : builtin_ask; |
|||
return 0; |
|||
} |
|||
|
|||
mysql_declare_client_plugin(AUTHENTICATION) |
|||
"dialog", |
|||
"Sergei Golubchik", |
|||
"Dialog Client Authentication Plugin", |
|||
{0,1,0}, |
|||
init_dialog, |
|||
NULL, |
|||
perform_dialog |
|||
mysql_end_client_plugin; |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
MYSQL_PLUGIN(auth, [Collection of Authentication Plugins], |
|||
[Collection of Authentication Plugins]) |
|||
MYSQL_PLUGIN_DYNAMIC(auth, [dialog.la]) |
|||
MYSQL_PLUGIN_ACTIONS(auth,[ |
|||
AC_COMPILE_IFELSE([ |
|||
AC_LANG_PROGRAM([[ |
|||
#define _GNU_SOURCE |
|||
#include <sys/socket.h> |
|||
]],[[ |
|||
struct ucred cred; |
|||
getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, 0); |
|||
]])],have_peercred=yes) |
|||
AM_CONDITIONAL(HAVE_PEERCRED, test x$have_peercred = xyes) |
|||
]) |
|||
AM_CONDITIONAL(HAVE_PEERCRED, false) |
|||
1102
sql-common/client.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,436 @@ |
|||
/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program 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 General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
/** |
|||
@file |
|||
|
|||
Support code for the client side (libmysql) plugins |
|||
|
|||
Client plugins are somewhat different from server plugins, they are simpler. |
|||
|
|||
They do not need to be installed or in any way explicitly loaded on the |
|||
client, they are loaded automatically on demand. |
|||
One client plugin per shared object, soname *must* match the plugin name. |
|||
|
|||
There is no reference counting and no unloading either. |
|||
*/ |
|||
|
|||
#include <my_global.h> |
|||
#include "mysql.h" |
|||
#include <my_sys.h> |
|||
#include <m_string.h> |
|||
#ifdef THREAD |
|||
#include <my_pthread.h> |
|||
#else |
|||
#include <my_no_pthread.h> |
|||
#endif |
|||
|
|||
#include <sql_common.h> |
|||
#include "errmsg.h" |
|||
#include <mysql/client_plugin.h> |
|||
|
|||
struct st_client_plugin_int { |
|||
struct st_client_plugin_int *next; |
|||
void *dlhandle; |
|||
struct st_mysql_client_plugin *plugin; |
|||
}; |
|||
|
|||
static my_bool initialized= 0; |
|||
static MEM_ROOT mem_root; |
|||
|
|||
static const char *plugin_declarations_sym= "_mysql_client_plugin_declaration_"; |
|||
static uint plugin_version[MYSQL_CLIENT_MAX_PLUGINS]= |
|||
{ |
|||
0, /* these two are taken by Connector/C */ |
|||
0, /* these two are taken by Connector/C */ |
|||
MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION |
|||
}; |
|||
|
|||
/* |
|||
Loaded plugins are stored in a linked list. |
|||
The list is append-only, the elements are added to the head (like in a stack). |
|||
The elements are added under a mutex, but the list can be read and traversed |
|||
without any mutex because once an element is added to the list, it stays |
|||
there. The main purpose of a mutex is to prevent two threads from |
|||
loading the same plugin twice in parallel. |
|||
*/ |
|||
struct st_client_plugin_int *plugin_list[MYSQL_CLIENT_MAX_PLUGINS]; |
|||
#ifdef THREAD |
|||
static pthread_mutex_t LOCK_load_client_plugin; |
|||
#endif |
|||
|
|||
static int is_not_initialized(MYSQL *mysql, const char *name) |
|||
{ |
|||
if (initialized) |
|||
return 0; |
|||
|
|||
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, |
|||
unknown_sqlstate, ER(CR_AUTH_PLUGIN_CANNOT_LOAD), |
|||
name, "not initialized"); |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
/** |
|||
finds a plugin in the list |
|||
|
|||
@param name plugin name to search for |
|||
@param type plugin type |
|||
|
|||
@note this does NOT necessarily need a mutex, take care! |
|||
|
|||
@retval a pointer to a found plugin or 0 |
|||
*/ |
|||
|
|||
static struct st_mysql_client_plugin *find_plugin(const char *name, int type) |
|||
{ |
|||
struct st_client_plugin_int *p; |
|||
|
|||
DBUG_ASSERT(initialized); |
|||
DBUG_ASSERT(type >= 0 && type < MYSQL_CLIENT_MAX_PLUGINS); |
|||
if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS) |
|||
return 0; |
|||
|
|||
for (p= plugin_list[type]; p; p= p->next) |
|||
{ |
|||
if (strcmp(p->plugin->name, name) == 0) |
|||
return p->plugin; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
/** |
|||
verifies the plugin and adds it to the list |
|||
|
|||
@param mysql MYSQL structure (for error reporting) |
|||
@param plugin plugin to install |
|||
@param dlhandle a handle to the shared object (returned by dlopen) |
|||
or 0 if the plugin was not dynamically loaded |
|||
@param argc number of arguments in the 'va_list args' |
|||
@param args arguments passed to the plugin initialization function |
|||
|
|||
@retval a pointer to an installed plugin or 0 |
|||
*/ |
|||
|
|||
static struct st_mysql_client_plugin * |
|||
add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle, |
|||
int argc, va_list args) |
|||
{ |
|||
const char *errmsg; |
|||
struct st_client_plugin_int plugin_int, *p; |
|||
char errbuf[1024]; |
|||
|
|||
DBUG_ASSERT(initialized); |
|||
|
|||
plugin_int.plugin= plugin; |
|||
plugin_int.dlhandle= dlhandle; |
|||
|
|||
if (plugin->type >= MYSQL_CLIENT_MAX_PLUGINS) |
|||
{ |
|||
errmsg= "Unknown client plugin type"; |
|||
goto err1; |
|||
} |
|||
|
|||
if (plugin->interface_version < plugin_version[plugin->type] || |
|||
(plugin->interface_version >> 8) > |
|||
(plugin_version[plugin->type] >> 8)) |
|||
{ |
|||
errmsg= "Incompatible client plugin interface"; |
|||
goto err1; |
|||
} |
|||
|
|||
/* Call the plugin initialization function, if any */ |
|||
if (plugin->init && plugin->init(errbuf, sizeof(errbuf), argc, args)) |
|||
{ |
|||
errmsg= errbuf; |
|||
goto err1; |
|||
} |
|||
|
|||
p= (struct st_client_plugin_int *) |
|||
memdup_root(&mem_root, &plugin_int, sizeof(plugin_int)); |
|||
|
|||
if (!p) |
|||
{ |
|||
errmsg= "Out of memory"; |
|||
goto err2; |
|||
} |
|||
|
|||
safe_mutex_assert_owner(&LOCK_load_client_plugin); |
|||
|
|||
p->next= plugin_list[plugin->type]; |
|||
plugin_list[plugin->type]= p; |
|||
|
|||
return plugin; |
|||
|
|||
err2: |
|||
if (plugin->deinit) |
|||
plugin->deinit(); |
|||
err1: |
|||
if (dlhandle) |
|||
dlclose(dlhandle); |
|||
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate, |
|||
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), plugin->name, |
|||
errmsg); |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
/** |
|||
Loads plugins which are specified in the environment variable |
|||
LIBMYSQL_PLUGINS. |
|||
|
|||
Multiple plugins must be separated by semicolon. This function doesn't |
|||
return or log an error. |
|||
|
|||
The function is be called by mysql_client_plugin_init |
|||
|
|||
@todo |
|||
Support extended syntax, passing parameters to plugins, for example |
|||
LIBMYSQL_PLUGINS="plugin1(param1,param2);plugin2;..." |
|||
or |
|||
LIBMYSQL_PLUGINS="plugin1=int:param1,str:param2;plugin2;..." |
|||
*/ |
|||
|
|||
static void load_env_plugins(MYSQL *mysql) |
|||
{ |
|||
char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS"); |
|||
|
|||
/* no plugins to load */ |
|||
if (!s) |
|||
return; |
|||
|
|||
free_env= plugs= my_strdup(s, MYF(MY_WME)); |
|||
|
|||
do { |
|||
if ((s= strchr(plugs, ';'))) |
|||
*s= '\0'; |
|||
mysql_load_plugin(mysql, plugs, -1, 0); |
|||
plugs= s + 1; |
|||
} while (s); |
|||
|
|||
my_free(free_env, MYF(0)); |
|||
} |
|||
|
|||
/********** extern functions to be used by libmysql *********************/ |
|||
|
|||
/** |
|||
Initializes the client plugin layer. |
|||
|
|||
This function must be called before any other client plugin function. |
|||
|
|||
@retval 0 successful |
|||
@retval != 0 error occured |
|||
*/ |
|||
|
|||
int mysql_client_plugin_init() |
|||
{ |
|||
MYSQL mysql; |
|||
struct st_mysql_client_plugin **builtin; |
|||
|
|||
if (initialized) |
|||
return 0; |
|||
|
|||
bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */ |
|||
|
|||
pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW); |
|||
init_alloc_root(&mem_root, 128, 128); |
|||
|
|||
bzero(&plugin_list, sizeof(plugin_list)); |
|||
|
|||
initialized= 1; |
|||
|
|||
pthread_mutex_lock(&LOCK_load_client_plugin); |
|||
|
|||
for (builtin= mysql_client_builtins; *builtin; builtin++) |
|||
add_plugin(&mysql, *builtin, 0, 0, 0); |
|||
|
|||
pthread_mutex_unlock(&LOCK_load_client_plugin); |
|||
|
|||
load_env_plugins(&mysql); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/** |
|||
Deinitializes the client plugin layer. |
|||
|
|||
Unloades all client plugins and frees any associated resources. |
|||
*/ |
|||
|
|||
void mysql_client_plugin_deinit() |
|||
{ |
|||
int i; |
|||
struct st_client_plugin_int *p; |
|||
|
|||
if (!initialized) |
|||
return; |
|||
|
|||
for (i=0; i < MYSQL_CLIENT_MAX_PLUGINS; i++) |
|||
for (p= plugin_list[i]; p; p= p->next) |
|||
{ |
|||
if (p->plugin->deinit) |
|||
p->plugin->deinit(); |
|||
if (p->dlhandle) |
|||
dlclose(p->dlhandle); |
|||
} |
|||
|
|||
bzero(&plugin_list, sizeof(plugin_list)); |
|||
initialized= 0; |
|||
free_root(&mem_root, MYF(0)); |
|||
pthread_mutex_destroy(&LOCK_load_client_plugin); |
|||
} |
|||
|
|||
/************* public facing functions, for client consumption *********/ |
|||
|
|||
/* see <mysql/client_plugin.h> for a full description */ |
|||
struct st_mysql_client_plugin * |
|||
mysql_client_register_plugin(MYSQL *mysql, |
|||
struct st_mysql_client_plugin *plugin) |
|||
{ |
|||
if (is_not_initialized(mysql, plugin->name)) |
|||
return NULL; |
|||
|
|||
pthread_mutex_lock(&LOCK_load_client_plugin); |
|||
|
|||
/* make sure the plugin wasn't loaded meanwhile */ |
|||
if (find_plugin(plugin->name, plugin->type)) |
|||
{ |
|||
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, |
|||
unknown_sqlstate, ER(CR_AUTH_PLUGIN_CANNOT_LOAD), |
|||
plugin->name, "it is already loaded"); |
|||
plugin= NULL; |
|||
} |
|||
else |
|||
plugin= add_plugin(mysql, plugin, 0, 0, 0); |
|||
|
|||
pthread_mutex_unlock(&LOCK_load_client_plugin); |
|||
return plugin; |
|||
} |
|||
|
|||
|
|||
/* see <mysql/client_plugin.h> for a full description */ |
|||
struct st_mysql_client_plugin * |
|||
mysql_load_plugin_v(MYSQL *mysql, const char *name, int type, |
|||
int argc, va_list args) |
|||
{ |
|||
const char *errmsg; |
|||
char dlpath[FN_REFLEN+1]; |
|||
void *sym, *dlhandle; |
|||
struct st_mysql_client_plugin *plugin; |
|||
|
|||
if (is_not_initialized(mysql, name)) |
|||
return NULL; |
|||
|
|||
pthread_mutex_lock(&LOCK_load_client_plugin); |
|||
|
|||
/* make sure the plugin wasn't loaded meanwhile */ |
|||
if (type >= 0 && find_plugin(name, type)) |
|||
{ |
|||
errmsg= "it is already loaded"; |
|||
goto err; |
|||
} |
|||
|
|||
/* Compile dll path */ |
|||
strxnmov(dlpath, sizeof(dlpath) - 1, |
|||
mysql->options.extension && mysql->options.extension->plugin_dir ? |
|||
mysql->options.extension->plugin_dir : PLUGINDIR, "/", |
|||
name, SO_EXT, NullS); |
|||
|
|||
/* Open new dll handle */ |
|||
if (!(dlhandle= dlopen(dlpath, RTLD_NOW))) |
|||
{ |
|||
errmsg= dlerror(); |
|||
goto err; |
|||
} |
|||
|
|||
if (!(sym= dlsym(dlhandle, plugin_declarations_sym))) |
|||
{ |
|||
errmsg= "not a plugin"; |
|||
dlclose(dlhandle); |
|||
goto err; |
|||
} |
|||
|
|||
plugin= (struct st_mysql_client_plugin*)sym; |
|||
|
|||
if (type >=0 && type != plugin->type) |
|||
{ |
|||
errmsg= "type mismatch"; |
|||
goto err; |
|||
} |
|||
|
|||
if (strcmp(name, plugin->name)) |
|||
{ |
|||
errmsg= "name mismatch"; |
|||
goto err; |
|||
} |
|||
|
|||
if (type < 0 && find_plugin(name, plugin->type)) |
|||
{ |
|||
errmsg= "it is already loaded"; |
|||
goto err; |
|||
} |
|||
|
|||
plugin= add_plugin(mysql, plugin, dlhandle, argc, args); |
|||
|
|||
pthread_mutex_unlock(&LOCK_load_client_plugin); |
|||
|
|||
return plugin; |
|||
|
|||
err: |
|||
pthread_mutex_unlock(&LOCK_load_client_plugin); |
|||
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate, |
|||
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, errmsg); |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
/* see <mysql/client_plugin.h> for a full description */ |
|||
struct st_mysql_client_plugin * |
|||
mysql_load_plugin(MYSQL *mysql, const char *name, int type, int argc, ...) |
|||
{ |
|||
struct st_mysql_client_plugin *p; |
|||
va_list args; |
|||
va_start(args, argc); |
|||
p= mysql_load_plugin_v(mysql, name, type, argc, args); |
|||
va_end(args); |
|||
return p; |
|||
} |
|||
|
|||
|
|||
/* see <mysql/client_plugin.h> for a full description */ |
|||
struct st_mysql_client_plugin * |
|||
mysql_client_find_plugin(MYSQL *mysql, const char *name, int type) |
|||
{ |
|||
struct st_mysql_client_plugin *p; |
|||
|
|||
if (is_not_initialized(mysql, name)) |
|||
return NULL; |
|||
|
|||
if (type < 0 || type >= MYSQL_CLIENT_MAX_PLUGINS) |
|||
{ |
|||
set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD, unknown_sqlstate, |
|||
ER(CR_AUTH_PLUGIN_CANNOT_LOAD), name, |
|||
"invalid type"); |
|||
} |
|||
|
|||
if ((p= find_plugin(name, type))) |
|||
return p; |
|||
|
|||
/* not found, load it */ |
|||
return mysql_load_plugin(mysql, name, type, 0); |
|||
} |
|||
|
|||
1941
sql/sql_acl.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue