From b9e491632133440ec14df4396f00a12b7c5b716c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 9 Aug 2012 14:39:31 +0200 Subject: [PATCH] Add xauth-pam, an XAuth backend verifying credentials with PAM --- configure.in | 6 +- src/libcharon/Makefile.am | 7 + src/libcharon/plugins/xauth_pam/Makefile.am | 17 ++ src/libcharon/plugins/xauth_pam/xauth_pam.c | 215 ++++++++++++++++++ src/libcharon/plugins/xauth_pam/xauth_pam.h | 49 ++++ .../plugins/xauth_pam/xauth_pam_plugin.c | 60 +++++ .../plugins/xauth_pam/xauth_pam_plugin.h | 42 ++++ 7 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/plugins/xauth_pam/Makefile.am create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam.c create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam.h create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h diff --git a/configure.in b/configure.in index c5fd1d3c6..a1adb8cc1 100644 --- a/configure.in +++ b/configure.in @@ -134,6 +134,7 @@ ARG_ENABL_SET([eap-tnc], [enable EAP TNC trusted network connect module.] ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.]) ARG_DISBL_SET([xauth-generic], [disable generic XAuth backend.]) ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verify passwords.]) +ARG_ENABL_SET([xauth-pam], [enable XAuth backend using PAM to verify passwords.]) ARG_ENABL_SET([tnc-ifmap], [enable TNC IF-MAP module.]) ARG_ENABL_SET([tnc-pdp], [enable TNC policy decision point module.]) ARG_ENABL_SET([tnc-imc], [enable TNC IMC module.]) @@ -745,7 +746,7 @@ if test x$nm = xtrue; then AC_SUBST(nm_LIBS) fi -if test x$eap_gtc = xtrue; then +if test x$xauth_pam = xtrue; then AC_HAVE_LIBRARY([pam],[LIBS="$LIBS"],[AC_MSG_ERROR([PAM library not found])]) AC_CHECK_HEADER([security/pam_appl.h],,[AC_MSG_ERROR([PAM header security/pam_appl.h not found!])]) fi @@ -900,6 +901,7 @@ ADD_PLUGIN([eap-peap], [c charon nm]) ADD_PLUGIN([eap-tnc], [c charon]) ADD_PLUGIN([xauth-generic], [c charon]) ADD_PLUGIN([xauth-eap], [c charon]) +ADD_PLUGIN([xauth-pam], [c charon]) ADD_PLUGIN([tnc-ifmap], [c charon]) ADD_PLUGIN([tnc-pdp], [c charon]) ADD_PLUGIN([tnc-imc], [c charon]) @@ -1026,6 +1028,7 @@ AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue) AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue) AM_CONDITIONAL(USE_XAUTH_GENERIC, test x$xauth_generic = xtrue) AM_CONDITIONAL(USE_XAUTH_EAP, test x$xauth_eap = xtrue) +AM_CONDITIONAL(USE_XAUTH_PAM, test x$xauth_pam = xtrue) AM_CONDITIONAL(USE_TNC_IFMAP, test x$tnc_ifmap = xtrue) AM_CONDITIONAL(USE_TNC_PDP, test x$tnc_pdp = xtrue) AM_CONDITIONAL(USE_TNC_IMC, test x$tnc_imc = xtrue) @@ -1204,6 +1207,7 @@ AC_OUTPUT( src/libcharon/plugins/eap_radius/Makefile src/libcharon/plugins/xauth_generic/Makefile src/libcharon/plugins/xauth_eap/Makefile + src/libcharon/plugins/xauth_pam/Makefile src/libcharon/plugins/tnc_ifmap/Makefile src/libcharon/plugins/tnc_pdp/Makefile src/libcharon/plugins/tnc_imc/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index a254c0336..2d4227990 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -546,3 +546,10 @@ if MONOLITHIC libcharon_la_LIBADD += plugins/xauth_eap/libstrongswan-xauth-eap.la endif endif + +if USE_XAUTH_PAM + SUBDIRS += plugins/xauth_pam +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_pam/libstrongswan-xauth-pam.la +endif +endif diff --git a/src/libcharon/plugins/xauth_pam/Makefile.am b/src/libcharon/plugins/xauth_pam/Makefile.am new file mode 100644 index 000000000..47521a3ff --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-pam.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-pam.la +endif + +libstrongswan_xauth_pam_la_SOURCES = \ + xauth_pam_plugin.h xauth_pam_plugin.c \ + xauth_pam.h xauth_pam.c + +libstrongswan_xauth_pam_la_LDFLAGS = -module -avoid-version -lpam diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam.c b/src/libcharon/plugins/xauth_pam/xauth_pam.c new file mode 100644 index 000000000..98c1a97a4 --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * 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; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include "xauth_pam.h" + +#include +#include + +#include + +typedef struct private_xauth_pam_t private_xauth_pam_t; + +/** + * Private data of an xauth_pam_t object. + */ +struct private_xauth_pam_t { + + /** + * Public interface. + */ + xauth_pam_t public; + + /** + * ID of the peer + */ + identification_t *peer; +}; + +METHOD(xauth_method_t, initiate, status_t, + private_xauth_pam_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +/** + * PAM conv callback function + */ +static int auth_conv(int num_msg, const struct pam_message **msg, + struct pam_response **resp, char *password) +{ + struct pam_response *response; + + if (num_msg != 1) + { + return PAM_CONV_ERR; + } + response = malloc(sizeof(struct pam_response)); + response->resp = strdup(password); + response->resp_retcode = 0; + *resp = response; + return PAM_SUCCESS; +} + +/** + * Authenticate a username/password using PAM + */ +static bool authenticate(char *service, char *user, char *password) +{ + pam_handle_t *pamh = NULL; + static struct pam_conv conv; + int ret; + + conv.conv = (void*)auth_conv; + conv.appdata_ptr = password; + + ret = pam_start(service, user, &conv, &pamh); + if (ret != PAM_SUCCESS) + { + DBG1(DBG_IKE, "XAuth pam_start for '%s' failed: %s", + user, pam_strerror(pamh, ret)); + return FALSE; + } + ret = pam_authenticate(pamh, 0); + if (ret == PAM_SUCCESS) + { + ret = pam_acct_mgmt(pamh, 0); + if (ret != PAM_SUCCESS) + { + DBG1(DBG_IKE, "XAuth pam_acct_mgmt for '%s' failed: %s", + user, pam_strerror(pamh, ret)); + } + } + else + { + DBG1(DBG_IKE, "XAuth pam_authenticate for '%s' failed: %s", + user, pam_strerror(pamh, ret)); + } + pam_end(pamh, ret); + return ret == PAM_SUCCESS; +} + +/** + * Convert configuration attribute content to a null-terminated string + */ +static void attr2string(char *buf, size_t len, chunk_t chunk) +{ + if (chunk.len && chunk.len < len) + { + snprintf(buf, len, "%.*s", (int)chunk.len, chunk.ptr); + } +} + +METHOD(xauth_method_t, process, status_t, + private_xauth_pam_t *this, cp_payload_t *in, cp_payload_t **out) +{ + char *service, user[128] = "", pass[128] = "", *pos; + configuration_attribute_t *attr; + enumerator_t *enumerator; + chunk_t chunk; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + /* trim to username part if email address given */ + chunk = attr->get_chunk(attr); + pos = memchr(chunk.ptr, '@', chunk.len); + if (pos) + { + chunk.len = (u_char*)pos - chunk.ptr; + } + attr2string(user, sizeof(user), chunk); + break; + case XAUTH_USER_PASSWORD: + attr2string(pass, sizeof(pass), attr->get_chunk(attr)); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user[0] || !pass[0]) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + + this->peer->destroy(this->peer); + this->peer = identification_create_from_string(user); + + /* Look for PAM service, with a legacy fallback for the eap-gtc plugin. + * Default to "login". */ + service = lib->settings->get_str(lib->settings, + "%s.plugins.xauth-pam.pam_service", + lib->settings->get_str(lib->settings, + "%s.plugins.eap-gtc.pam_service", + "login", charon->name), + charon->name); + + if (authenticate(service, user, pass)) + { + DBG1(DBG_IKE, "PAM authentication of '%s' successful", user); + return SUCCESS; + } + return FAILED; +} + +METHOD(xauth_method_t, get_identity, identification_t*, + private_xauth_pam_t *this) +{ + return this->peer; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_pam_t *this) +{ + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_pam_t *xauth_pam_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_pam_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate, + .process = _process, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .peer = peer->clone(peer), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam.h b/src/libcharon/plugins/xauth_pam/xauth_pam.h new file mode 100644 index 000000000..f2d310c0d --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * 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; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +/** + * @defgroup xauth_pam_i xauth_pam + * @{ @ingroup xauth_pam + */ + +#ifndef XAUTH_PAM_H_ +#define XAUTH_PAM_H_ + +typedef struct xauth_pam_t xauth_pam_t; + +#include + +/** + * XAuth plugin using Pluggable Authentication Modules to verify credentials. + */ +struct xauth_pam_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the XAuth method using PAM, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_pam_t object + */ +xauth_pam_t *xauth_pam_create_server(identification_t *server, + identification_t *peer); + +#endif /** XAUTH_PAM_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c new file mode 100644 index 000000000..363aaf003 --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * 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; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +#include "xauth_pam_plugin.h" +#include "xauth_pam.h" + +#include + +METHOD(plugin_t, get_name, char*, + xauth_pam_plugin_t *this) +{ + return "xauth-pam"; +} + +METHOD(plugin_t, get_features, int, + xauth_pam_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_pam_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "pam"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_pam_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_pam_plugin_create() +{ + xauth_pam_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h new file mode 100644 index 000000000..b75268880 --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * 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; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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. + */ + +/** + * @defgroup xauth_pam xauth_pam + * @ingroup cplugins + * + * @defgroup xauth_pam_plugin xauth_pam_plugin + * @{ @ingroup xauth_pam + */ + +#ifndef XAUTH_PAM_PLUGIN_H_ +#define XAUTH_PAM_PLUGIN_H_ + +#include + +typedef struct xauth_pam_plugin_t xauth_pam_plugin_t; + +/** + * XAuth plugin using Pluggable Authentication Modules to verify credentials. + */ +struct xauth_pam_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_PAM_PLUGIN_H_ @}*/