From 3bbb37e0ef1e77e9a93b7be7fb506bbbdd6a0400 Mon Sep 17 00:00:00 2001 From: Eugene Crosser Date: Wed, 4 Dec 2013 18:31:08 +0400 Subject: [PATCH] initial PAM module --- Makefile.am | 3 + authfile.c | 5 +- configure.ac | 16 +++++ pam_pcsc_cr.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index d974a5c..d6eeb62 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,6 +3,9 @@ AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 +libdir = $(PAMDIR) +DEFS = -DDEBUG_PAM -DPAM_DEBUG @DEFS@ + noinst_HEADERS = pcsc_cr.h token.h crypto_if.h crypto.h serial.h authobj.h \ authfile.h diff --git a/authfile.c b/authfile.c index 8c023d1..6937a66 100644 --- a/authfile.c +++ b/authfile.c @@ -215,7 +215,7 @@ struct _auth_obj authfile(const char *tokenid, } if (!ret.err) { - int bufsize = (w.userid?strlen(w.userid)+1:0) + ao.paylsize; + int bufsize = (w.userid?strlen(w.userid)+1:0) + ao.paylsize + 1; if (bufsize) { if ((ret.buffer = malloc(bufsize)) == NULL) { ret.err = "authfile malloc failed"; @@ -229,8 +229,9 @@ struct _auth_obj authfile(const char *tokenid, } if (ao.payload) { memcpy(p, ao.payload, ao.paylsize); + p[ao.paylsize] = '\0'; ret.payload = p; - ret.paylsize = ao.paylsize; + ret.paylsize = ao.paylsize+1; } } } diff --git a/configure.ac b/configure.ac index 17b40dd..43a5f59 100644 --- a/configure.ac +++ b/configure.ac @@ -19,6 +19,22 @@ AC_PROG_INSTALL AM_PROG_LIBTOOL PKG_PROG_PKG_CONFIG +AC_CHECK_HEADERS([security/pam_appl.h], [], [ + AC_MSG_ERROR([[PAM headers not found]]) +]) +AC_CHECK_HEADERS([security/pam_modules.h security/_pam_macros.h \ + security/pam_modutil.h], [], [], [ +#include +#include +]) +AC_CHECK_LIB([pam], [pam_start]) +AC_CHECK_FUNCS([pam_modutil_drop_priv]) +AC_SUBST(PAMDIR, "\$(exec_prefix)/lib/security") +AC_ARG_WITH(pam-dir, + [ --with-pam-dir=DIR path to install PAM module], + [PAMDIR="$withval"], + []) + PKG_CHECK_MODULES([PCSC], [libpcsclite]) AC_ARG_WITH(pcsclite-include-path, [ --with-pcsclite-include-path=PATH path to pcsclite includes], diff --git a/pam_pcsc_cr.c b/pam_pcsc_cr.c index e69de29..b101448 100644 --- a/pam_pcsc_cr.c +++ b/pam_pcsc_cr.c @@ -0,0 +1,170 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include "authobj.h" +#include "authfile.h" +#include "pcsc_cr.h" + +#ifndef PIC +# define PAM_STATIC +#endif + +#define PAM_SM_AUTH + +#ifdef HAVE_SECURITY_PAM_APPL_H +# include +#endif +#ifdef HAVE_SECURITY_PAM_MODULES_H +# include +#endif + +#ifndef PAM_EXTERN +# ifdef PAM_STATIC +# define PAM_EXTERN static +# else +# define PAM_EXTERN extern +# endif +#endif + +static struct _auth_chunk +token_key(const unsigned char *challenge, const int challengesize) +{ + struct _auth_chunk ho = {0}; + long rc; + int keysize = sizeof(ho.data); + + if ((rc = pcsc_cr(challenge, challengesize, ho.data, &keysize))) { + ho.err = pcsc_errstr(rc); + } + return ho; +} + +static void update_nonce(char *nonce, const int nonsize) +{ + int n = 0; + + sscanf(nonce, "%d", &n); + snprintf(nonce, nonsize, "%d", n+1); +} + +struct _cfg { + int verbose; +}; + +void parse_cfg(struct _cfg * const cfg, int argc, const char *argv[]) +{ + int i; + + for (i = 0; i < argc; i++) { + if (strchr(argv[i],':') && strchr(argv[i],'=')) + pcsc_option(argv[i]); + else if (!strcmp(argv[i], "verbose")) cfg->verbose = 1; + } +} + +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + struct _cfg cfg; + const char *tokenid = NULL; + const char *user; + const char *password; + struct _auth_obj ao; + int pam_err; + + parse_cfg(&cfg, argc, argv); + + if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { + if (cfg.verbose) syslog(LOG_ERR, "get_user failed: %s", + pam_strerror(pamh, pam_err)); + return (pam_err); + } + if (strspn(user, "0123456789") == strlen(user)) { + tokenid = user; + user = NULL; + } + + if (flags & PAM_DISALLOW_NULL_AUTHTOK) { + if ((pam_err = pam_get_item(pamh, PAM_AUTHTOK, + (const void **)&password))) { + if (cfg.verbose) syslog(LOG_ERR, + "get_authtok failed: %s", + pam_strerror(pamh, pam_err)); + return (pam_err); + } + } else { + password = ""; + } + + ao = authfile(tokenid, user, password, update_nonce, + NULL, 0, NULL, 0, token_key); + if (ao.err) { + if (cfg.verbose) syslog(LOG_INFO, "authfile: %s", ao.err); + return PAM_AUTH_ERR; + } else { + if (!user) + pam_set_item(pamh, PAM_USER, ao.data); + if (ao.payload && ao.payload[0]) + pam_set_item(pamh, PAM_AUTHTOK, ao.payload); + return PAM_SUCCESS; + } +} + +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; +} + +PAM_EXTERN int +pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_chauthtok(pam_handle_t *pamh, int flags, + int argc, const char *argv[]) +{ + return PAM_SERVICE_ERR; +} + +#ifdef PAM_MODULE_ENTRY +PAM_MODULE_ENTRY("pam_unix"); +#endif + +#ifdef PAM_STATIC +struct pam_module _pam_pcsc_cr_modstruct = { + "pam_pcsc_cr", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; +#endif -- 2.39.2