diff options
author | Sergei Golubchik <sergii@pisem.net> | 2010-11-25 18:17:28 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2010-11-25 18:17:28 +0100 |
commit | 65ca700def99289cc31a7040537f5aa6e12bf485 (patch) | |
tree | 97b3a07299b626c519da0e80c122b5b79b933914 /plugin | |
parent | 2ab57de38d13d927ddff2d51aed4af34e13998f5 (diff) | |
parent | 6e5bcca7935d3c62f84bb640e5357664a210ee12 (diff) | |
download | mariadb-git-65ca700def99289cc31a7040537f5aa6e12bf485.tar.gz |
merge.
checkpoint.
does not compile.
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/Makefile.am | 6 | ||||
-rw-r--r-- | plugin/auth/CMakeLists.txt | 15 | ||||
-rw-r--r-- | plugin/auth/Makefile.am | 15 | ||||
-rw-r--r-- | plugin/auth/auth_socket.c | 119 | ||||
-rw-r--r-- | plugin/auth/dialog.c | 346 | ||||
-rw-r--r-- | plugin/auth/plug.in | 15 | ||||
-rw-r--r-- | plugin/daemon_example/Makefile.am | 6 | ||||
-rw-r--r-- | plugin/daemon_example/daemon_example.cc | 21 | ||||
-rw-r--r-- | plugin/fulltext/Makefile.am | 2 | ||||
-rw-r--r-- | plugin/fulltext/plugin_example.c | 21 |
10 files changed, 551 insertions, 15 deletions
diff --git a/plugin/Makefile.am b/plugin/Makefile.am index 4a84ce4915a..d5f0651d4bc 100644 --- a/plugin/Makefile.am +++ b/plugin/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (C) 2005-2006 MySQL 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 @@ -24,7 +24,3 @@ EXTRA_DIST = fulltext/configure.in SUBDIRS = @mysql_pg_dirs@ DIST_SUBDIRS = @mysql_pg_distdirs@ -# As of 5.5.3-m3, we want to include the plugin files of a debug build in the package -install-exec-hook: - $(mkinstalldirs) $(DESTDIR)$(pkglibdir) $(DESTDIR)$(pkglibdir)/plugin - test ! -d debug || $(TAR) cf - debug | ( cd $(DESTDIR)$(pkglibdir)/plugin && $(TAR) xvf - ) diff --git a/plugin/auth/CMakeLists.txt b/plugin/auth/CMakeLists.txt new file mode 100644 index 00000000000..cc842f69441 --- /dev/null +++ b/plugin/auth/CMakeLists.txt @@ -0,0 +1,15 @@ +MYSQL_ADD_PLUGIN(auth dialog.c + MODULE_ONLY) + +CHECK_CXX_SOURCE_COMPILES( +"#define _GNU_SOURCE +#include <sys/socket.h> +int main() { + struct ucred cred; + getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, 0); +}" HAVE_PEERCRED) + +IF(HAVE_PEERCRED) + MYSQL_ADD_PLUGIN(auth_socket auth_socket.c + MODULE_ONLY) +ENDIF(HAVE_PEERCRED) diff --git a/plugin/auth/Makefile.am b/plugin/auth/Makefile.am new file mode 100644 index 00000000000..acca98e26f8 --- /dev/null +++ b/plugin/auth/Makefile.am @@ -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 + diff --git a/plugin/auth/auth_socket.c b/plugin/auth/auth_socket.c new file mode 100644 index 00000000000..cc406dac331 --- /dev/null +++ b/plugin/auth/auth_socket.c @@ -0,0 +1,119 @@ +/* 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; +maria_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, + "1.0", + MariaDB_PLUGIN_MATURITY_BETA +} +maria_declare_plugin_end; + diff --git a/plugin/auth/dialog.c b/plugin/auth/dialog.c new file mode 100644 index 00000000000..72c6364f49a --- /dev/null +++ b/plugin/auth/dialog.c @@ -0,0 +1,346 @@ +/* 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" + +typedef unsigned char uchar; + +/********************* 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, + (const uchar*) (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((char*) pkt, info->auth_string)) + return CR_ERROR; + + /* send the last, ordinary, question */ + if (vio->write_packet(vio, + (const uchar*) (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((char*) 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, + (const uchar*) (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((char*) 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; +maria_declare_plugin(dialog) +{ + MYSQL_AUTHENTICATION_PLUGIN, + &two_handler, + "two_questions", + "Sergei Golubchik", + "Dialog plugin demo 1", + PLUGIN_LICENSE_GPL, + NULL, + NULL, + 0x0100, + NULL, + NULL, + "1.0", + MariaDB_PLUGIN_MATURITY_BETA +}, +{ + MYSQL_AUTHENTICATION_PLUGIN, + &three_handler, + "three_attempts", + "Sergei Golubchik", + "Dialog plugin demo 2", + PLUGIN_LICENSE_GPL, + NULL, + NULL, + 0x0100, + NULL, + NULL, + "1.0", + MariaDB_PLUGIN_MATURITY_BETA +} +maria_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) +{ + int len; + + fputs(prompt, stdout); + fputc(' ', stdout); + if (fgets(buf, buf_len, stdin) == 0) + return 0; + + len= strlen(buf); + if (len && buf[len-1]=='\n') + buf[len-1]=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, (char*) pkt, reply_buf, sizeof(reply_buf)); + if (!reply) + return CR_ERROR; + } + /* send the reply to the server */ + res= vio->write_packet(vio, (uchar*) 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; + diff --git a/plugin/auth/plug.in b/plugin/auth/plug.in new file mode 100644 index 00000000000..ce31465b056 --- /dev/null +++ b/plugin/auth/plug.in @@ -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) diff --git a/plugin/daemon_example/Makefile.am b/plugin/daemon_example/Makefile.am index d60271521b3..82278b4685f 100644 --- a/plugin/daemon_example/Makefile.am +++ b/plugin/daemon_example/Makefile.am @@ -27,15 +27,11 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \ EXTRA_LTLIBRARIES = libdaemon_example.la pkgplugin_LTLIBRARIES = @plugin_daemon_example_shared_target@ libdaemon_example_la_LDFLAGS = -module -rpath $(pkgplugindir) -L$(top_builddir)/libservices -lmysqlservices - -libdaemon_example_la_CXXFLAGS= $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN -libdaemon_example_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN +libdaemon_example_la_CXXFLAGS= -shared $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN libdaemon_example_la_SOURCES = daemon_example.cc - EXTRA_LIBRARIES = libdaemon_example.a noinst_LIBRARIES = @plugin_daemon_example_static_target@ libdaemon_example_a_CXXFLAGS = $(AM_CXXFLAGS) -libdaemon_example_a_CFLAGS = $(AM_CFLAGS) libdaemon_example_a_SOURCES= daemon_example.cc EXTRA_DIST = CMakeLists.txt diff --git a/plugin/daemon_example/daemon_example.cc b/plugin/daemon_example/daemon_example.cc index 9bdacdfeae9..79b58d27414 100644 --- a/plugin/daemon_example/daemon_example.cc +++ b/plugin/daemon_example/daemon_example.cc @@ -85,7 +85,7 @@ pthread_handler_t mysql_heartbeat(void *p) 1 failure (cannot happen) */ -static int daemon_example_plugin_init(void *p) +static int daemon_example_plugin_init(void *p __attribute__ ((unused))) { DBUG_ENTER("daemon_example_plugin_init"); @@ -151,7 +151,7 @@ static int daemon_example_plugin_init(void *p) */ -static int daemon_example_plugin_deinit(void *p) +static int daemon_example_plugin_deinit(void *p __attribute__ ((unused))) { DBUG_ENTER("daemon_example_plugin_deinit"); char buffer[HEART_STRING_BUFFER]; @@ -204,3 +204,20 @@ mysql_declare_plugin(daemon_example) NULL /* config options */ } mysql_declare_plugin_end; +maria_declare_plugin(daemon_example) +{ + MYSQL_DAEMON_PLUGIN, + &daemon_example_plugin, + "daemon_example", + "Brian Aker", + "Daemon example, creates a heartbeat beat file in mysql-heartbeat.log", + PLUGIN_LICENSE_GPL, + daemon_example_plugin_init, /* Plugin Init */ + daemon_example_plugin_deinit, /* Plugin Deinit */ + 0x0100 /* 1.0 */, + NULL, /* status variables */ + NULL, /* system variables */ + "1.0", /* string version */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */ +} +maria_declare_plugin_end; diff --git a/plugin/fulltext/Makefile.am b/plugin/fulltext/Makefile.am index 80a8753b332..096800d0d30 100644 --- a/plugin/fulltext/Makefile.am +++ b/plugin/fulltext/Makefile.am @@ -21,5 +21,5 @@ INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include pkgplugin_LTLIBRARIES= mypluglib.la mypluglib_la_SOURCES= plugin_example.c mypluglib_la_LDFLAGS= -module -rpath $(pkgplugindir) -mypluglib_la_CFLAGS= -DMYSQL_DYNAMIC_PLUGIN +mypluglib_la_CFLAGS= -shared -DMYSQL_DYNAMIC_PLUGIN EXTRA_DIST= CMakeLists.txt diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c index 70022da2cc4..f39ff6a78fd 100644 --- a/plugin/fulltext/plugin_example.c +++ b/plugin/fulltext/plugin_example.c @@ -145,7 +145,7 @@ static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param the list of search terms when parsing a search string. */ -static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len) +static void add_word(MYSQL_FTPARSER_PARAM *param, const unsigned char *word, size_t len) { MYSQL_FTPARSER_BOOLEAN_INFO bool_info= { FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 }; @@ -169,7 +169,7 @@ static void add_word(MYSQL_FTPARSER_PARAM *param, char *word, size_t len) static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param) { - char *end, *start, *docend= param->doc + param->length; + const unsigned char *end, *start, *docend= param->doc + param->length; number_of_calls++; @@ -270,4 +270,21 @@ mysql_declare_plugin(ftexample) NULL } mysql_declare_plugin_end; +maria_declare_plugin(ftexample) +{ + MYSQL_FTPARSER_PLUGIN, /* type */ + &simple_parser_descriptor, /* descriptor */ + "simple_parser", /* name */ + "MySQL AB", /* author */ + "Simple Full-Text Parser", /* description */ + PLUGIN_LICENSE_GPL, + simple_parser_plugin_init, /* init function (when loaded) */ + simple_parser_plugin_deinit,/* deinit function (when unloaded) */ + 0x0001, /* version */ + simple_status, /* status variables */ + simple_system_variables, /* system variables */ + "0.01", /* string version */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */ +} +maria_declare_plugin_end; |