mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
PAM plugin with test
This commit is contained in:
22
mysql-test/suite/plugins/r/pam.result
Normal file
22
mysql-test/suite/plugins/r/pam.result
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
install plugin pam soname 'auth_pam.so';
|
||||||
|
create user test_pam identified via pam using 'mariadb_mtr';
|
||||||
|
#
|
||||||
|
# athentication is successful, challenge/pin are ok
|
||||||
|
# note that current_user() differts from user()
|
||||||
|
#
|
||||||
|
Challenge input first.
|
||||||
|
Enter: not very secret challenge
|
||||||
|
Now, the magic number!
|
||||||
|
PIN: ****
|
||||||
|
select user(), current_user(), database();
|
||||||
|
user() current_user() database()
|
||||||
|
test_pam@localhost pam_test@% test
|
||||||
|
#
|
||||||
|
# athentication is unsuccessful
|
||||||
|
#
|
||||||
|
Challenge input first.
|
||||||
|
Enter: not very secret challenge
|
||||||
|
Now, the magic number!
|
||||||
|
PIN: ****
|
||||||
|
drop user test_pam;
|
||||||
|
uninstall plugin pam;
|
8
mysql-test/suite/plugins/suite.pm
Normal file
8
mysql-test/suite/plugins/suite.pm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package My::Suite::Plugins;
|
||||||
|
|
||||||
|
@ISA = qw(My::Suite);
|
||||||
|
|
||||||
|
$ENV{PAM_SETUP_FOR_MTR}=1 if -e '/etc/pam.d/mariadb_mtr';
|
||||||
|
|
||||||
|
bless { };
|
||||||
|
|
46
mysql-test/suite/plugins/t/pam.test
Normal file
46
mysql-test/suite/plugins/t/pam.test
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
--source include/not_embedded.inc
|
||||||
|
|
||||||
|
if (!$AUTH_PAM_SO) {
|
||||||
|
skip No pam auth plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$PAM_SETUP_FOR_MTR) {
|
||||||
|
skip No pam setup for mtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
--replace_result .dll .so
|
||||||
|
eval install plugin pam soname '$AUTH_PAM_SO';
|
||||||
|
create user test_pam identified via pam using 'mariadb_mtr';
|
||||||
|
|
||||||
|
let $plugindir=`SELECT @@global.plugin_dir`;
|
||||||
|
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/pam_good.txt
|
||||||
|
not very secret challenge
|
||||||
|
9225
|
||||||
|
select user(), current_user(), database();
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--write_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt
|
||||||
|
not very secret challenge
|
||||||
|
9224
|
||||||
|
select user(), current_user(), database();
|
||||||
|
EOF
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # athentication is successful, challenge/pin are ok
|
||||||
|
--echo # note that current_user() differts from user()
|
||||||
|
--echo #
|
||||||
|
--exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_good.txt
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # athentication is unsuccessful
|
||||||
|
--echo #
|
||||||
|
--error 1
|
||||||
|
--exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_bad.txt
|
||||||
|
|
||||||
|
--remove_file $MYSQLTEST_VARDIR/tmp/pam_good.txt
|
||||||
|
--remove_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt
|
||||||
|
drop user test_pam;
|
||||||
|
uninstall plugin pam;
|
||||||
|
|
16
plugin/auth_pam/Makefile.am
Normal file
16
plugin/auth_pam/Makefile.am
Normal file
@ -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
|
||||||
|
|
130
plugin/auth_pam/auth_pam.c
Normal file
130
plugin/auth_pam/auth_pam.c
Normal file
@ -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;
|
4
plugin/auth_pam/plug.in
Normal file
4
plugin/auth_pam/plug.in
Normal file
@ -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)])
|
87
plugin/auth_pam/testing/pam_mariadb_mtr.c
Normal file
87
plugin/auth_pam/testing/pam_mariadb_mtr.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user