mariadb/plugin/auth_pam/auth_pam.c

227 lines
5.9 KiB
C
Raw Normal View History

/*
Copyright (c) 2011, 2019, MariaDB Corporation.
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
2017-02-10 13:26:55 +02:00
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
#include <unistd.h>
2011-12-02 16:27:13 +01:00
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <mysql/plugin_auth.h>
#include "auth_pam_tool.h"
#include <my_global.h>
#ifndef DBUG_OFF
static char pam_debug = 0;
#define PAM_DEBUG(X) do { if (pam_debug) { fprintf X; } } while(0)
#else
#define PAM_DEBUG(X) /* no-op */
#endif
static char winbind_hack = 0;
static char *opt_plugin_dir; /* To be dynamically linked. */
static const char *tool_name= "auth_pam_tool_dir/auth_pam_tool";
static const int tool_name_len= 31;
static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
2011-12-02 16:27:13 +01:00
{
int p_to_c[2], c_to_p[2]; /* Parent-to-child and child-to-parent pipes. */
pid_t proc_id;
int result= CR_ERROR, pkt_len;
unsigned char field, *pkt;
2011-12-02 16:27:13 +01:00
PAM_DEBUG((stderr, "PAM: opening pipes.\n"));
if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0)
{
/* Error creating pipes. */
return CR_ERROR;
}
PAM_DEBUG((stderr, "PAM: forking.\n"));
if ((proc_id= fork()) < 0)
{
/* Error forking. */
close(p_to_c[0]);
close(c_to_p[1]);
goto error_ret;
}
2011-12-02 16:27:13 +01:00
if (proc_id == 0)
2011-12-02 16:27:13 +01:00
{
/* The 'sandbox' process started. */
char toolpath[FN_REFLEN];
size_t plugin_dir_len= strlen(opt_plugin_dir);
PAM_DEBUG((stderr, "PAM: Child process prepares pipes.\n"));
if (close(p_to_c[1]) < 0 ||
close(c_to_p[0]) < 0 ||
dup2(p_to_c[0], 0) < 0 || /* Parent's pipe to STDIN. */
dup2(c_to_p[1], 1) < 0) /* Sandbox's pipe to STDOUT. */
2011-12-02 16:27:13 +01:00
{
exit(-1);
2011-12-02 16:27:13 +01:00
}
PAM_DEBUG((stderr, "PAM: check tool directory: %s, %s.\n",
opt_plugin_dir, tool_name));
if (plugin_dir_len + tool_name_len + 2 > sizeof(toolpath))
2011-12-02 16:27:13 +01:00
{
/* Tool path too long. */
exit(-1);
}
2011-12-02 16:27:13 +01:00
memcpy(toolpath, opt_plugin_dir, plugin_dir_len);
if (plugin_dir_len && toolpath[plugin_dir_len-1] != FN_LIBCHAR)
toolpath[plugin_dir_len++]= FN_LIBCHAR;
memcpy(toolpath+plugin_dir_len, tool_name, tool_name_len+1);
2011-12-02 16:27:13 +01:00
PAM_DEBUG((stderr, "PAM: execute pam sandbox [%s].\n", toolpath));
(void) execl(toolpath, toolpath, NULL);
PAM_DEBUG((stderr, "PAM: exec() failed.\n"));
exit(-1);
2011-12-02 16:27:13 +01:00
}
/* Parent process continues. */
2011-12-02 16:27:13 +01:00
PAM_DEBUG((stderr, "PAM: parent continues.\n"));
if (close(p_to_c[0]) < 0 ||
close(c_to_p[1]) < 0)
goto error_ret;
/* no user name yet ? read the client handshake packet with the user name */
if (info->user_name == 0)
{
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
return CR_ERROR;
}
else
pkt= NULL;
2011-12-02 16:27:13 +01:00
PAM_DEBUG((stderr, "PAM: parent sends user data [%s], [%s].\n",
info->user_name, info->auth_string));
2011-12-02 16:27:13 +01:00
#ifndef DBUG_OFF
2019-05-19 20:55:37 +02:00
field= pam_debug ? 1 : 0;
#else
field= 0;
#endif
2019-05-19 20:55:37 +02:00
field|= winbind_hack ? 2 : 0;
if (write(p_to_c[1], &field, 1) != 1 ||
write_string(p_to_c[1], (const uchar *) info->user_name,
info->user_name_length) ||
write_string(p_to_c[1], (const uchar *) info->auth_string,
info->auth_string_length))
goto error_ret;
for (;;)
{
PAM_DEBUG((stderr, "PAM: listening to the sandbox.\n"));
if (read(c_to_p[0], &field, 1) < 1)
{
PAM_DEBUG((stderr, "PAM: read failed.\n"));
goto error_ret;
}
2011-12-02 16:27:13 +01:00
if (field == AP_EOF)
{
PAM_DEBUG((stderr, "PAM: auth OK returned.\n"));
break;
}
2011-12-02 16:27:13 +01:00
switch (field)
{
case AP_AUTHENTICATED_AS:
PAM_DEBUG((stderr, "PAM: reading authenticated_as string.\n"));
if (read_string(c_to_p[0], info->authenticated_as,
sizeof(info->authenticated_as) - 1) < 0)
goto error_ret;
break;
case AP_CONV:
{
unsigned char buf[10240];
int buf_len;
PAM_DEBUG((stderr, "PAM: getting CONV string.\n"));
if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0)
goto error_ret;
if (!pkt || !*pkt || (buf[0] >> 1) != 2)
{
PAM_DEBUG((stderr, "PAM: sending CONV string.\n"));
if (vio->write_packet(vio, buf, buf_len))
goto error_ret;
PAM_DEBUG((stderr, "PAM: reading CONV answer.\n"));
if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
goto error_ret;
}
2011-12-02 16:27:13 +01:00
PAM_DEBUG((stderr, "PAM: answering CONV.\n"));
if (write_string(p_to_c[1], pkt, pkt_len))
goto error_ret;
pkt= NULL;
}
break;
2011-12-02 16:27:13 +01:00
default:
PAM_DEBUG((stderr, "PAM: unknown sandbox field.\n"));
goto error_ret;
}
}
result= CR_OK;
2011-12-02 16:27:13 +01:00
error_ret:
close(p_to_c[1]);
close(c_to_p[0]);
waitpid(proc_id, NULL, WNOHANG);
PAM_DEBUG((stderr, "PAM: auth result %d.\n", result));
return result;
}
#include "auth_pam_common.c"
static int init(void *p __attribute__((unused)))
{
if (use_cleartext_plugin)
info.client_auth_plugin= "mysql_clear_password";
if (!(opt_plugin_dir= dlsym(RTLD_DEFAULT, "opt_plugin_dir")))
return 1;
return 0;
}
2011-12-02 16:27:13 +01:00
maria_declare_plugin(pam)
{
MYSQL_AUTHENTICATION_PLUGIN,
2012-01-12 20:12:46 +01:00
&info,
2011-12-02 16:27:13 +01:00
"pam",
"MariaDB Corp",
2011-12-02 16:27:13 +01:00
"PAM based authentication",
PLUGIN_LICENSE_GPL,
init,
2011-12-02 16:27:13 +01:00
NULL,
0x0200,
2011-12-02 16:27:13 +01:00
NULL,
vars,
"2.0",
MariaDB_PLUGIN_MATURITY_GAMMA
2011-12-02 16:27:13 +01:00
}
maria_declare_plugin_end;