diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index 470f30974..50cfbf937 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -39,6 +39,9 @@ libimcv_la_SOURCES = \ pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \ pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c +ipsec_SCRIPTS = imv/_imv_policy +EXTRA_DIST = imv/_imv_policy + SUBDIRS = . if USE_IMC_TEST diff --git a/src/libimcv/imv/_imv_policy b/src/libimcv/imv/_imv_policy new file mode 100755 index 000000000..68a963c27 --- /dev/null +++ b/src/libimcv/imv/_imv_policy @@ -0,0 +1,39 @@ +#! /bin/sh +# default TNC policy command script +# +# Copyright 2013 Andreas Steffen +# HSR Hochschule fuer Technik Rapperswil +# +# 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. +# +# CAUTION: Installing a new version of strongSwan will install a new +# copy of this script, wiping out any custom changes you make. If +# you need changes, make a copy of this under another name, and customize +# that, and use the "libimcv.policy_script = " option in strongswan.conf +# to make strongSwan use yours instead of this default one. + +# Environment variables that this script gets +# +# TNC_SESSION_ID +# unique session ID used as a reference by the policy +# manager. +# +case "$1" in +start) + echo "start session $TNC_SESSION_ID" + ;; +stop) + echo "stop session $TNC_SESSION_ID" + ;; +*) echo "$0: unknown command '$1'" + exit 1 + ;; +esac diff --git a/src/libimcv/imv/imv_database.c b/src/libimcv/imv/imv_database.c index 1402e2e81..b49677f19 100644 --- a/src/libimcv/imv/imv_database.c +++ b/src/libimcv/imv/imv_database.c @@ -13,17 +13,22 @@ * for more details. */ +#define _GNU_SOURCE + +#include +#include +#include + #include "imv_database.h" #include -#include -#include - typedef struct private_imv_database_t private_imv_database_t; #define SESSION_TIME_DELTA_MAX 2 /* seconds */ +#define DEFAULT_POLICY_SCRIPT "ipsec _imv_policy" + /** * Private data of a imv_database_t object. * @@ -40,6 +45,11 @@ struct private_imv_database_t { */ database_t *db; + /** + * policy script + */ + char *script; + }; METHOD(imv_database_t, get_session_id, int, @@ -165,6 +175,49 @@ METHOD(imv_database_t, add_device, int, return did; } +METHOD(imv_database_t, policy_script, bool, + private_imv_database_t *this, int session_id, bool start) +{ + char command[512], resp[128], *last; + FILE *shell; + + snprintf(command, sizeof(command), "2>&1 TNC_SESSION_ID='%d' %s %s", + session_id, this->script, start ? "start" : "stop"); + DBG3(DBG_IMV, "running policy script: %s", command); + + shell = popen(command, "r"); + if (shell == NULL) + { + DBG1(DBG_IMV, "could not execute policy script '%s'", + this->script); + return FALSE; + } + while (TRUE) + { + if (fgets(resp, sizeof(resp), shell) == NULL) + { + if (ferror(shell)) + { + DBG1(DBG_IMV, "error reading output from policy script"); + } + break; + } + else + { + last = resp + strlen(resp) - 1; + if (last >= resp && *last == '\n') + { + /* replace trailing '\n' */ + *last = '\0'; + } + DBG1(DBG_IMV, "policy: %s", resp); + } + } + pclose(shell); + + return TRUE; +} + METHOD(imv_database_t, get_database, database_t*, private_imv_database_t *this) { @@ -190,10 +243,13 @@ imv_database_t *imv_database_create(char *uri) .get_session_id = _get_session_id, .add_product = _add_product, .add_device = _add_device, + .policy_script = _policy_script, .get_database = _get_database, .destroy = _destroy, }, .db = lib->db->create(lib->db, uri), + .script = lib->settings->get_str(lib->settings, + "libimcv.policy_script", DEFAULT_POLICY_SCRIPT), ); if (!this->db) diff --git a/src/libimcv/imv/imv_database.h b/src/libimcv/imv/imv_database.h index 3b3cbd6a9..c49a94183 100644 --- a/src/libimcv/imv/imv_database.h +++ b/src/libimcv/imv/imv_database.h @@ -56,12 +56,21 @@ struct imv_database_t { /** * Add device identification to a session * - * @param session_id Sessiion ID + * @param session_id Session ID * @param device Device identification * @return Device ID or 0 if not available */ int (*add_device)(imv_database_t *this, int session_id, chunk_t device); + /** + * Announce session start/stop to policy script + * + * @param session_id Session ID + * @param start TRUE if session start, FALSE if session stop + * @return TRUE if command successful, FALSE otherwise + */ + bool (*policy_script)(imv_database_t *this, int session_id, bool start); + /** * Get database handle * diff --git a/src/libimcv/plugins/imv_os/imv_os.c b/src/libimcv/plugins/imv_os/imv_os.c index 48af9c5a1..560b8bf11 100644 --- a/src/libimcv/plugins/imv_os/imv_os.c +++ b/src/libimcv/plugins/imv_os/imv_os.c @@ -96,6 +96,8 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, TNC_ConnectionState new_state) { imv_state_t *state; + imv_database_t *imv_db; + int session_id; if (!imv_os) { @@ -108,6 +110,12 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, state = imv_os_state_create(connection_id); return imv_os->create_state(imv_os, state); case TNC_CONNECTION_STATE_DELETE: + imv_db = imv_os->get_database(imv_os); + if (imv_db && imv_os->get_state(imv_os, connection_id, &state)) + { + session_id = state->get_session_id(state); + imv_db->policy_script(imv_db, session_id, FALSE); + } return imv_os->delete_state(imv_os, connection_id); default: return imv_os->change_state(imv_os, connection_id, @@ -284,7 +292,7 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) ita_attr_settings_t *attr_cast; imv_database_t *imv_db; enumerator_t *e; - int did; + int session_id, device_id; char *name; chunk_t value; @@ -304,9 +312,13 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) imv_db = imv_os->get_database(imv_os); if (imv_db) { - did = imv_db->add_device(imv_db, - state->get_session_id(state), value); - os_state->set_device_id(os_state, did); + session_id = state->get_session_id(state); + device_id = imv_db->add_device(imv_db, + session_id, value); + os_state->set_device_id(os_state, device_id); + + /* trigger the policy manager */ + imv_db->policy_script(imv_db, session_id, TRUE); } } DBG1(DBG_IMV, "setting '%s'\n %.*s", diff --git a/src/libimcv/plugins/imv_os/imv_os_database.c b/src/libimcv/plugins/imv_os/imv_os_database.c index 6f7b29b6d..c7f9b6be1 100644 --- a/src/libimcv/plugins/imv_os/imv_os_database.c +++ b/src/libimcv/plugins/imv_os/imv_os_database.c @@ -191,8 +191,6 @@ METHOD(imv_os_database_t, set_device_info, void, private_imv_os_database_t *this, int session_id, int count, int count_update, int count_blacklist, u_int flags) { - enumerator_t *e; - this->db->execute(this->db, NULL, "INSERT INTO device_infos (session, count, count_update, " "count_blacklist, flags) VALUES (?, ?, ?, ?, ?)",