mirror of
https://github.com/Yubico/yubico-pam.git
synced 2024-11-29 00:24:11 +01:00
Merge branch 'pr-221'
This commit is contained in:
commit
d468b61caf
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
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
|
||||
|
2
.github/workflows/scan.yml
vendored
2
.github/workflows/scan.yml
vendored
@ -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:
|
||||
|
14
.travis.yml
14
.travis.yml
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
13
configure.ac
13
configure.ac
@ -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)])
|
||||
|
@ -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
|
||||
|
32
pam_yubico.c
32
pam_yubico.c
@ -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);
|
||||
|
@ -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
193
util.c
@ -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
3
util.h
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user