1
0
mirror of https://github.com/Yubico/yubico-pam.git synced 2024-11-29 00:24:11 +01:00

Add support of Mysql/Mariadb for the yubikey_mapping

Add support of Mysql/Mariadb for the yubikey_mapping

Mise à jour sql complete, manque la documentation

Final

clean

Add packages dependency

actions: apt update

Fix bool variable cause error build travis

Fix job #2

Fix job #3

Fix #4

fix &null

fix &null

fix &null

 Fix line 257 %s

test Apple integration

test Apple integration

Timeout Travis extend

Timeout travis extend

Fix klali comment

Fix warning

fix configure.ac

fix configure.ac

Update configure.ac

Update util.c

Update util.h

Update util.c

Update util.c

Update util.c

Update util.c

Fix white space

fix left column
This commit is contained in:
Benjamin AIMARD 2020-11-28 12:26:39 +01:00
parent 07892d21e0
commit b708e6dcf1
10 changed files with 269 additions and 13 deletions

View File

@ -30,8 +30,9 @@ jobs:
- name: Build yubico-pam
run: |
sudo apt update
sudo apt install -y libykclient-dev libykpers-1-dev libyubikey-dev \
libpam-dev help2man asciidoc-base
libpam-dev help2man asciidoc-base libmysqlclient-dev
autoreconf --install
./configure
make

View File

@ -8,7 +8,7 @@ on:
env:
SCAN_IMG:
yubico-yes-docker-local.jfrog.io/static-code-analysis/c:v1
COMPILE_DEPS: "libykclient-dev libykpers-1-dev libyubikey-dev"
COMPILE_DEPS: "libykclient-dev libykpers-1-dev libyubikey-dev libmysqlclient-dev"
jobs:
build:

View File

@ -1,4 +1,3 @@
sudo: required
language: c
os:
- linux
@ -7,13 +6,14 @@ compiler:
- gcc
- clang
env:
- CONFIGURE_ARGS="" EXTRA="libldap2-dev libykpers-1-dev libnet-ldap-server-perl"
- CONFIGURE_ARGS="--without-ldap" EXTRA="libykpers-1-dev"
- CONFIGURE_ARGS="--without-cr" EXTRA="libldap2-dev libnet-ldap-server-perl"
- CONFIGURE_ARGS="--without-ldap --without-cr"
- CONFIGURE_ARGS="" EXTRA="libldap2-dev libykpers-1-dev libnet-ldap-server-perl libmysqlclient-dev"
- CONFIGURE_ARGS="--without-ldap" EXTRA="libykpers-1-dev libmysqlclient-dev"
- CONFIGURE_ARGS="--without-cr" EXTRA="libldap2-dev libnet-ldap-server-perl libmysqlclient-dev"
- CONFIGURE_ARGS="--without-ldap --without-cr" EXTRA="libmysqlclient-dev"
script: tests/aux/build-and-test.sh
matrix:
jobs:
install: travis_wait 30 mvn install
include:
- compiler: gcc
os: linux
env: COVERAGE="--enable-coverage" EXTRA="libldap2-dev libykpers-1-dev libnet-ldap-server-perl lcov"
env: COVERAGE="--enable-coverage" EXTRA="libldap2-dev libykpers-1-dev libnet-ldap-server-perl lcov libmysqlclient-dev"

View File

@ -45,7 +45,12 @@ pam_yubico_la_LDFLAGS = -module -avoid-version
noinst_LTLIBRARIES = libpam_util.la libpam_real.la
libpam_util_la_SOURCES = util.c util.h
libpam_util_la_LIBADD = @LTLIBYUBIKEY@ @YKPERS_LIBS@
libpam_util_la_LIBADD = @LTLIBYUBIKEY@ @YKPERS_LIBS@
# if MYSQL_SUPPORT
AM_CFLAGS += @MYSQL_CFLAGS@
libpam_util_la_LIBADD += @MYSQL_LIBS@
# endif
libpam_real_la_SOURCES = pam_yubico.c

View File

