diff options
author | Sergei Golubchik <sergii@pisem.net> | 2012-01-13 15:50:02 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2012-01-13 15:50:02 +0100 |
commit | 4f435bddfd44d40999f88685c61cc04e319d8d6c (patch) | |
tree | f9d0655a0d901b87f918a736741144b502cba3f6 /plugin | |
parent | 8c2bcdf85ff753bceeb5b235f3605e348e6f9e1d (diff) | |
parent | 6ca4ca7d37fed3b3da18666768de6a2f8c34bc7b (diff) | |
download | mariadb-git-4f435bddfd44d40999f88685c61cc04e319d8d6c.tar.gz |
5.3 merge
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/auth_dialog/CMakeLists.txt | 3 | ||||
-rw-r--r-- | plugin/auth_dialog/dialog.c | 33 | ||||
-rw-r--r-- | plugin/auth_pam/Makefile.am | 16 | ||||
-rw-r--r-- | plugin/auth_pam/auth_pam.c | 130 | ||||
-rw-r--r-- | plugin/auth_pam/plug.in | 4 | ||||
-rw-r--r-- | plugin/auth_pam/testing/pam_mariadb_mtr.c | 87 | ||||
-rw-r--r-- | plugin/feedback/feedback.h | 2 | ||||
-rw-r--r-- | plugin/fulltext/plugin_example.c | 2 |
8 files changed, 264 insertions, 13 deletions
diff --git a/plugin/auth_dialog/CMakeLists.txt b/plugin/auth_dialog/CMakeLists.txt index 3e1f3579848..a6f6ee9b173 100644 --- a/plugin/auth_dialog/CMakeLists.txt +++ b/plugin/auth_dialog/CMakeLists.txt @@ -14,4 +14,5 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -MYSQL_ADD_PLUGIN(dialog dialog.c MODULE_ONLY) +MYSQL_ADD_PLUGIN(dialog dialog.c ${CMAKE_SOURCE_DIR}/libmysql/get_password.c + MODULE_ONLY) diff --git a/plugin/auth_dialog/dialog.c b/plugin/auth_dialog/dialog.c index 9f974f6898f..2026369bc26 100644 --- a/plugin/auth_dialog/dialog.c +++ b/plugin/auth_dialog/dialog.c @@ -43,7 +43,7 @@ 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 fgets() based implementation will be used. + a default implementation will be used. */ static mysql_authentication_dialog_ask_t ask; @@ -52,13 +52,25 @@ static char *builtin_ask(MYSQL *mysql __attribute__((unused)), const char *prompt, char *buf, int buf_len) { - char *ptr; fputs(prompt, stdout); fputc(' ', stdout); - if (fgets(buf, buf_len, stdin) == NULL) - return NULL; - if ((ptr= strchr(buf, '\n'))) - *ptr= 0; + + if (type == 2) /* password */ + { + get_tty_password_buff("", buf, buf_len); + buf[buf_len-1]= 0; + } + else + { + if (!fgets(buf, buf_len-1, stdin)) + buf[0]= 0; + else + { + int len= strlen(buf); + if (len && buf[len-1] == '\n') + buf[len-1]= 0; + } + } return buf; } @@ -84,6 +96,7 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) unsigned char *pkt, cmd= 0; int pkt_len, res; char reply_buf[1024], *reply; + int first = 1; do { @@ -92,13 +105,13 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) if (pkt_len < 0) return CR_ERROR; - if (pkt == 0) + if (pkt == 0 && first) { /* 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 it's doing. + 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) @@ -114,10 +127,10 @@ static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */ /* - asking for a password with an empty prompt means mysql->password + asking for a password in the first packet mean mysql->password, if it's set otherwise we ask the user and read the reply */ - if ((cmd >> 1) == 2 && *pkt == 0) + if ((cmd >> 1) == 2 && first && mysql->passwd[0]) reply= mysql->passwd; else reply= ask(mysql, cmd >> 1, (const char *) pkt, diff --git a/plugin/auth_pam/Makefile.am b/plugin/auth_pam/Makefile.am new file mode 100644 index 00000000000..be20d393781 --- /dev/null +++ b/plugin/auth_pam/Makefile.am @@ -0,0 +1,16 @@ +EXTRA_LTLIBRARIES = auth_pam.la libauth_pam.la + +pkgplugindir=$(pkglibdir)/plugin +AM_CPPFLAGS = -I$(top_srcdir)/include + +pkgplugin_LTLIBRARIES = @plugin_auth_pam_shared_target@ +auth_pam_la_LDFLAGS = -module -rpath $(pkgplugindir) -L$(top_builddir)/libservices -lmysqlservices -lpam +auth_pam_la_CFLAGS = -shared -DMYSQL_DYNAMIC_PLUGIN +auth_pam_la_SOURCES = auth_pam.c + +noinst_LTLIBRARIES = @plugin_auth_pam_static_target@ +libauth_pam_la_LDFLAGS = -lpam +libauth_pam_la_SOURCES = auth_pam.c + +EXTRA_DIST = plug.in + diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c new file mode 100644 index 00000000000..45c49975f6e --- /dev/null +++ b/plugin/auth_pam/auth_pam.c @@ -0,0 +1,130 @@ +#include <mysql/plugin_auth.h> +#include <string.h> +#include <security/pam_appl.h> +#include <security/pam_modules.h> + +struct param { + unsigned char buf[10240], *ptr; + MYSQL_PLUGIN_VIO *vio; +}; + +static int conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct param *param = (struct param *)data; + unsigned char *end = param->buf + sizeof(param->buf) - 1; + int i; + + *resp = 0; + + for (i = 0; i < n; i++) + { + /* if there's a message - append it to the buffer */ + if (msg[i]->msg) + { + int len = strlen(msg[i]->msg); + if (len > end - param->ptr) + len = end - param->ptr; + if (len > 0) + { + memcpy(param->ptr, msg[i]->msg, len); + param->ptr+= len; + *(param->ptr)++ = '\n'; + } + } + /* if the message style is *_PROMPT_*, meaning PAM asks a question, + send the accumulated text to the client, read the reply */ + if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || + msg[i]->msg_style == PAM_PROMPT_ECHO_ON) + { + int pkt_len; + unsigned char *pkt; + + /* allocate the response array. + freeing it is the responsibility of the caller */ + if (*resp == 0) + { + *resp = calloc(sizeof(struct pam_response), n); + if (*resp == 0) + return PAM_BUF_ERR; + } + + /* dialog plugin interprets the first byte of the packet + as the magic number. + 2 means "read the input with the echo enabled" + 4 means "password-like input, echo disabled" + C'est la vie. */ + param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4; + if (param->vio->write_packet(param->vio, param->buf, param->ptr - param->buf - 1)) + return PAM_CONV_ERR; + + pkt_len = param->vio->read_packet(param->vio, &pkt); + if (pkt_len < 0) + return PAM_CONV_ERR; + /* allocate and copy the reply to the response array */ + (*resp)[i].resp = strndup((char*)pkt, pkt_len); + param->ptr = param->buf + 1; + } + } + return PAM_SUCCESS; +} + +#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end + +static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) +{ + pam_handle_t *pamh = NULL; + int status; + const char *new_username; + struct param param; + struct pam_conv c = { &conv, ¶m }; + + /* + get the service name, as specified in + + CREATE USER ... IDENTIFIED WITH pam_auth AS "service" + */ + const char *service = info->auth_string && info->auth_string[0] + ? info->auth_string : "mysql"; + + param.ptr = param.buf + 1; + param.vio = vio; + + DO( pam_start(service, info->user_name, &c, &pamh) ); + DO( pam_authenticate (pamh, 0) ); + DO( pam_acct_mgmt(pamh, 0) ); + DO( pam_get_item(pamh, PAM_USER, (const void**)&new_username) ); + + if (new_username && strcmp(new_username, info->user_name)) + strncpy(info->authenticated_as, new_username, + sizeof(info->authenticated_as)); + +end: + pam_end(pamh, status); + return status == PAM_SUCCESS ? CR_OK : CR_ERROR; +} + +static struct st_mysql_auth pam_info = +{ + MYSQL_AUTHENTICATION_INTERFACE_VERSION, + "dialog", + pam_auth +}; + +maria_declare_plugin(pam) +{ + MYSQL_AUTHENTICATION_PLUGIN, + &pam_info, + "pam", + "Sergei Golubchik", + "PAM 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_pam/plug.in b/plugin/auth_pam/plug.in new file mode 100644 index 00000000000..05af6ce6461 --- /dev/null +++ b/plugin/auth_pam/plug.in @@ -0,0 +1,4 @@ +MYSQL_PLUGIN(auth_pam, [PAM Authentication Plugin], [PAM Authentication Plugin]) +MYSQL_PLUGIN_DYNAMIC(auth_pam, [auth_pam.la]) + +AC_CHECK_HEADER([security/pam_appl.h],,[MYSQL_PLUGIN_WITHOUT(auth_pam)]) diff --git a/plugin/auth_pam/testing/pam_mariadb_mtr.c b/plugin/auth_pam/testing/pam_mariadb_mtr.c new file mode 100644 index 00000000000..73defe30112 --- /dev/null +++ b/plugin/auth_pam/testing/pam_mariadb_mtr.c @@ -0,0 +1,87 @@ +/* + Pam module to test pam authentication plugin. Used in pam.test. + Linux only. + + Compile as + + gcc pam_mariadb_mtr.c -shared -lpam -fPIC -o pam_mariadb_mtr.so + + Install as appropriate (for example, in /lib/security/). + Create /etc/pam.d/mariadb_mtr with +========================================================= +auth required pam_mariadb_mtr.so pam_test +account required pam_mariadb_mtr.so +========================================================= +*/ + +#include <stdlib.h> +#include <string.h> +#include <security/pam_modules.h> +#include <security/pam_appl.h> + +#define N 3 + +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + struct pam_conv *conv; + struct pam_response *resp = 0; + int pam_err, retval = PAM_SYSTEM_ERR; + struct pam_message msg[N] = { + { PAM_TEXT_INFO, "Challenge input first." }, + { PAM_PROMPT_ECHO_ON, "Enter:" }, + { PAM_ERROR_MSG, "Now, the magic number!" } + }; + const struct pam_message *msgp[N] = { msg, msg+1, msg+2 }; + char *r1 = 0, *r2 = 0; + + pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv); + if (pam_err != PAM_SUCCESS) + goto ret; + + pam_err = (*conv->conv)(N, msgp, &resp, conv->appdata_ptr); + + if (pam_err != PAM_SUCCESS || !resp || !((r1= resp[1].resp))) + goto ret; + + free(resp); + + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = "PIN:"; + pam_err = (*conv->conv)(1, msgp, &resp, conv->appdata_ptr); + + if (pam_err != PAM_SUCCESS || !resp || !((r2= resp[0].resp))) + goto ret; + + if (strlen(r1) == atoi(r2) % 100) + retval = PAM_SUCCESS; + else + retval = PAM_AUTH_ERR; + + if (argc > 0 && argv[0]) + pam_set_item(pamh, PAM_USER, argv[0]); + +ret: + free(resp); + free(r1); + free(r2); + return retval; +} + +PAM_EXTERN int +pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + + return PAM_SUCCESS; +} + diff --git a/plugin/feedback/feedback.h b/plugin/feedback/feedback.h index 74fb806fac2..c5acbb5ef72 100644 --- a/plugin/feedback/feedback.h +++ b/plugin/feedback/feedback.h @@ -13,7 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define MYSQL_SERVER +#define MYSQL_SERVER 1 #include <sql_class.h> namespace feedback { diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c index b58f3e9eda5..981335bddd6 100644 --- a/plugin/fulltext/plugin_example.c +++ b/plugin/fulltext/plugin_example.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2005, 2011, Oracle and/or its affiliates 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 |