@ -75,6 +75,19 @@ AC_ARG_WITH([ldap],
[libldap not found, will not be compiled (--without-ldap to disable ldap support)])],
[])])
AC_ARG_WITH([mysql],
[AS_HELP_STRING([--without-mysql],
[disable support for mysql])],
[],
[with_mysql=yes])
AS_IF([test "x$with_mysql" != xno],
[
PKG_CHECK_MODULES([MYSQL], [mysqlclient],
[AC_DEFINE([HAVE_MYSQL], [1],[Define if you have mysqlclient])],
[AC_MSG_WARN(
[libmysqlclient not found, will not be compiled (--without-mysql to disable mysql support)])])
])
AM_CONDITIONAL(MYSQL_SUPPORT,test "x$with_mysql" != xno)
AC_LIB_HAVE_LINKFLAGS([ykclient],, [#include <ykclient.h>],
[ykclient_set_proxy(0, 0)])

View File

@ -116,6 +116,18 @@ CA certitificate file for the LDAP connection.
*chalresp_path*=_path_::
Path of a system-wide directory where challenge-response files can be found for users. Default location is `$HOME/.yubico/`.
*mysql_server*=_mysqlserver_::
Hostname/Adress of mysql server. Example 10.0.0.1
*mysql_user*=_mysqluser_::
User for accessing to the database. Strongly recommended to use a specific user with read only access.
*mysql_password*=_mysqlpassword_::
Mysql password associated to the user.
*mysql_database*=_mysqldatabase_::
the name of the database. Example : otp
== EXAMPLES
auth sufficient pam_yubico.so id=16 debug

View File

@ -134,6 +134,11 @@ struct cfg
const char *user_attr;
const char *yubi_attr;
const char *yubi_attr_prefix;
const char *mysql_server;
const char *mysql_user;
const char *mysql_password;
const char *mysql_database;
unsigned int token_id_length;
enum key_mode mode;
const char *chalresp_path;
@ -164,8 +169,19 @@ authorize_user_token (struct cfg *cfg,
pam_handle_t *pamh)
{
int retval = AUTH_ERROR;
if (cfg->auth_file)
if (cfg->mysql_server)
{
#ifdef HAVE_MYSQL
/* Administrator had configured the database and specified is name
as an argument for this module.
*/
DBG ("Using Mariadb or Mysql Database");
retval = check_user_token_mysql(cfg->mysql_server, cfg->mysql_user, cfg->mysql_password, cfg->mysql_database, username, otp_id, cfg->debug, cfg->debug_file);
#else
DBG (("Trying to use MYSQL, but this function is not compiled in pam_yubico!!"));
#endif
}
else if (cfg->auth_file)
{
/* Administrator had configured the file and specified is name
as an argument for this module.
@ -874,6 +890,15 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
cfg->mode = CLIENT;
if (strncmp (argv[i], "chalresp_path=", 14) == 0)
cfg->chalresp_path = argv[i] + 14;
if (strncmp (argv[i], "mysql_server=", 13) == 0)
cfg->mysql_server = argv[i] + 13;
if (strncmp (argv[i], "mysql_user=", 11) == 0)
cfg->mysql_user = argv[i] + 11;
if (strncmp (argv[i], "mysql_password=", 15) == 0)
cfg->mysql_password = argv[i] + 15;
if (strncmp (argv[i], "mysql_database=", 15) == 0)
cfg->mysql_database = argv[i] + 15;
if (strncmp (argv[i], "debug_file=", 11) == 0)
{
const char *filename = argv[i] + 11;
@ -939,6 +964,9 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
DBG ("token_id_length=%u", cfg->token_id_length);
DBG ("mode=%s", cfg->mode == CLIENT ? "client" : "chresp" );
DBG ("chalresp_path=%s", cfg->chalresp_path ? cfg->chalresp_path : "(null)");
DBG ("mysql_server=%s", cfg->mysql_server ? cfg->mysql_server : "(null)");
DBG ("mysql_user=%s", cfg->mysql_user ? cfg->mysql_user : "(null)");
DBG ("mysql_database=%s", cfg->mysql_database ? cfg->mysql_database : "(null)");
if (fd != -1)
close(fd);

View File

@ -7,7 +7,7 @@ autoreconf -i
if [ "x$TRAVIS_OS_NAME" != "xosx" ]; then
sudo add-apt-repository -y ppa:yubico/stable
sudo apt-get update -qq || true
sudo apt-get install -qq -y --no-install-recommends libykclient-dev libpam0g-dev libyubikey-dev asciidoc docbook-xsl xsltproc libxml2-utils $EXTRA
sudo apt-get install -qq -y --no-install-recommends libykclient-dev libpam0g-dev libyubikey-dev asciidoc docbook-xsl xsltproc libxml2-utils libmysqlclient-dev $EXTRA
else
brew update
brew install pkg-config
@ -17,6 +17,7 @@ else
brew install libyubikey
brew install ykclient
brew install ykpers
brew install mysql-connector-c #Mysql
cpanp install Net::LDAP::Server
# this is required so asciidoc can find the xml catalog

193
util.c
View File

@ -52,6 +52,10 @@
#include <ykdef.h>
#endif /* HAVE_CR */
#ifdef HAVE_MYSQL
#include <mysql.h>
#endif
int
get_user_cfgfile_path(const char *common_path, const char *filename, const struct passwd *user, char **fn)
{
@ -93,6 +97,195 @@ get_user_cfgfile_path(const char *common_path, const char *filename, const struc
return 1;
}
#ifdef HAVE_MYSQL
/*
* This function will look for users name with valid user token id, in a database Mysql
*
* Returns one of AUTH_FOUND, AUTH_NOT_FOUND, AUTH_NO_TOKENS, AUTH_ERROR.
*
* Need database with this table structure:
*
* CREATE TABLE IF NOT EXISTS `otp`.`yubikey_mappings`(
* `otp_id` VARCHAR(12) NOT NULL ,
* `username` VARCHAR(64) NOT NULL ,
* PRIMARY KEY (`otp_id`(12))
* );
*
*/
int
check_user_token_mysql(const char *mysql_server,
const char *mysql_user,
const char *mysql_password,
const char *mysql_database,
const char *username,
const char *otp_id,
int verbose,
FILE *debug_file)
{
int retval = AUTH_ERROR;
int fd;
struct stat st;
FILE *opwfile;
MYSQL *con = NULL;
MYSQL_STMT *stmt;
MYSQL_BIND ps_params[2];
MYSQL_BIND bind[1];
long unsigned int str_username;
long unsigned int str_otp;
long unsigned int length;
int int_data;
int row_count;
bool is_null;
bool error;
if(mysql_library_init(0, NULL, NULL)){
if(verbose){
D (debug_file, "could not initialize MySQL client library");
}
return retval;
}
con = mysql_init(con);
if(!con) {
if(verbose)
D (debug_file, "out of memorys");
return retval;
}
if(mysql_real_connect(con, mysql_server,mysql_user,mysql_password,mysql_database, 0, NULL, 0) == NULL)
{
if(verbose)
D (debug_file, "Connection failed ...");
return retval;
}
stmt = mysql_stmt_init(con);
if(!stmt)
{
if(verbose)
D (debug_file, "Connection failed ... 2");
return retval;
}
const char *sql = "SELECT count(username) FROM yubikey_mappings WHERE username = ?;";
const char *sql2 = "SELECT count(username) FROM yubikey_mappings WHERE username = ? and otp_id = ?;";
if(otp_id == NULL)
{
if(mysql_stmt_prepare(stmt, sql, strlen(sql)))
{
if(verbose)
D (debug_file, "mysql_stmt_prepare() failed %s", mysql_stmt_error(stmt));
return retval;
}
}else{
if(mysql_stmt_prepare(stmt, sql2, strlen(sql2)))
{
if(verbose)
D (debug_file, "mysql_stmt_prepare() failed %s", mysql_stmt_error(stmt));
return retval;
}
}
str_username = strlen(username);
memset(ps_params, 0, sizeof(ps_params));
ps_params[0].buffer_type = MYSQL_TYPE_STRING;
ps_params[0].buffer = (char *)username;
ps_params[0].buffer_length = str_username;
ps_params[0].length = &str_username;
ps_params[0].is_null = 0;
if(otp_id != NULL)
{
str_otp= strlen(otp_id);
ps_params[1].buffer_type = MYSQL_TYPE_STRING;
ps_params[1].buffer = (char *)otp_id;
ps_params[1].buffer_length = str_otp;
ps_params[1].length = &str_otp;
ps_params[1].is_null = 0;
}
if(mysql_stmt_bind_param(stmt, ps_params))
{
if(verbose)
D (debug_file, "mysql_stmt_bind_param() failed %s", mysql_stmt_error(stmt));
return retval;
}
if(mysql_stmt_execute(stmt))
{
if(verbose)
D (debug_file, "mysql_stmt_execute() failed %s", mysql_stmt_error(stmt));
return retval;
}
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].buffer = (char *)&int_data;
bind[0].length = &length;
bind[0].is_null = &is_null;
bind[0].error = &error;
if(mysql_stmt_bind_result(stmt, bind))
{
if(verbose)
D (debug_file, "mysql_stmt_bind_result() failed %s", mysql_stmt_error(stmt));
}
if(mysql_stmt_store_result(stmt))
{
if(verbose)
D (debug_file, "mysql_stmt_store_result() failed %s", mysql_stmt_error(stmt));
return retval;
}
while(!mysql_stmt_fetch(stmt))
{
if(is_null)
{
D (debug_file, "mysql_stmt_fetch() failed");
}
else
{
if(otp_id != NULL){
if(int_data)
{
return AUTH_FOUND;
}
else
{
return AUTH_NOT_FOUND;
}
}
else if(otp_id == NULL)
{
if(int_data)
{
return AUTH_NOT_FOUND;
}
else
{
return AUTH_NO_TOKENS;
}
}
}
}
if(mysql_stmt_close(stmt))
{
if(verbose)
D (debug_file, "mysql_stmt_close() failed %s", mysql_stmt_error(stmt));
return retval;
}
mysql_close(con);
mysql_library_end();
return retval;
}
#endif
/*
* This function will look for users name with valid user token id.

3
util.h
View File

@ -51,6 +51,9 @@
#define AUTH_NOT_FOUND -1 /* The requested token is not associated to the user */
int get_user_cfgfile_path(const char *common_path, const char *filename, const struct passwd *user, char **fn);
#ifdef HAVE_MYSQL
int check_user_token_mysql(const char *mysql_server,const char *mysql_user,const char *mysql_password,const char *mysql_database,const char *username,const char *otp_id,int verbose,FILE *debug_file);
#endif
int check_user_token(const char *authfile, const char *username, const char *otp_id, int verbose, FILE *debug_file);
#if HAVE_CR