Merge branch 'swima'

This commit is contained in:
Andreas Steffen
2017-07-08 23:20:32 +02:00
113 changed files with 10006 additions and 630 deletions
+4 -1
View File
@@ -24,7 +24,8 @@ options = \
options/scepclient.opt \
options/starter.opt \
options/swanctl.opt \
options/tnc.opt
options/tnc.opt \
options/sw-collector.opt
plugins = \
plugins/addrblock.opt \
@@ -60,11 +61,13 @@ plugins = \
plugins/imc-os.opt \
plugins/imc-scanner.opt \
plugins/imc-swid.opt \
plugins/imc-swima.opt \
plugins/imc-test.opt \
plugins/imv-attestation.opt \
plugins/imv-os.opt \
plugins/imv-scanner.opt \
plugins/imv-swid.opt \
plugins/imv-swima.opt \
plugins/imv-test.opt \
plugins/ipseckey.opt \
plugins/led.opt \
+29
View File
@@ -0,0 +1,29 @@
sw-collector {}
Options for the sw-collector tool.
Options for the sw-collector tool.
sw-collector.database =
Path to software collector database containing event timestamps, software
creation and deletion events and collected software identifiers.
sw-collector.history =
Path pointing to apt history.log file.
sw-collector.first_time = 0000-00-00T00:00:00Z
Time in UTC when the Linux OS was installed.
sw-collector.rest_api.uri =
HTTP URI of the central collector's REST API.
sw-collector.rest_api.timeout = 120
Timeout of REST API HTTP POST transaction.
sw-collector.tag_creator.name = strongSwan Project
Name of the tagCreator entity.
sw-collector.tag_creator.regid = strongswan.org
regid of the tagCreator entity.
sw-collector.load =
Plugins to load in sw-collector tool.
+19
View File
@@ -0,0 +1,19 @@
libimcv.plugins.imc-swima.swid_database =
Path to software collector database containing event timestamps, software
creation and deletion events and collected software identifiers.
libimcv.plugins.imc-swima.swid_epoch = 0x11223344
Set 32 bit epoch value for event IDs manually if software collector database
is not available.
libimcv.plugins.imc-swima.swid_directory = ${prefix}/share
Directory where SWID tags are located.
libimcv.plugins.imc-swima.swid_generator = /usr/local/bin/swid_generator
SWID generator command to be executed.
libimcv.plugins.imc-swima.swid_pretty = FALSE
Generate XML-encoded SWID tags with pretty indentation.
libimcv.plugins.imc-swima.swid_full = FALSE
Include file information in the XML-encoded SWID tags.
+5
View File
@@ -0,0 +1,5 @@
libimcv.plugins.imv-swima.rest_api.uri =
HTTP URI of the SWID REST API.
libimcv.plugins.imv-swima.rest_api.timeout = 120
Timeout of SWID REST API HTTP POST transaction.
+11 -2
View File
@@ -247,6 +247,8 @@ ARG_ENABL_SET([imc-attestation],[enable IMC attestation module.])
ARG_ENABL_SET([imv-attestation],[enable IMV attestation module.])
ARG_ENABL_SET([imc-swid], [enable IMC swid module.])
ARG_ENABL_SET([imv-swid], [enable IMV swid module.])
ARG_ENABL_SET([imc-swima], [enable IMC swima module.])
ARG_ENABL_SET([imv-swima], [enable IMV swima module.])
ARG_ENABL_SET([imc-hcd], [enable IMC hcd module.])
ARG_ENABL_SET([imv-hcd], [enable IMV hcd module.])
ARG_ENABL_SET([tnc-ifmap], [enable TNC IF-MAP module. Requires libxml])
@@ -422,7 +424,7 @@ if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue -o x$tnc_t
tls=true;
fi
if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$imv_scanner = xtrue -o x$imc_os = xtrue -o x$imv_os = xtrue -o x$imc_attestation = xtrue -o x$imv_attestation = xtrue -o x$imc_swid = xtrue -o x$imv_swid = xtrue -o x$imc_hcd = xtrue -o x$imv_hcd = xtrue; then
if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$imv_scanner = xtrue -o x$imc_os = xtrue -o x$imv_os = xtrue -o x$imc_attestation = xtrue -o x$imv_attestation = xtrue -o x$imc_swid = xtrue -o x$imv_swid = xtrue -o x$imc_swima = xtrue -o x$imv_swima = xtrue -o x$imc_hcd = xtrue -o x$imv_hcd = xtrue; then
imcv=true;
fi
@@ -1001,7 +1003,7 @@ if test x$tss_tss2 = xtrue; then
AC_SUBST(tss2_LIBS)
fi
if test x$imv_swid = xtrue; then
if test x$imc_swima = xtrue -o $imv_swima = xtrue -o x$imv_swid = xtrue; then
PKG_CHECK_MODULES(json, [json-c], [],
[PKG_CHECK_MODULES(json, [json])])
AC_SUBST(json_CFLAGS)
@@ -1607,6 +1609,8 @@ AM_CONDITIONAL(USE_IMC_ATTESTATION, test x$imc_attestation = xtrue)
AM_CONDITIONAL(USE_IMV_ATTESTATION, test x$imv_attestation = xtrue)
AM_CONDITIONAL(USE_IMC_SWID, test x$imc_swid = xtrue)
AM_CONDITIONAL(USE_IMV_SWID, test x$imv_swid = xtrue)
AM_CONDITIONAL(USE_IMC_SWIMA, test x$imc_swima = xtrue)
AM_CONDITIONAL(USE_IMV_SWIMA, test x$imv_swima = xtrue)
AM_CONDITIONAL(USE_IMC_HCD, test x$imc_hcd = xtrue)
AM_CONDITIONAL(USE_IMV_HCD, test x$imv_hcd = xtrue)
AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue)
@@ -1707,6 +1711,9 @@ fi
if test x$fuzzing = xtrue; then
AC_DEFINE([USE_FUZZING], [], [build code for fuzzing])
fi
if test x$imc_swima = xtrue -o x$imv_swima = xtrue -o x$imv_swid = xtrue ; then
AC_DEFINE([USE_JSON], [], [build code for JSON])
fi
# ====================================================
# options for enabled modules (see conf/Makefile.am)
@@ -1833,6 +1840,8 @@ AC_CONFIG_FILES([
src/libimcv/plugins/imv_attestation/Makefile
src/libimcv/plugins/imc_swid/Makefile
src/libimcv/plugins/imv_swid/Makefile
src/libimcv/plugins/imc_swima/Makefile
src/libimcv/plugins/imv_swima/Makefile
src/libimcv/plugins/imc_hcd/Makefile
src/libimcv/plugins/imv_hcd/Makefile
src/charon/Makefile
+36 -2
View File
@@ -2,7 +2,11 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libtpmtss \
-DIPSEC_SCRIPT=\"${ipsec_script}\"
-DIPSEC_SCRIPT=\"${ipsec_script}\" \
-DSWID_DIRECTORY=\"${prefix}/share\"
AM_CFLAGS = \
$(json_CFLAGS)
ipseclib_LTLIBRARIES = libimcv.la
@@ -12,7 +16,8 @@ libimcv_la_LDFLAGS = \
libimcv_la_LIBADD = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libtncif/libtncif.la \
$(top_builddir)/src/libtpmtss/libtpmtss.la
$(top_builddir)/src/libtpmtss/libtpmtss.la \
$(json_LIBS)
if USE_WINDOWS
libimcv_la_LIBADD += -lws2_32
@@ -49,6 +54,9 @@ libimcv_la_SOURCES = \
ietf/ietf_attr_product_info.h ietf/ietf_attr_product_info.c \
ietf/ietf_attr_remediation_instr.h ietf/ietf_attr_remediation_instr.c \
ietf/ietf_attr_string_version.h ietf/ietf_attr_string_version.c \
ietf/swima/ietf_swima_attr_req.h ietf/swima/ietf_swima_attr_req.c \
ietf/swima/ietf_swima_attr_sw_inv.h ietf/swima/ietf_swima_attr_sw_inv.c \
ietf/swima/ietf_swima_attr_sw_ev.h ietf/swima/ietf_swima_attr_sw_ev.c \
ita/ita_attr.h ita/ita_attr.c \
ita/ita_attr_command.h ita/ita_attr_command.c \
ita/ita_attr_dummy.h ita/ita_attr_dummy.c \
@@ -84,6 +92,7 @@ libimcv_la_SOURCES = \
pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
pwg/pwg_attr.h pwg/pwg_attr.c \
pwg/pwg_attr_vendor_smi_code.h pwg/pwg_attr_vendor_smi_code.c \
rest/rest.h rest/rest.c \
seg/seg_contract.h seg/seg_contract.c \
seg/seg_contract_manager.h seg/seg_contract_manager.c \
seg/seg_env.h seg/seg_env.c \
@@ -91,6 +100,13 @@ libimcv_la_SOURCES = \
swid/swid_inventory.h swid/swid_inventory.c \
swid/swid_tag.h swid/swid_tag.c \
swid/swid_tag_id.h swid/swid_tag_id.c \
swima/swima_data_model.h swima/swima_data_model.c \
swima/swima_record.h swima/swima_record.c \
swima/swima_event.h swima/swima_event.c \
swima/swima_events.h swima/swima_events.c \
swima/swima_inventory.h swima/swima_inventory.c \
swima/swima_collector.h swima/swima_collector.c \
swima/swima_error.h swima/swima_error.c \
tcg/tcg_attr.h tcg/tcg_attr.c \
tcg/pts/tcg_pts_attr_proto_caps.h tcg/pts/tcg_pts_attr_proto_caps.c \
tcg/pts/tcg_pts_attr_dh_nonce_params_req.h tcg/pts/tcg_pts_attr_dh_nonce_params_req.c \
@@ -173,6 +189,14 @@ if USE_IMV_SWID
SUBDIRS += plugins/imv_swid
endif
if USE_IMC_SWIMA
SUBDIRS += plugins/imc_swima
endif
if USE_IMV_SWIMA
SUBDIRS += plugins/imv_swima
endif
if USE_IMC_HCD
SUBDIRS += plugins/imc_hcd
endif
@@ -190,8 +214,18 @@ imcv_tests_SOURCES = \
pa_tnc/pa_tnc_attr_manager.c \
seg/seg_env.c seg/seg_contract.c \
seg/seg_contract_manager.c \
swima/swima_data_model.c \
swima/swima_event.c \
swima/swima_events.c \
swima/swima_record.c \
swima/swima_inventory.c \
swima/swima_collector.c \
suites/test_imcv_seg.c \
suites/test_imcv_swima.c \
ietf/ietf_attr_pa_tnc_error.c \
ietf/swima/ietf_swima_attr_req.c \
ietf/swima/ietf_swima_attr_sw_inv.c \
ietf/swima/ietf_swima_attr_sw_ev.c \
tcg/seg/tcg_seg_attr_seg_env.c \
imcv.c imcv_tests.h imcv_tests.c
+35 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2015 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -25,10 +25,14 @@
#include "ietf/ietf_attr_product_info.h"
#include "ietf/ietf_attr_remediation_instr.h"
#include "ietf/ietf_attr_string_version.h"
#include "ietf/swima/ietf_swima_attr_req.h"
#include "ietf/swima/ietf_swima_attr_sw_inv.h"
#include "ietf/swima/ietf_swima_attr_sw_ev.h"
#include "generic/generic_attr_bool.h"
ENUM(ietf_attr_names, IETF_ATTR_TESTING, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED,
ENUM_BEGIN(ietf_attr_names, IETF_ATTR_TESTING,
IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED,
"Testing",
"Attribute Request",
"Product Information",
@@ -43,6 +47,20 @@ ENUM(ietf_attr_names, IETF_ATTR_TESTING, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED,
"Forwarding Enabled",
"Factory Default Password Enabled",
);
ENUM_NEXT(ietf_attr_names, IETF_ATTR_SW_REQUEST,
IETF_ATTR_SRC_METADATA_RESP,
IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED,
"SW Request",
"SW Identifier Inventory",
"SW Identifier Events",
"SW Inventory",
"SW Events",
"SW Subscription Status Request",
"SW Subscription Status Response",
"SW Source Metadata Request",
"SW Source Metadata Response",
);
ENUM_END(ietf_attr_names, IETF_ATTR_SRC_METADATA_RESP);
/**
* See header
@@ -79,8 +97,23 @@ pa_tnc_attr_t* ietf_attr_create_from_data(uint32_t type, size_t length,
case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
return generic_attr_bool_create_from_data(length, value,
pen_type_create(PEN_IETF, type));
case IETF_ATTR_SW_REQUEST:
return ietf_swima_attr_req_create_from_data(length, value);
case IETF_ATTR_SW_ID_INVENTORY:
return ietf_swima_attr_sw_inv_create_from_data(length, value, TRUE);
case IETF_ATTR_SW_INVENTORY:
return ietf_swima_attr_sw_inv_create_from_data(length, value, FALSE);
case IETF_ATTR_SW_ID_EVENTS:
return ietf_swima_attr_sw_ev_create_from_data(length, value, TRUE);
case IETF_ATTR_SW_EVENTS:
return ietf_swima_attr_sw_ev_create_from_data(length, value, FALSE);
case IETF_ATTR_TESTING:
case IETF_ATTR_RESERVED:
/* unsupported IETF/SWIMA attributes */
case IETF_ATTR_SUBSCRIPTION_STATUS_REQ:
case IETF_ATTR_SUBSCRIPTION_STATUS_RESP:
case IETF_ATTR_SRC_METADATA_REQ:
case IETF_ATTR_SRC_METADATA_RESP:
default:
return NULL;
}
+16 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,9 +28,11 @@
typedef enum ietf_attr_t ietf_attr_t;
/**
* IETF standard PA-TNC attribute types defined by RFC 5792
* IETF standard PA-TNC attribute types
*/
enum ietf_attr_t {
/* RFC 5792 */
IETF_ATTR_TESTING = 0,
IETF_ATTR_ATTRIBUTE_REQUEST = 1,
IETF_ATTR_PRODUCT_INFORMATION = 2,
@@ -44,6 +46,18 @@ enum ietf_attr_t {
IETF_ATTR_REMEDIATION_INSTRUCTIONS = 10,
IETF_ATTR_FORWARDING_ENABLED = 11,
IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED = 12,
/* draft-ietf-sacm-nea-swid-patnc */
IETF_ATTR_SW_REQUEST = 17,
IETF_ATTR_SW_ID_INVENTORY = 18,
IETF_ATTR_SW_ID_EVENTS = 19,
IETF_ATTR_SW_INVENTORY = 20,
IETF_ATTR_SW_EVENTS = 21,
IETF_ATTR_SUBSCRIPTION_STATUS_REQ = 22,
IETF_ATTR_SUBSCRIPTION_STATUS_RESP = 23,
IETF_ATTR_SRC_METADATA_REQ = 24,
IETF_ATTR_SRC_METADATA_RESP = 25,
IETF_ATTR_RESERVED = 0xffffffff,
};
+17 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,13 +20,23 @@
#include <bio/bio_reader.h>
#include <utils/debug.h>
ENUM(pa_tnc_error_code_names, PA_ERROR_RESERVED,
PA_ERROR_ATTR_TYPE_NOT_SUPPORTED,
ENUM_BEGIN(pa_tnc_error_code_names, PA_ERROR_RESERVED,
PA_ERROR_ATTR_TYPE_NOT_SUPPORTED,
"Reserved",
"Invalid Parameter",
"Version Not Supported",
"Attribute Type Not Supported"
);
ENUM_NEXT(pa_tnc_error_code_names, PA_ERROR_SW,
PA_ERROR_SW_SUBSCRIPTION_ID_REUSE,
PA_ERROR_ATTR_TYPE_NOT_SUPPORTED,
"SW Error",
"SW Subscription Denied",
"SW Response Too Large",
"SW Subscription Fulfillment Error",
"SW Subscription ID Reuse"
);
ENUM_END(pa_tnc_error_code_names, PA_ERROR_SW_SUBSCRIPTION_ID_REUSE);
typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t;
@@ -246,7 +256,8 @@ METHOD(pa_tnc_attr_t, process, status_t,
reader->read_uint24(reader, &this->error_code.vendor_id);
reader->read_uint32(reader, &this->error_code.type);
if (this->error_code.vendor_id == PEN_IETF)
if (this->error_code.vendor_id == PEN_IETF &&
this->error_code.type <= PA_ERROR_PA_TNC_MSG_ROOF)
{
if (!reader->read_data(reader, PA_ERROR_MSG_INFO_SIZE, &this->msg_info))
{
@@ -396,7 +407,8 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_type_t error_code,
{
private_ietf_attr_pa_tnc_error_t *this;
if (error_code.vendor_id == PEN_IETF)
if (error_code.vendor_id == PEN_IETF &&
error_code.type <= PA_ERROR_PA_TNC_MSG_ROOF)
{
msg_info.len = PA_ERROR_MSG_INFO_SIZE;
}
+15 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -27,15 +27,24 @@ typedef enum pa_tnc_error_code_t pa_tnc_error_code_t;
#include "ietf_attr.h"
#include "pa_tnc/pa_tnc_attr.h"
/**
* IETF Standard PA-TNC Error Codes as defined in section 4.2.8 of RFC 5792
*/
enum pa_tnc_error_code_t {
PA_ERROR_RESERVED = 0,
PA_ERROR_INVALID_PARAMETER = 1,
PA_ERROR_VERSION_NOT_SUPPORTED = 2,
PA_ERROR_ATTR_TYPE_NOT_SUPPORTED = 3,
/* RFC 5792 PA-TNC */
PA_ERROR_RESERVED = 0,
PA_ERROR_INVALID_PARAMETER = 1,
PA_ERROR_VERSION_NOT_SUPPORTED = 2,
PA_ERROR_ATTR_TYPE_NOT_SUPPORTED = 3,
PA_ERROR_PA_TNC_MSG_ROOF = 3,
/* draft-ietf-sacm-nea-swid-patnc (SWIMA) */
PA_ERROR_SW = 32,
PA_ERROR_SW_SUBSCRIPTION_DENIED = 33,
PA_ERROR_SW_RESPONSE_TOO_LARGE = 34,
PA_ERROR_SW_SUBSCRIPTION_FULFILLMENT = 35,
PA_ERROR_SW_SUBSCRIPTION_ID_REUSE = 36
};
/**
@@ -0,0 +1,320 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ietf_swima_attr_req.h"
#include "swima/swima_record.h"
#include <pa_tnc/pa_tnc_msg.h>
#include <bio/bio_writer.h>
#include <bio/bio_reader.h>
#include <utils/debug.h>
#include <collections/linked_list.h>
typedef struct private_ietf_swima_attr_req_t private_ietf_swima_attr_req_t;
/**
* SW Request
* see section 5.7 of IETF SW Inventory Message and Attributes for PA-TNC
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |C|S|R| Reserved| Software Identifier Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Request ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Earliest EID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Software Identifier Length | Software Identifier (Var Len) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#define SW_REQ_RESERVED_MASK 0xE0
/**
* Private data of an ietf_swima_attr_req_t object.
*/
struct private_ietf_swima_attr_req_t {
/**
* Public members of ietf_swima_attr_req_t
*/
ietf_swima_attr_req_t public;
/**
* Vendor-specific attribute type
*/
pen_type_t type;
/**
* Length of attribute value
*/
size_t length;
/**
* Attribute value or segment
*/
chunk_t value;
/**
* Noskip flag
*/
bool noskip_flag;
/**
* SWID request flags
*/
uint8_t flags;
/**
* Request ID
*/
uint32_t request_id;
/**
* Inventory of Target Software Identifiers
*/
swima_inventory_t *targets;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_type, pen_type_t,
private_ietf_swima_attr_req_t *this)
{
return this->type;
}
METHOD(pa_tnc_attr_t, get_value, chunk_t,
private_ietf_swima_attr_req_t *this)
{
return this->value;
}
METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
private_ietf_swima_attr_req_t *this)
{
return this->noskip_flag;
}
METHOD(pa_tnc_attr_t, set_noskip_flag,void,
private_ietf_swima_attr_req_t *this, bool noskip)
{
this->noskip_flag = noskip;
}
METHOD(pa_tnc_attr_t, build, void,
private_ietf_swima_attr_req_t *this)
{
bio_writer_t *writer;
swima_record_t *sw_record;
uint32_t earliest_eid;
chunk_t sw_id;
enumerator_t *enumerator;
if (this->value.ptr)
{
return;
}
earliest_eid = this->targets->get_eid(this->targets, NULL);
writer = bio_writer_create(IETF_SWIMA_REQ_MIN_SIZE);
writer->write_uint8 (writer, this->flags);
writer->write_uint24(writer, this->targets->get_count(this->targets));
writer->write_uint32(writer, this->request_id);
writer->write_uint32(writer, earliest_eid);
enumerator = this->targets->create_enumerator(this->targets);
while (enumerator->enumerate(enumerator, &sw_record))
{
sw_id = sw_record->get_sw_id(sw_record, NULL);
writer->write_data16(writer, sw_id);
}
enumerator->destroy(enumerator);
this->value = writer->extract_buf(writer);
this->length = this->value.len;
writer->destroy(writer);
}
METHOD(pa_tnc_attr_t, process, status_t,
private_ietf_swima_attr_req_t *this, uint32_t *offset)
{
bio_reader_t *reader;
swima_record_t *sw_record;
uint32_t sw_id_count, earliest_eid;
chunk_t sw_id;
*offset = 0;
if (this->value.len < this->length)
{
return NEED_MORE;
}
if (this->value.len < IETF_SWIMA_REQ_MIN_SIZE)
{
DBG1(DBG_TNC, "insufficient data for SW Request");
return FAILED;
}
reader = bio_reader_create(this->value);
reader->read_uint8 (reader, &this->flags);
reader->read_uint24(reader, &sw_id_count);
reader->read_uint32(reader, &this->request_id);
reader->read_uint32(reader, &earliest_eid);
*offset = IETF_SWIMA_REQ_MIN_SIZE;
this->flags &= SW_REQ_RESERVED_MASK;
this->targets->set_eid(this->targets, earliest_eid, 0);
while (sw_id_count--)
{
if (!reader->read_data16(reader, &sw_id))
{
DBG1(DBG_TNC, "insufficient data for Software ID");
reader->destroy(reader);
return FAILED;
}
*offset += 2 + sw_id.len;
sw_record = swima_record_create(0, sw_id, chunk_empty);
this->targets->add(this->targets, sw_record);
}
reader->destroy(reader);
return SUCCESS;
}
METHOD(pa_tnc_attr_t, add_segment, void,
private_ietf_swima_attr_req_t *this, chunk_t segment)
{
this->value = chunk_cat("mc", this->value, segment);
}
METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
private_ietf_swima_attr_req_t *this)
{
ref_get(&this->ref);
return &this->public.pa_tnc_attribute;
}
METHOD(pa_tnc_attr_t, destroy, void,
private_ietf_swima_attr_req_t *this)
{
if (ref_put(&this->ref))
{
this->targets->destroy(this->targets);
free(this->value.ptr);
free(this);
}
}
METHOD(ietf_swima_attr_req_t, get_flags, uint8_t,
private_ietf_swima_attr_req_t *this)
{
return this->flags;
}
METHOD(ietf_swima_attr_req_t, get_request_id, uint32_t,
private_ietf_swima_attr_req_t *this)
{
return this->request_id;
}
METHOD(ietf_swima_attr_req_t, set_targets, void,
private_ietf_swima_attr_req_t *this, swima_inventory_t *targets)
{
this->targets->destroy(this->targets);
this->targets = targets->get_ref(targets);
}
METHOD(ietf_swima_attr_req_t, get_targets, swima_inventory_t*,
private_ietf_swima_attr_req_t *this)
{
return this->targets;
}
/**
* Described in header.
*/
pa_tnc_attr_t *ietf_swima_attr_req_create(uint8_t flags, uint32_t request_id)
{
private_ietf_swima_attr_req_t *this;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
.get_request_id = _get_request_id,
.set_targets = _set_targets,
.get_targets = _get_targets,
},
.type = { PEN_IETF, IETF_ATTR_SW_REQUEST },
.flags = flags & SW_REQ_RESERVED_MASK,
.request_id = request_id,
.targets = swima_inventory_create(),
.ref = 1,
);
return &this->public.pa_tnc_attribute;
}
/**
* Described in header.
*/
pa_tnc_attr_t *ietf_swima_attr_req_create_from_data(size_t length, chunk_t data)
{
private_ietf_swima_attr_req_t *this;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
.get_request_id = _get_request_id,
.set_targets = _set_targets,
.get_targets = _get_targets,
},
.type = { PEN_IETF, IETF_ATTR_SW_REQUEST },
.length = length,
.value = chunk_clone(data),
.targets = swima_inventory_create(),
.ref = 1,
);
return &this->public.pa_tnc_attribute;
}
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 ietf_swima_attr_req ietf_swima_attr_req
* @{ @ingroup ietf_attr
*/
#ifndef IETF_SWIMA_ATTR_REQ_H_
#define IETF_SWIMA_ATTR_REQ_H_
#define IETF_SWIMA_REQ_MIN_SIZE 12
typedef struct ietf_swima_attr_req_t ietf_swima_attr_req_t;
typedef enum ietf_swima_attr_req_flag_t ietf_swima_attr_req_flag_t;
enum ietf_swima_attr_req_flag_t {
IETF_SWIMA_ATTR_REQ_FLAG_NONE = 0,
IETF_SWIMA_ATTR_REQ_FLAG_C = (1 << 7),
IETF_SWIMA_ATTR_REQ_FLAG_S = (1 << 6),
IETF_SWIMA_ATTR_REQ_FLAG_R = (1 << 5)
};
#include "swima/swima_inventory.h"
#include "ietf/ietf_attr.h"
#include "pa_tnc/pa_tnc_attr.h"
/**
* Class implementing the IETF SW Request attribute
*/
struct ietf_swima_attr_req_t {
/**
* Public PA-TNC attribute interface
*/
pa_tnc_attr_t pa_tnc_attribute;
/**
* Get SW request flags
*
* @return Flags
*/
uint8_t (*get_flags)(ietf_swima_attr_req_t *this);
/**
* Get Request ID
*
* @return Request ID
*/
uint32_t (*get_request_id)(ietf_swima_attr_req_t *this);
/**
* Set Software Identity targets
*
* @param targets SW ID inventory containing targets (not cloned)
*/
void (*set_targets)(ietf_swima_attr_req_t *this, swima_inventory_t *targets);
/**
* Get Software Identity targets
*
* @return SW ID inventory containing targets
*/
swima_inventory_t* (*get_targets)(ietf_swima_attr_req_t *this);
};
/**
* Creates an ietf_swima_attr_req_t object
*
* @param flags Sets the C|S|R flags
* @param request_id Request ID
*/
pa_tnc_attr_t* ietf_swima_attr_req_create(uint8_t flags, uint32_t request_id);
/**
* Creates an ietf_swima_attr_req_t object from received data
*
* @param length Total length of attribute value
* @param value Unparsed attribute value (might be a segment)
*/
pa_tnc_attr_t* ietf_swima_attr_req_create_from_data(size_t length, chunk_t value);
#endif /** IETF_SWIMA_ATTR_REQ_H_ @}*/
@@ -0,0 +1,482 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ietf_swima_attr_sw_ev.h"
#include "swima/swima_event.h"
#include <pa_tnc/pa_tnc_msg.h>
#include <bio/bio_writer.h>
#include <bio/bio_reader.h>
#include <utils/debug.h>
#define SW_EV_TIMESTAMP_SIZE 20
typedef struct private_ietf_swima_attr_sw_ev_t private_ietf_swima_attr_sw_ev_t;
/**
* Software [Identifier] Events
* see sections 5.9/5.11 of IETF SW Inventory Message and Attributes for PA-TNC
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Flags | Software Identifier Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Request ID Copy / Subscription ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | EID Epoch |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Last EID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Last Consulted EID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | EID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Record Identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Data Model Type PEN |Data Model Type|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source ID Num | Action | Software Identifier Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Software Identifier (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Software Locator Length | Software Locator (Var. Len) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Software Event only
* see section 5.11 of IETF SW Inventory Message and Attributes for PA-TNC
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Record Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Record (Variable length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Private data of an ietf_swima_attr_sw_ev_t object.
*/
struct private_ietf_swima_attr_sw_ev_t {
/**
* Public members of ietf_swima_attr_sw_ev_t
*/
ietf_swima_attr_sw_ev_t public;
/**
* Vendor-specific attribute type
*/
pen_type_t type;
/**
* Length of attribute value
*/
size_t length;
/**
* Offset up to which attribute value has been processed
*/
size_t offset;
/**
* Current position of attribute value pointer
*/
chunk_t value;
/**
* Contains complete attribute or current segment
*/
chunk_t segment;
/**
* Noskip flag
*/
bool noskip_flag;
/**
* Request ID
*/
uint32_t request_id;
/**
* Attribute flags
*/
uint8_t flags;
/**
* Number of unprocessed software events in attribute
*/
uint32_t event_count;
/**
* Event list
*/
swima_events_t *events;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_type, pen_type_t,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->type;
}
METHOD(pa_tnc_attr_t, get_value, chunk_t,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->value;
}
METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->noskip_flag;
}
METHOD(pa_tnc_attr_t, set_noskip_flag,void,
private_ietf_swima_attr_sw_ev_t *this, bool noskip)
{
this->noskip_flag = noskip;
}
METHOD(pa_tnc_attr_t, build, void,
private_ietf_swima_attr_sw_ev_t *this)
{
bio_writer_t *writer;
swima_event_t *sw_event;
swima_record_t *sw_record;
chunk_t timestamp, sw_id, sw_locator, record;
pen_type_t data_model;
uint32_t eid, record_id, last_eid, last_consulted_eid, eid_epoch;
uint8_t action, source_id;
enumerator_t *enumerator;
if (this->value.ptr)
{
return;
}
last_consulted_eid = this->events->get_eid(this->events, &eid_epoch,
&last_eid);
writer = bio_writer_create(IETF_SWIMA_SW_EV_MIN_SIZE);
writer->write_uint8 (writer, this->flags);
writer->write_uint24(writer, this->events->get_count(this->events));
writer->write_uint32(writer, this->request_id);
writer->write_uint32(writer, eid_epoch);
writer->write_uint32(writer, last_eid);
writer->write_uint32(writer, last_consulted_eid);
enumerator = this->events->create_enumerator(this->events);
while (enumerator->enumerate(enumerator, &sw_event))
{
eid = sw_event->get_eid(sw_event, &timestamp);
action = sw_event->get_action(sw_event);
sw_record = sw_event->get_sw_record(sw_event);
record_id = sw_record->get_record_id(sw_record);
data_model = sw_record->get_data_model(sw_record);
source_id = sw_record->get_source_id(sw_record);
sw_id = sw_record->get_sw_id(sw_record, &sw_locator);
writer->write_uint32(writer, eid);
writer->write_data (writer, timestamp);
writer->write_uint32(writer, record_id);
writer->write_uint24(writer, data_model.vendor_id);
writer->write_uint8 (writer, data_model.type);
writer->write_uint8 (writer, source_id);
writer->write_uint8 (writer, action);
writer->write_data16(writer, sw_id);
writer->write_data16(writer, sw_locator);
if (this->type.type == IETF_ATTR_SW_EVENTS)
{
record = sw_record->get_record(sw_record);
writer->write_data32(writer, record);
}
}
enumerator->destroy(enumerator);
this->value = writer->extract_buf(writer);
this->segment = this->value;
this->length = this->value.len;
writer->destroy(writer);
}
METHOD(pa_tnc_attr_t, process, status_t,
private_ietf_swima_attr_sw_ev_t *this, uint32_t *offset)
{
bio_reader_t *reader;
uint32_t data_model_pen, record_id;
uint32_t eid, eid_epoch, last_eid, last_consulted_eid;
uint8_t data_model_type, source_id, action;
pen_type_t data_model;
chunk_t sw_id, sw_locator, record, timestamp;
swima_event_t *sw_event;
swima_record_t *sw_record;
status_t status = NEED_MORE;
if (this->offset == 0)
{
if (this->length < IETF_SWIMA_SW_EV_MIN_SIZE)
{
DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_IETF,
ietf_attr_names, this->type.type);
*offset = this->offset;
return FAILED;
}
if (this->value.len < IETF_SWIMA_SW_EV_MIN_SIZE)
{
return NEED_MORE;
}
reader = bio_reader_create(this->value);
reader->read_uint8 (reader, &this->flags);
reader->read_uint24(reader, &this->event_count);
reader->read_uint32(reader, &this->request_id);
reader->read_uint32(reader, &eid_epoch);
reader->read_uint32(reader, &last_eid);
reader->read_uint32(reader, &last_consulted_eid);
this->offset = IETF_SWIMA_SW_EV_MIN_SIZE;
this->events->set_eid(this->events, last_consulted_eid, eid_epoch);
this->events->set_last_eid(this->events, last_eid);
this->value = reader->peek(reader);
reader->destroy(reader);
}
reader = bio_reader_create(this->value);
while (this->event_count)
{
if (!reader->read_uint32(reader, &eid) ||
!reader->read_data (reader, SW_EV_TIMESTAMP_SIZE, &timestamp) ||
!reader->read_uint32(reader, &record_id) ||
!reader->read_uint24(reader, &data_model_pen) ||
!reader->read_uint8 (reader, &data_model_type) ||
!reader->read_uint8 (reader, &source_id) ||
!reader->read_uint8 (reader, &action) ||
!reader->read_data16(reader, &sw_id) ||
!reader->read_data16(reader, &sw_locator))
{
goto end;
}
record = chunk_empty;
if (action == 0 || action > SWIMA_EVENT_ACTION_LAST)
{
DBG1(DBG_TNC, "invalid event action value for %N/%N", pen_names,
PEN_IETF, ietf_attr_names, this->type.type);
*offset = this->offset;
reader->destroy(reader);
return FAILED;
}
if (this->type.type == IETF_ATTR_SW_EVENTS &&
!reader->read_data32(reader, &record))
{
goto end;
}
data_model = pen_type_create(data_model_pen, data_model_type);
sw_record = swima_record_create(record_id, sw_id, sw_locator);
sw_record->set_data_model(sw_record, data_model);
sw_record->set_source_id(sw_record, source_id);
sw_record->set_record(sw_record, record);
sw_event = swima_event_create(eid, timestamp, action, sw_record);
this->events->add(this->events, sw_event);
this->offset += this->value.len - reader->remaining(reader);
this->value = reader->peek(reader);
/* at least one software event was processed */
status = SUCCESS;
this->event_count--;
}
if (this->length == this->offset)
{
status = SUCCESS;
}
else
{
DBG1(DBG_TNC, "inconsistent length for %N/%N", pen_names, PEN_IETF,
ietf_attr_names, this->type.type);
*offset = this->offset;
status = FAILED;
}
end:
reader->destroy(reader);
return status;
}
METHOD(pa_tnc_attr_t, add_segment, void,
private_ietf_swima_attr_sw_ev_t *this, chunk_t segment)
{
this->value = chunk_cat("cc", this->value, segment);
chunk_free(&this->segment);
this->segment = this->value;
}
METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
private_ietf_swima_attr_sw_ev_t *this)
{
ref_get(&this->ref);
return &this->public.pa_tnc_attribute;
}
METHOD(pa_tnc_attr_t, destroy, void,
private_ietf_swima_attr_sw_ev_t *this)
{
if (ref_put(&this->ref))
{
this->events->destroy(this->events);
free(this->segment.ptr);
free(this);
}
}
METHOD(ietf_swima_attr_sw_ev_t, get_flags, uint8_t,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->flags;
}
METHOD(ietf_swima_attr_sw_ev_t, get_request_id, uint32_t,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->request_id;
}
METHOD(ietf_swima_attr_sw_ev_t, get_event_count, uint32_t,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->event_count;
}
METHOD(ietf_swima_attr_sw_ev_t, set_events, void,
private_ietf_swima_attr_sw_ev_t *this, swima_events_t *events)
{
this->events->destroy(this->events);
this->events = events->get_ref(events);
}
METHOD(ietf_swima_attr_sw_ev_t, get_events, swima_events_t*,
private_ietf_swima_attr_sw_ev_t *this)
{
return this->events;
}
METHOD(ietf_swima_attr_sw_ev_t, clear_events, void,
private_ietf_swima_attr_sw_ev_t *this)
{
this->events->clear(this->events);
}
/**
* Described in header.
*/
pa_tnc_attr_t *ietf_swima_attr_sw_ev_create(uint8_t flags, uint32_t request_id,
bool sw_id_only)
{
private_ietf_swima_attr_sw_ev_t *this;
ietf_attr_t type;
type = sw_id_only ? IETF_ATTR_SW_ID_EVENTS : IETF_ATTR_SW_EVENTS;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
.get_request_id = _get_request_id,
.get_event_count = _get_event_count,
.set_events = _set_events,
.get_events = _get_events,
.clear_events = _clear_events,
},
.type = { PEN_IETF, type },
.flags = flags,
.request_id = request_id,
.events = swima_events_create(),
.ref = 1,
);
return &this->public.pa_tnc_attribute;
}
/**
* Described in header.
*/
pa_tnc_attr_t *ietf_swima_attr_sw_ev_create_from_data(size_t length,
chunk_t data, bool sw_id_only)
{
private_ietf_swima_attr_sw_ev_t *this;
ietf_attr_t type;
type = sw_id_only ? IETF_ATTR_SW_ID_EVENTS : IETF_ATTR_SW_EVENTS;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
.get_request_id = _get_request_id,
.get_event_count = _get_event_count,
.set_events = _set_events,
.get_events = _get_events,
.clear_events = _clear_events,
},
.type = { PEN_IETF, type },
.length = length,
.segment = chunk_clone(data),
.events = swima_events_create(),
.ref = 1,
);
/* received either complete attribute value or first segment */
this->value = this->segment;
return &this->public.pa_tnc_attribute;
}
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 ietf_swima_attr_sw_ev ietf_swima_attr_sw_ev
* @{ @ingroup ietf_attr
*/
#ifndef IETF_SWIMA_ATTR_SW_EV_H_
#define IETF_SWIMA_ATTR_SW_EV_H_
#define IETF_SWIMA_SW_EV_MIN_SIZE 20
typedef struct ietf_swima_attr_sw_ev_t ietf_swima_attr_sw_ev_t;
typedef enum ietf_swima_attr_sw_ev_flag_t ietf_swima_attr_sw_ev_flag_t;
enum ietf_swima_attr_sw_ev_flag_t {
IETF_SWIMA_ATTR_SW_EV_FLAG_NONE = 0,
IETF_SWIMA_ATTR_SW_EV_FLAG_S_F = (1 << 7)
};
#include "ietf/ietf_attr.h"
#include "swima/swima_events.h"
#include "pa_tnc/pa_tnc_attr.h"
/**
* Class implementing the IETF SW Identifier Inventory attribute
*
*/
struct ietf_swima_attr_sw_ev_t {
/**
* Public PA-TNC attribute interface
*/
pa_tnc_attr_t pa_tnc_attribute;
/**
* Get Software Inventory flags
*
* @return Flags
*/
uint8_t (*get_flags)(ietf_swima_attr_sw_ev_t *this);
/**
* Get Request ID
*
* @return Request ID
*/
uint32_t (*get_request_id)(ietf_swima_attr_sw_ev_t *this);
/**
* Get number of Software [Identifier] Events
*
* @return Software [Identifier] event count
*/
uint32_t (*get_event_count)(ietf_swima_attr_sw_ev_t *this);
/**
* Add Software [Identifier] Events
*
* @param sw_events List of Software [Identifier] events to be added
*/
void (*set_events)(ietf_swima_attr_sw_ev_t *this,
swima_events_t *sw_events);
/**
* Get Software [Identifier] Events
*
* @result Software [Identifier] events
*/
swima_events_t* (*get_events)(ietf_swima_attr_sw_ev_t *this);
/**
* Remove all Software [Identifier] events
*/
void (*clear_events)(ietf_swima_attr_sw_ev_t *this);
};
/**
* Creates an ietf_swima_attr_sw_ev_t object
*
* @param flags Sets the flags
* @param request_id Copy of the Request ID
* @param sw_id_only TRUE if the Software ID, only is transmitted
*/
pa_tnc_attr_t* ietf_swima_attr_sw_ev_create(uint8_t flags, uint32_t request_id,
bool sw_id_only);
/**
* Creates an ietf_swima_attr_sw_ev_t object from received data
*
* @param length Total length of attribute value
* @param value Unparsed attribute value (might be a segment)
* @param sw_id_only TRUE if the Software ID, only is transmitted
*/
pa_tnc_attr_t* ietf_swima_attr_sw_ev_create_from_data(size_t length,
chunk_t value, bool sw_id_only);
#endif /** IETF_SWIMA_ATTR_SW_EV_H_ @}*/
@@ -0,0 +1,438 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "ietf_swima_attr_sw_inv.h"
#include "swima/swima_record.h"
#include <pa_tnc/pa_tnc_msg.h>
#include <bio/bio_writer.h>
#include <bio/bio_reader.h>
#include <utils/debug.h>
typedef struct private_ietf_swima_attr_sw_inv_t private_ietf_swima_attr_sw_inv_t;
/**
* Software [Identifier] Inventory
* see sections 5.8/5.10 of IETF SW Inventory Message and Attributes for PA-TNC
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Flags | Software Identifier Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Request ID Copy / Subscription ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | EID Epoch |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Last EID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Record Identifier |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Data Model Type PEN |Data Model Type|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source ID Num | Software Identifier Length |Software Id (v)|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Software Locator Length | Software Locator (Var. Len) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Software Inventory only
* see section 5.10 of IETF SW Inventory Message and Attributes for PA-TNC
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Record Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Record (Variable length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Private data of an ietf_swima_attr_sw_inv_t object.
*/
struct private_ietf_swima_attr_sw_inv_t {
/**
* Public members of ietf_swima_attr_sw_inv_t
*/
ietf_swima_attr_sw_inv_t public;
/**
* Vendor-specific attribute type
*/
pen_type_t type;
/**
* Length of attribute value
*/
size_t length;
/**
* Offset up to which attribute value has been processed
*/
size_t offset;
/**
* Current position of attribute value pointer
*/
chunk_t value;
/**
* Contains complete attribute or current segment
*/
chunk_t segment;
/**
* Noskip flag
*/
bool noskip_flag;
/**
* Request ID
*/
uint32_t request_id;
/**
* Attribute flags
*/
uint8_t flags;
/**
* Number of unprocessed software inventory evidence records in attribute
*/
uint32_t record_count;
/**
* SWID Tag ID Inventory
*/
swima_inventory_t *inventory;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_type, pen_type_t,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->type;
}
METHOD(pa_tnc_attr_t, get_value, chunk_t,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->value;
}
METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->noskip_flag;
}
METHOD(pa_tnc_attr_t, set_noskip_flag,void,
private_ietf_swima_attr_sw_inv_t *this, bool noskip)
{
this->noskip_flag = noskip;
}
METHOD(pa_tnc_attr_t, build, void,
private_ietf_swima_attr_sw_inv_t *this)
{
bio_writer_t *writer;
swima_record_t *sw_record;
chunk_t sw_id, sw_locator, record;
pen_type_t data_model;
uint32_t record_id, last_eid, eid_epoch;
uint8_t source_id;
enumerator_t *enumerator;
if (this->value.ptr)
{
return;
}
last_eid = this->inventory->get_eid(this->inventory, &eid_epoch);
writer = bio_writer_create(IETF_SWIMA_SW_INV_MIN_SIZE);
writer->write_uint8 (writer, this->flags);
writer->write_uint24(writer, this->inventory->get_count(this->inventory));
writer->write_uint32(writer, this->request_id);
writer->write_uint32(writer, eid_epoch);
writer->write_uint32(writer, last_eid);
enumerator = this->inventory->create_enumerator(this->inventory);
while (enumerator->enumerate(enumerator, &sw_record))
{
record_id = sw_record->get_record_id(sw_record);
data_model = sw_record->get_data_model(sw_record);
source_id = sw_record->get_source_id(sw_record);
sw_id = sw_record->get_sw_id(sw_record, &sw_locator);
writer->write_uint32(writer, record_id);
writer->write_uint24(writer, data_model.vendor_id);
writer->write_uint8 (writer, data_model.type);
writer->write_uint8 (writer, source_id);
writer->write_data16(writer, sw_id);
writer->write_data16(writer, sw_locator);
if (this->type.type == IETF_ATTR_SW_INVENTORY)
{
record = sw_record->get_record(sw_record);
writer->write_data32(writer, record);
}
}
enumerator->destroy(enumerator);
this->value = writer->extract_buf(writer);
this->segment = this->value;
this->length = this->value.len;
writer->destroy(writer);
}
METHOD(pa_tnc_attr_t, process, status_t,
private_ietf_swima_attr_sw_inv_t *this, uint32_t *offset)
{
bio_reader_t *reader;
uint32_t data_model_pen, record_id, last_eid, eid_epoch;
uint8_t data_model_type, source_id;
pen_type_t data_model;
chunk_t sw_id, sw_locator, record;
swima_record_t *sw_record;
status_t status = NEED_MORE;
if (this->offset == 0)
{
if (this->length < IETF_SWIMA_SW_INV_MIN_SIZE)
{
DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_IETF,
ietf_attr_names, this->type.type);
*offset = this->offset;
return FAILED;
}
if (this->value.len < IETF_SWIMA_SW_INV_MIN_SIZE)
{
return NEED_MORE;
}
reader = bio_reader_create(this->value);
reader->read_uint8 (reader, &this->flags);
reader->read_uint24(reader, &this->record_count);
reader->read_uint32(reader, &this->request_id);
reader->read_uint32(reader, &eid_epoch);
reader->read_uint32(reader, &last_eid);
this->offset = IETF_SWIMA_SW_INV_MIN_SIZE;
this->value = reader->peek(reader);
this->inventory->set_eid(this->inventory, last_eid, eid_epoch);
reader->destroy(reader);
}
reader = bio_reader_create(this->value);
while (this->record_count)
{
if (!reader->read_uint32(reader, &record_id) ||
!reader->read_uint24(reader, &data_model_pen) ||
!reader->read_uint8 (reader, &data_model_type) ||
!reader->read_uint8 (reader, &source_id) ||
!reader->read_data16(reader, &sw_id) ||
!reader->read_data16(reader, &sw_locator))
{
goto end;
}
record = chunk_empty;
if (this->type.type == IETF_ATTR_SW_INVENTORY &&
!reader->read_data32(reader, &record))
{
goto end;
}
data_model = pen_type_create(data_model_pen, data_model_type);
sw_record = swima_record_create(record_id, sw_id, sw_locator);
sw_record->set_data_model(sw_record, data_model);
sw_record->set_source_id(sw_record, source_id);
sw_record->set_record(sw_record, record);
this->inventory->add(this->inventory, sw_record);
this->offset += this->value.len - reader->remaining(reader);
this->value = reader->peek(reader);
/* at least one software inventory evidence record was processed */
status = SUCCESS;
this->record_count--;
}
if (this->length == this->offset)
{
status = SUCCESS;
}
else
{
DBG1(DBG_TNC, "inconsistent length for %N/%N", pen_names, PEN_IETF,
ietf_attr_names, this->type.type);
*offset = this->offset;
status = FAILED;
}
end:
reader->destroy(reader);
return status;
}
METHOD(pa_tnc_attr_t, add_segment, void,
private_ietf_swima_attr_sw_inv_t *this, chunk_t segment)
{
this->value = chunk_cat("cc", this->value, segment);
chunk_free(&this->segment);
this->segment = this->value;
}
METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
private_ietf_swima_attr_sw_inv_t *this)
{
ref_get(&this->ref);
return &this->public.pa_tnc_attribute;
}
METHOD(pa_tnc_attr_t, destroy, void,
private_ietf_swima_attr_sw_inv_t *this)
{
if (ref_put(&this->ref))
{
this->inventory->destroy(this->inventory);
free(this->segment.ptr);
free(this);
}
}
METHOD(ietf_swima_attr_sw_inv_t, get_flags, uint8_t,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->flags;
}
METHOD(ietf_swima_attr_sw_inv_t, get_request_id, uint32_t,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->request_id;
}
METHOD(ietf_swima_attr_sw_inv_t, get_record_count, uint32_t,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->record_count;
}
METHOD(ietf_swima_attr_sw_inv_t, set_inventory, void,
private_ietf_swima_attr_sw_inv_t *this, swima_inventory_t *inventory)
{
this->inventory->destroy(this->inventory);
this->inventory = inventory->get_ref(inventory);
}
METHOD(ietf_swima_attr_sw_inv_t, get_inventory, swima_inventory_t*,
private_ietf_swima_attr_sw_inv_t *this)
{
return this->inventory;
}
METHOD(ietf_swima_attr_sw_inv_t, clear_inventory, void,
private_ietf_swima_attr_sw_inv_t *this)
{
this->inventory->clear(this->inventory);
}
/**
* Described in header.
*/
pa_tnc_attr_t *ietf_swima_attr_sw_inv_create(uint8_t flags, uint32_t request_id,
bool sw_id_only)
{
private_ietf_swima_attr_sw_inv_t *this;
ietf_attr_t type;
type = sw_id_only ? IETF_ATTR_SW_ID_INVENTORY : IETF_ATTR_SW_INVENTORY;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
.get_request_id = _get_request_id,
.get_record_count = _get_record_count,
.set_inventory = _set_inventory,
.get_inventory = _get_inventory,
.clear_inventory = _clear_inventory,
},
.type = { PEN_IETF, type },
.flags = flags,
.request_id = request_id,
.inventory = swima_inventory_create(),
.ref = 1,
);
return &this->public.pa_tnc_attribute;
}
/**
* Described in header.
*/
pa_tnc_attr_t *ietf_swima_attr_sw_inv_create_from_data(size_t length,
chunk_t data, bool sw_id_only)
{
private_ietf_swima_attr_sw_inv_t *this;
ietf_attr_t type;
type = sw_id_only ? IETF_ATTR_SW_ID_INVENTORY : IETF_ATTR_SW_INVENTORY;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_flags = _get_flags,
.get_request_id = _get_request_id,
.get_record_count = _get_record_count,
.set_inventory = _set_inventory,
.get_inventory = _get_inventory,
.clear_inventory = _clear_inventory,
},
.type = { PEN_IETF, type },
.length = length,
.segment = chunk_clone(data),
.inventory = swima_inventory_create(),
.ref = 1,
);
/* received either complete attribute value or first segment */
this->value = this->segment;
return &this->public.pa_tnc_attribute;
}
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 ietf_swima_attr_sw_inv ietf_swima_attr_sw_inv
* @{ @ingroup ietf_attr
*/
#ifndef IETF_SWIMA_ATTR_SW_INV_H_
#define IETF_SWIMA_ATTR_SW_INV_H_
#define IETF_SWIMA_SW_INV_MIN_SIZE 16
typedef struct ietf_swima_attr_sw_inv_t ietf_swima_attr_sw_inv_t;
typedef enum ietf_swima_attr_sw_inv_flag_t ietf_swima_attr_sw_inv_flag_t;
enum ietf_swima_attr_sw_inv_flag_t {
IETF_SWIMA_ATTR_SW_INV_FLAG_NONE = 0,
IETF_SWIMA_ATTR_SW_INV_FLAG_S_F = (1 << 7)
};
#include "ietf/ietf_attr.h"
#include "swima/swima_inventory.h"
#include "pa_tnc/pa_tnc_attr.h"
/**
* Class implementing the IETF SW Identifier Inventory attribute
*
*/
struct ietf_swima_attr_sw_inv_t {
/**
* Public PA-TNC attribute interface
*/
pa_tnc_attr_t pa_tnc_attribute;
/**
* Get Software Inventory flags
*
* @return Flags
*/
uint8_t (*get_flags)(ietf_swima_attr_sw_inv_t *this);
/**
* Get Request ID
*
* @return Request ID
*/
uint32_t (*get_request_id)(ietf_swima_attr_sw_inv_t *this);
/**
* Get number of Software [Identifier] Inventory records
*
* @return Software ID count
*/
uint32_t (*get_record_count)(ietf_swima_attr_sw_inv_t *this);
/**
* Add a Software [Identifier] Inventory
*
* @param sw_inventory Software [Identifier] record to be added
*/
void (*set_inventory)(ietf_swima_attr_sw_inv_t *this,
swima_inventory_t *sw_inventory);
/**
* Get Software [Identifier] Inventory
*
* @result Software [Identifier] Inventory
*/
swima_inventory_t* (*get_inventory)(ietf_swima_attr_sw_inv_t *this);
/**
* Remove all Software [Identifier] records from the inventory
*/
void (*clear_inventory)(ietf_swima_attr_sw_inv_t *this);
};
/**
* Creates an ietf_swima_attr_sw_inv_t object
*
* @param flags Sets the flags
* @param request_id Copy of the Request ID
* @param sw_id_only TRUE if the Software ID, only is transmitted
*/
pa_tnc_attr_t* ietf_swima_attr_sw_inv_create(uint8_t flags, uint32_t request_id,
bool sw_id_only);
/**
* Creates an ietf_swima_attr_sw_inv_t object from received data
*
* @param length Total length of attribute value
* @param value Unparsed attribute value (might be a segment)
* @param sw_id_only TRUE if the Software ID, only is transmitted
*/
pa_tnc_attr_t* ietf_swima_attr_sw_inv_create_from_data(size_t length,
chunk_t value, bool sw_id_only);
#endif /** IETF_SWIMA_ATTR_SW_INV_H_ @}*/
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 Andreas Steffen
* Copyright (C) 2014-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,4 +14,4 @@
*/
TEST_SUITE(imcv_seg_suite_create)
TEST_SUITE(imcv_swima_suite_create)
+68 -50
View File
@@ -652,114 +652,120 @@ INSERT INTO algorithms (
8192, 'SHA384'
);
INSERT INTO algorithms (
id, name
) VALUES (
4096, 'SHA512'
);
/* File Hashes */
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 2, 32768, X'6c6f8e12f6cbfba612e780374c4cdcd40f20968a'
2, 2, 32768, '6c6f8e12f6cbfba612e780374c4cdcd40f20968a'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 2, 16384, X'dbcecd19d59310183cf5c31ddee29e8d7bec64d3f9583aad074330a1b3024b07'
2, 2, 16384, 'dbcecd19d59310183cf5c31ddee29e8d7bec64d3f9583aad074330a1b3024b07'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 2, 8192, X'197c5385e5853003188833d4f991136c1b0875fa416a60b1159f64e57e457b3184762c884a802a2bda194c058e3bd953'
2, 2, 8192, '197c5385e5853003188833d4f991136c1b0875fa416a60b1159f64e57e457b3184762c884a802a2bda194c058e3bd953'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 4, 32768, X'3ad204f99eb7262efab79cfca02628870ea76361'
2, 4, 32768, '3ad204f99eb7262efab79cfca02628870ea76361'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 4, 16384, X'3a2170aad92fdd58b55e0e199822bc873cf587b2d1eb1ed7ed8dcea97ae86376'
2, 4, 16384, '3a2170aad92fdd58b55e0e199822bc873cf587b2d1eb1ed7ed8dcea97ae86376'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 4, 8192, X'f778076baa876b5e4b502494a3db081fb09dd870dee6991d54104a74b7e009c58fe261db5ffd13c11e08ef0cefcfa59f'
2, 4, 8192, 'f778076baa876b5e4b502494a3db081fb09dd870dee6991d54104a74b7e009c58fe261db5ffd13c11e08ef0cefcfa59f'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 5, 32768, X'ecd9c7076cc0572724c7a67db7f19c2831e0445f'
4, 5, 32768, 'ecd9c7076cc0572724c7a67db7f19c2831e0445f'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 5, 16384, X'28f3ea5afd34444c8232ea75003131e294a0c9b847de300e4b205d38c1a41305'
4, 5, 16384, '28f3ea5afd34444c8232ea75003131e294a0c9b847de300e4b205d38c1a41305'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
28, 5, 8192, X'51921a8b9322f2d3f06d55002ff40a79da67e70cb563b2a50977642d603dfac2ccbb68b3d32a8bb350769b75d6254208'
4, 5, 8192, '51921a8b9322f2d3f06d55002ff40a79da67e70cb563b2a50977642d603dfac2ccbb68b3d32a8bb350769b75d6254208'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 1, 32768, X'd9309b9e45928239d7a7b18711e690792632cce4'
5, 1, 32768, 'd9309b9e45928239d7a7b18711e690792632cce4'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 1, 16384, X'dbfa1856d278d8707c4989b30dd065b4bcd309908f0f2e6e66ff2aa83ff93f59'
5, 1, 16384, 'dbfa1856d278d8707c4989b30dd065b4bcd309908f0f2e6e66ff2aa83ff93f59'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 1, 8192, X'fb8d027f03bb5ebb47741ed247eb9e174127b714d20229885feb37e0979aeb14a1b74020cded891d680441093625729c'
5, 1, 8192, 'fb8d027f03bb5ebb47741ed247eb9e174127b714d20229885feb37e0979aeb14a1b74020cded891d680441093625729c'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 3, 32768, X'3715f2f94016a91fab5bbc503f0f1d43c5a9fc2b'
5, 3, 32768, '3715f2f94016a91fab5bbc503f0f1d43c5a9fc2b'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 3, 16384, X'c03a5296b5decb87b01517f9927a8b2349dfb29ff9f5ba084f994c155ca5d4be'
5, 3, 16384, 'c03a5296b5decb87b01517f9927a8b2349dfb29ff9f5ba084f994c155ca5d4be'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 3, 8192, X'b8bc345f56115235cc6091f61e312ce43ea54a5b99e7295002ae7b415fd35e06ec4c731ab70ad00d784bb53a318a2fa0'
5, 3, 8192, 'b8bc345f56115235cc6091f61e312ce43ea54a5b99e7295002ae7b415fd35e06ec4c731ab70ad00d784bb53a318a2fa0'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 5, 32768, X'e59602f4edf24c1b36199588886d06665d4adcd7'
6, 5, 32768, 'e59602f4edf24c1b36199588886d06665d4adcd7'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 5, 16384, X'090e1b77bda7fe665e498c6b5e09dbb7ddc5cfe57f213de48f4fb6736484f500'
6, 5, 16384, '090e1b77bda7fe665e498c6b5e09dbb7ddc5cfe57f213de48f4fb6736484f500'
);
INSERT INTO file_hashes (
product, file, algo, hash
version, file, algo, hash
) VALUES (
18, 5, 8192, X'7cbdb4612a13443dba910ecdef5161f2213e52c9b4a2eef14bcee5d287e9df931cd022e9e9715518ad9c9b6e3384a668'
6, 5, 8192, '7cbdb4612a13443dba910ecdef5161f2213e52c9b4a2eef14bcee5d287e9df931cd022e9e9715518ad9c9b6e3384a668'
);
/* Packages */
@@ -790,30 +796,42 @@ INSERT INTO packages ( /* 4 */
/* Versions */
INSERT INTO versions (
INSERT INTO versions ( /* 1 */
package, product, release, time
) VALUES (
1, 28, '1.0.1e-2', 1366531494
);
INSERT INTO versions (
INSERT INTO versions ( /* 2 */
package, product, release, time
) VALUES (
2, 28, '1.0.1e-2', 1366531494
);
INSERT INTO versions (
INSERT INTO versions ( /* 3 */
package, product, release, time
) VALUES (
3, 28, '1.0.1e-2', 1366531494
);
INSERT INTO versions (
INSERT INTO versions ( /* 4 */
package, product, release, time
) VALUES (
4, 28, '1.0.1e-2', 1366531494
);
INSERT INTO versions ( /* 5 */
package, product, time
) VALUES (
2, 18, 1350544774
);
INSERT INTO versions ( /* 6 */
package, product, time
) VALUES (
4, 18, 1350544774
);
/* Components */
INSERT INTO components (
@@ -1681,59 +1699,59 @@ INSERT INTO enforcements ( /* 18 */
INSERT INTO "swid_entities" ( /* 1 */
"name", "regid"
) VALUES (
'strongSwan Project', 'regid.2004-03.org.strongswan'
'strongSwan Project', 'strongswan.org'
);
INSERT INTO swid_entities ( /* 2 */
"name", "regid"
) VALUES (
'Adobe Systems Inc.', 'regid.1986-12.com.adobe'
'Adobe Systems Inc.', 'adobe.com'
);
INSERT INTO swid_entities ( /* 3 */
"name", "regid"
) VALUES (
'Microsoft Corporation', 'regid.1991-06.com.microsoft'
'Microsoft Corporation', 'microsoft.com'
);
INSERT INTO swid_entities ( /* 4 */
"name", "regid"
) VALUES (
'Ubuntu Project', 'regid.2004-05.com.ubuntu'
'Ubuntu Project', 'ubuntu.com'
);
INSERT INTO swid_entities ( /* 5 */
"name", "regid"
) VALUES (
'Apache Software Foundation', 'regid.1995-04.org.apache'
'Apache Software Foundation', 'apache.org'
);
INSERT INTO swid_entities ( /* 6 */
"name", "regid"
) VALUES (
'Debian Project', 'regid.1999-03.org.debian'
'Debian Project', 'debian.org'
);
INSERT INTO swid_entities ( /* 7 */
"name", "regid"
) VALUES (
'Internet Systems Consortium', 'regid.1994-04.org.isc'
'Internet Systems Consortium', 'isc.org'
);
INSERT INTO swid_entities ( /* 8 */
"name", "regid"
) VALUES (
'OpenSSL Project', 'regid.1998-12.org.openssl'
'OpenSSL Project', 'openssl.org'
);
INSERT INTO swid_entities ( /* 9 */
"name", "regid"
) VALUES (
'Samba Project', 'regid.1998-01.org.samba'
'Samba Project', 'samba.org'
);
INSERT INTO swid_entities ( /* 10 */
"name", "regid"
) VALUES (
'SQLite Project', 'regid.2002-08.org.sqlite'
'SQLite Project', 'sqlite.org'
);
+25
View File
@@ -130,6 +130,31 @@ static bool iterate_enforcements(database_t *db, int device_id, int session_id,
case IMV_WORKITEM_DIR_META:
arg_int = dir;
break;
case IMV_WORKITEM_SWID_TAGS:
/* software [identifier] inventory by default */
arg_int = 0;
/* software identifiers only? */
if (device_id && strchr(argument, 'R'))
{
/* get last EID in order to set earliest EID */
e2 = db->query(db,
"SELECT eid FROM swid_events where device == ? "
"ORDER BY eid DESC", DB_UINT, device_id, DB_INT);
if (e2)
{
if (e2->enumerate(e2, &arg_int))
{
arg_int++;
}
else
{
arg_int = 1;
}
e2->destroy(e2);
}
}
break;
default:
arg_int = 0;
}
+45 -10
View File
@@ -41,10 +41,12 @@ DROP TABLE IF EXISTS file_hashes;
CREATE TABLE file_hashes (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
file INTEGER NOT NULL REFERENCES files(id),
product INTEGER NOT NULL REFERENCES products(id),
device INTEGER DEFAULT 0 REFERENCES devices(id),
version INTEGER REFERENCES versions(id),
device INTEGER REFERENCES devices(id),
size INTEGER,
algo INTEGER NOT NULL REFERENCES algorithms(id),
hash BLOB NOT NULL
hash VARCHAR(64) NOT NULL,
mutable INTEGER DEFAULT 0
);
DROP TABLE IF EXISTS groups;
@@ -177,9 +179,9 @@ CREATE INDEX packages_name ON packages (
DROP TABLE IF EXISTS versions;
CREATE TABLE versions (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
package INTEGER NOT NULL REFERENCES packages(id),
product INTEGER NOT NULL REFERENCES products(id),
release TEXT NOT NULL,
package INTEGER NOT NULL REFERENCES packages(id),
release TEXT,
security INTEGER DEFAULT 0,
blacklist INTEGER DEFAULT 0,
time INTEGER DEFAULT 0
@@ -302,14 +304,47 @@ CREATE INDEX "swid_tags_sessions_session_id" ON "swid_tags_sessions" (
DROP TABLE IF EXISTS "swid_tagstats";
CREATE TABLE "swid_tagstats" (
"id" integer NOT NULL PRIMARY KEY,
"tag_id" integer NOT NULL REFERENCES "swid_tags" ("id"),
"device_id" integer NOT NULL REFERENCES "devices" ("id"),
"first_seen_id" integer NOT NULL REFERENCES "sessions" ("id"),
"last_seen_id" integer NOT NULL REFERENCES "sessions" ("id"),
"id" INTEGER NOT NULL PRIMARY KEY,
"tag_id" INTEGER NOT NULL REFERENCES "swid_tags" ("id"),
"device_id" INTEGER NOT NULL REFERENCES "devices" ("id"),
"first_seen_id" INTEGER NOT NULL REFERENCES "sessions" ("id"),
"last_seen_id" INTEGER NOT NULL REFERENCES "sessions" ("id"),
"first_installed_id" INTEGER REFERENCES "swid_events" ("id"),
"last_deleted_id" INTEGER REFERENCES "swid_events" ("id"),
UNIQUE ("tag_id", "device_id")
);
CREATE INDEX "swid_tagstats_tag_id" ON "swid_tagstats" ("tag_id");
CREATE INDEX "swid_tagstats_device_id" ON "swid_tagstats" ("device_id");
CREATE INDEX "swid_tagstats_first_seen_id" ON "swid_tagstats" ("first_seen_id");
CREATE INDEX "swid_tagstats_last_seen_id" ON "swid_tagstats" ("last_seen_id");
DROP TABLE IF EXISTS "swid_events";
CREATE TABLE "swid_events" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"device" INTEGER REFERENCES "devices" ("id"),
"epoch" INTEGER NOT NULL,
"eid" INTEGER NOT NULL,
"timestamp" CHAR(20) NOT NULL
);
DROP INDEX IF EXISTS "swid_events_device";
CREATE INDEX "swid_events_device" ON "swid_events" (
"device"
);
DROP TABLE IF EXISTS "swid_tags_events";
CREATE TABLE "swid_tags_events" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"tag_id" INTEGER NOT NULL REFERENCES "swid_tags" ("id"),
"event_id" INTEGER NOT NULL REFERENCES "swid_events" ("id"),
"action" INTEGER NOT NULL,
"record_id" INTEGER DEFAULT 0,
"source_id" INTEGER DEFAULT 0
);
DROP INDEX IF EXISTS "swid_tags_events_event_id";
DROP INDEX IF EXISTS "swid_tags_events_tag_id";
CREATE INDEX "swid_tags_events_event_id" ON "swid_tags_events" (
"event_id"
);
CREATE INDEX "swid_tags_events_tag_id" ON "swid_tags_events" (
"tag_id"
);
+3 -2
View File
@@ -299,8 +299,9 @@ METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool,
error_code = error_attr->get_error_code(error_attr);
msg_info = error_attr->get_msg_info(error_attr);
/* skip errors from non-IETF namespaces */
if (error_code.vendor_id != PEN_IETF)
/* skip errors from non-IETF namespaces and non PA-TNC msg errors */
if (error_code.vendor_id != PEN_IETF ||
error_code.type > PA_ERROR_PA_TNC_MSG_ROOF)
{
continue;
}
+1 -1
View File
@@ -1 +1 @@
regid.2004-03.org.strongswan*.swidtag
strongswan.org_*.swidtag
+8 -9
View File
@@ -1,21 +1,20 @@
regid = regid.2004-03.org.strongswan
regid = strongswan.org
unique_sw_id = strongSwan-$(PACKAGE_VERSION_MAJOR)-$(PACKAGE_VERSION_MINOR)-$(PACKAGE_VERSION_BUILD)$(PACKAGE_VERSION_REVIEW)
swid_tag = $(regid)_$(unique_sw_id).swidtag
swid_tag = $(regid)__$(unique_sw_id).swidtag
swiddir = $(prefix)/share/$(regid)
swid_DATA = $(swid_tag)
ipsec_DATA = $(swid_tag)
EXTRA_DIST = $(regid)_strongSwan.swidtag.in
CLEANFILES = $(regid)_strongSwan*.swidtag
swiddir = $(pkgdatadir)/swidtag
dist_swid_DATA = $(swid_tag)
EXTRA_DIST = $(regid)__strongSwan.swidtag.in
CLEANFILES = $(regid)__strongSwan*.swidtag
$(swid_tag) : regid.2004-03.org.strongswan_strongSwan.swidtag.in
$(swid_tag) : $(regid)__strongSwan.swidtag.in
$(AM_V_GEN) \
sed \
-e "s:@VERSION_MAJOR@:$(PACKAGE_VERSION_MAJOR):" \
-e "s:@VERSION_MINOR@:$(PACKAGE_VERSION_MINOR):" \
-e "s:@VERSION_BUILD@:$(PACKAGE_VERSION_BUILD):" \
-e "s:@VERSION_REVIEW@:$(PACKAGE_VERSION_REVIEW):" \
$(srcdir)/$(regid)_strongSwan.swidtag.in > $@
$(srcdir)/$(regid)__strongSwan.swidtag.in > $@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>apache2</product_title>
<product_version>
<name>2.2-22-13</name>
<numeric>
<major>2</major>
<minor>2</minor>
<build>22</build>
<review>13</review>
</numeric>
</product_version>
<software_creator>
<name>Apache Software Foundation</name>
<regid>regid.1995-04.org.apache</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>apache-2-2-22-13</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>bind9</product_title>
<product_version>
<name>9-8-4-dfsg</name>
<numeric>
<major>9</major>
<minor>8</minor>
<build>4</build>
<review>dfsg</review>
</numeric>
</product_version>
<software_creator>
<name>Internet Systems Consortium</name>
<regid>regid.1994-04.org.isc</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>bind-9-8-4-dfsg</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libsqlite3</product_title>
<product_version>
<name>3.7.13-1</name>
<numeric>
<major>3</major>
<minor>7</minor>
<build>13</build>
<review>1</review>
</numeric>
</product_version>
<software_creator>
<name>SQLite Project</name>
<regid>regid.2002-08.org.sqlite</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libsqlite-3-7-13-1</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libssl1.0.0</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libssl-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libssl-dev</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libssl-dev-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>openssl</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>openssl-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>sqlite3</product_title>
<product_version>
<name>3.7.13-1</name>
<numeric>
<major>3</major>
<minor>7</minor>
<build>13</build>
<review>1</review>
</numeric>
</product_version>
<software_creator>
<name>SQLite Project</name>
<regid>regid.2002-08.org.sqlite</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>sqlite-3-7-13-1</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<SoftwareIdentity
name="strongSwan"
uniqueId="strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@"
tagId="strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@"
version="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_BUILD@@VERSION_REVIEW@" versionScheme="alphanumeric"
xmlns="http://standards.iso.org/iso/19770/-2/2014/schema.xsd">
xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd">
<Entity
name="strongSwan Project"
regid="regid.2004-03.org.strongswan"
role="publisher licensor tagcreator"/>
regid="strongswan.org"
role="softwareCreator licensor tagCreator"/>
</SoftwareIdentity>
+2
View File
@@ -0,0 +1,2 @@
strongswan.org_*.swidtag
sw-collector
+52
View File
@@ -0,0 +1,52 @@
regid = strongswan.org
unique_sw_id = strongSwan-$(PACKAGE_VERSION_MAJOR)-$(PACKAGE_VERSION_MINOR)-$(PACKAGE_VERSION_BUILD)$(PACKAGE_VERSION_REVIEW)
swid_tag = $(regid)__$(unique_sw_id).swidtag
swiddir = $(pkgdatadir)/swidtag
dist_swid_DATA = $(swid_tag)
EXTRA_DIST = $(regid)__strongSwan.swidtag.in
CLEANFILES = $(regid)__strongSwan*.swidtag
$(swid_tag) : $(regid)__strongSwan.swidtag.in
$(AM_V_GEN) \
sed \
-e "s:@VERSION_MAJOR@:$(PACKAGE_VERSION_MAJOR):" \
-e "s:@VERSION_MINOR@:$(PACKAGE_VERSION_MINOR):" \
-e "s:@VERSION_BUILD@:$(PACKAGE_VERSION_BUILD):" \
-e "s:@VERSION_REVIEW@:$(PACKAGE_VERSION_REVIEW):" \
$(srcdir)/$(regid)__strongSwan.swidtag.in > $@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv \
-DPLUGINS=\""random openssl sqlite curl"\"
AM_CFLAGS = \
$(PLUGIN_CFLAGS) $(json_CFLAGS)
imcv_LTLIBRARIES = imc-swima.la
imc_swima_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imc_swima_la_SOURCES = imc_swima.c imc_swima_state.h imc_swima_state.c
imc_swima_la_LDFLAGS = -module -avoid-version -no-undefined
ipsec_PROGRAMS = sw-collector
sw_collector_SOURCES = \
sw_collector/sw-collector.c \
sw_collector/sw_collector_db.h sw_collector/sw_collector_db.c \
sw_collector/sw_collector_history.h sw_collector/sw_collector_history.c \
sw_collector/sw_collector_rest_api.h sw_collector/sw_collector_rest_api.c
sw_collector_LDADD = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libimcv/libimcv.la \
$(json_LIBS)
sw-collector.o : $(top_builddir)/config.status
templatesdir = $(pkgdatadir)/templates/database/sw-collector
dist_templates_DATA = sw_collector/sw_collector_tables.sql
+407
View File
@@ -0,0 +1,407 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "imc_swima_state.h"
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include "ietf/swima/ietf_swima_attr_req.h"
#include "ietf/swima/ietf_swima_attr_sw_inv.h"
#include "ietf/swima/ietf_swima_attr_sw_ev.h"
#include "swima/swima_inventory.h"
#include "swima/swima_collector.h"
#include "swima/swima_error.h"
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
/* IMC definitions */
static const char imc_name[] = "SWIMA";
static pen_type_t msg_types[] = {
{ PEN_IETF, PA_SUBTYPE_IETF_SW }
};
static imc_agent_t *imc_swima;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
if (imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_swima = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_swima)
{
return TNC_RESULT_FATAL;
}
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_swima_state_create(connection_id);
return imc_swima->create_state(imc_swima, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_swima->change_state(imc_swima, connection_id, new_state,
&state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_swima->delete_state(imc_swima, connection_id);
default:
return imc_swima->change_state(imc_swima, connection_id,
new_state, NULL);
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
imc_state_t *state;
imc_msg_t *out_msg;
pa_tnc_attr_t *attr;
seg_contract_t *contract;
seg_contract_manager_t *contracts;
size_t max_attr_size = SWIMA_MAX_ATTR_SIZE;
size_t max_seg_size;
char buf[BUF_LEN];
TNC_Result result = TNC_RESULT_SUCCESS;
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swima->get_state(imc_swima, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
/* Determine maximum PA-TNC attribute segment size */
max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE
- PA_TNC_ATTR_HEADER_SIZE
- TCG_SEG_ATTR_SEG_ENV_HEADER;
/* Announce support of PA-TNC segmentation to IMV */
contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size,
TRUE, imc_id, TRUE);
contract->get_info_string(contract, buf, BUF_LEN, TRUE);
DBG2(DBG_IMC, "%s", buf);
contracts = state->get_contracts(state);
contracts->add_contract(contracts, contract);
attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE);
/* send PA-TNC message with the excl flag not set */
out_msg = imc_msg_create(imc_swima, state, connection_id, imc_id,
TNC_IMVID_ANY, msg_types[0]);
out_msg->add_attribute(out_msg, attr);
result = out_msg->send(out_msg, FALSE);
out_msg->destroy(out_msg);
return result;
}
/**
* Add SWID Inventory or Event attribute to the send queue
*/
static void fulfill_request(imc_state_t *state, imc_msg_t *msg,
uint32_t request_id, bool sw_id_only,
swima_inventory_t *targets)
{
pa_tnc_attr_t *attr;
swima_collector_t *collector;
size_t msg_len = 64;
char error_msg[msg_len], *id_str;
bool collect_inventory = TRUE;
int items;
collector = swima_collector_create();
id_str = sw_id_only ? " ID" : "";
if (targets->get_eid(targets, NULL) > 0)
{
swima_events_t *sw_ev;
ietf_swima_attr_sw_ev_t *sw_ev_attr;
sw_ev = collector->collect_events(collector, sw_id_only, targets);
if (!sw_ev)
{
snprintf(error_msg, msg_len, "failed to collect SW%s events, "
"fallback to SW%s inventory", id_str, id_str);
attr = swima_error_create(PA_ERROR_SW, request_id, 0, error_msg);
msg->add_attribute(msg, attr);
}
else {
items = sw_ev->get_count(sw_ev);
DBG1(DBG_IMC, "collected %d SW%s event%s", items, id_str,
items == 1 ? "" : "s");
/* Send an IETF SW [Identity] Events attribute */
attr = ietf_swima_attr_sw_ev_create(IETF_SWIMA_ATTR_SW_INV_FLAG_NONE,
request_id, sw_id_only);
sw_ev_attr = (ietf_swima_attr_sw_ev_t*)attr;
sw_ev_attr->set_events(sw_ev_attr, sw_ev);
collect_inventory = FALSE;
}
}
if (collect_inventory)
{
swima_inventory_t *sw_inv;
ietf_swima_attr_sw_inv_t *sw_inv_attr;
sw_inv = collector->collect_inventory(collector, sw_id_only, targets);
if (!sw_inv)
{
snprintf(error_msg, msg_len, "failed to collect SW%s inventory",
id_str);
attr = swima_error_create(PA_ERROR_SW, request_id, 0, error_msg);
}
else
{
items = sw_inv->get_count(sw_inv);
DBG1(DBG_IMC, "collected %d SW%s record%s", items, id_str,
items == 1 ? "" : "s");
/* Send an IETF SW [Identity] Inventory attribute */
attr = ietf_swima_attr_sw_inv_create(IETF_SWIMA_ATTR_SW_INV_FLAG_NONE,
request_id, sw_id_only);
sw_inv_attr = (ietf_swima_attr_sw_inv_t*)attr;
sw_inv_attr->set_inventory(sw_inv_attr, sw_inv);
}
}
msg->add_attribute(msg, attr);
collector->destroy(collector);
}
static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
pa_tnc_attr_t *attr;
enumerator_t *enumerator;
pen_type_t type;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imc_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
ietf_swima_attr_req_t *attr_req;
uint8_t flags;
uint32_t request_id;
bool sw_id_only;
swima_inventory_t *targets;
type = attr->get_type(attr);
if (type.vendor_id != PEN_IETF || type.type != IETF_ATTR_SW_REQUEST)
{
continue;
}
attr_req = (ietf_swima_attr_req_t*)attr;
flags = attr_req->get_flags(attr_req);
request_id = attr_req->get_request_id(attr_req);
targets = attr_req->get_targets(attr_req);
if (flags & (IETF_SWIMA_ATTR_REQ_FLAG_S | IETF_SWIMA_ATTR_REQ_FLAG_C))
{
attr = swima_error_create(PA_ERROR_SW_SUBSCRIPTION_DENIED,
request_id, 0, "no subscription available yet");
out_msg->add_attribute(out_msg, attr);
break;
}
sw_id_only = (flags & IETF_SWIMA_ATTR_REQ_FLAG_R);
fulfill_request(state, out_msg, request_id, sw_id_only, targets);
break;
}
enumerator->destroy(enumerator);
if (fatal_error)
{
result = TNC_RESULT_FATAL;
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swima->get_state(imc_swima, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_swima, state, connection_id, msg_type,
chunk_create(msg, msg_len));
result = receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swima->get_state(imc_swima, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_swima, state, connection_id,
src_imv_id, dst_imc_id,msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result =receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
{
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_swima->destroy(imc_swima);
imc_swima = NULL;
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_swima)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_swima->bind_functions(imc_swima, bind_function);
}
@@ -0,0 +1,176 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "imc_swima_state.h"
#include <tncif_names.h>
#include <utils/debug.h>
typedef struct private_imc_swima_state_t private_imc_swima_state_t;
/**
* Private data of an imc_swima_state_t object.
*/
struct private_imc_swima_state_t {
/**
* Public members of imc_swima_state_t
*/
imc_swima_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
uint32_t max_msg_len;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_swima_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_swima_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_swima_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_swima_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_swima_state_t *this, uint32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, uint32_t,
private_imc_swima_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, get_contracts, seg_contract_manager_t*,
private_imc_swima_state_t *this)
{
return this->contracts;
}
METHOD(imc_state_t, change_state, void,
private_imc_swima_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_swima_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_swima_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_swima_state_t *this)
{
this->contracts->destroy(this->contracts);
free(this);
}
/**
* Described in header.
*/
imc_state_t *imc_swima_state_create(TNC_ConnectionID connection_id)
{
private_imc_swima_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.get_contracts = _get_contracts,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
},
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.contracts = seg_contract_manager_create(),
);
return &this->public.interface;
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 imc_swima imc_swima
* @ingroup libimcv_plugins
*
* @defgroup imc_swima_state_t imc_swima_state
* @{ @ingroup imc_swima
*/
#ifndef IMC_SWIMA_STATE_H_
#define IMC_SWIMA_STATE_H_
#include <imc/imc_state.h>
#include <library.h>
typedef struct imc_swima_state_t imc_swima_state_t;
/**
* Internal state of an imc_swima_t connection instance
*/
struct imc_swima_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
};
/**
* Create an imc_swima_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_swima_state_create(TNC_ConnectionID id);
#endif /** IMC_SWIMA_STATE_H_ @}*/
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<SoftwareIdentity
name="strongSwan"
tagId="strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@"
version="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_BUILD@@VERSION_REVIEW@" versionScheme="alphanumeric"
xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd">
<Entity
name="strongSwan Project"
regid="strongswan.org"
role="softwareCreator licensor tagCreator"/>
</SoftwareIdentity>
@@ -0,0 +1,565 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif
#include "sw_collector_db.h"
#include "sw_collector_history.h"
#include "sw_collector_rest_api.h"
#include <library.h>
#include <utils/debug.h>
#include <utils/lexparser.h>
/**
* global debug output variables
*/
static int debug_level = 2;
static bool stderr_quiet = FALSE;
static int count = 0;
typedef enum collector_op_t collector_op_t;
enum collector_op_t {
COLLECTOR_OP_EXTRACT,
COLLECTOR_OP_LIST,
COLLECTOR_OP_UNREGISTERED,
COLLECTOR_OP_GENERATE
};
/**
* sw_collector dbg function
*/
static void sw_collector_dbg(debug_t group, level_t level, char *fmt, ...)
{
va_list args;
if (level <= debug_level)
{
if (!stderr_quiet)
{
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
#ifdef HAVE_SYSLOG
{
int priority = LOG_INFO;
char buffer[8192];
char *current = buffer, *next;
/* write in memory buffer first */
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
/* do a syslog with every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
syslog(priority, "%s\n", current);
current = next;
}
}
#endif /* HAVE_SYSLOG */
}
}
/**
* atexit handler
*/
static void cleanup(void)
{
library_deinit();
#ifdef HAVE_SYSLOG
closelog();
#endif
}
/**
* Display usage of sw-collector command
*/
static void usage(void)
{
printf("\
Usage:\n\
sw-collector --help\n\
sw-collector [--debug <level>] [--quiet] --list\n\
sw-collector [--debug <level>] [--quiet] --unregistered|--generate\n\
sw-collector [--debug <level>] [--quiet] [--count <event count>]\n");
}
/**
* Parse command line options
*/
static collector_op_t do_args(int argc, char *argv[])
{
collector_op_t op = COLLECTOR_OP_EXTRACT;
/* reinit getopt state */
optind = 0;
while (TRUE)
{
int c;
struct option long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "count", required_argument, NULL, 'c' },
{ "debug", required_argument, NULL, 'd' },
{ "generate", no_argument, NULL, 'g' },
{ "list", no_argument, NULL, 'l' },
{ "quiet", no_argument, NULL, 'q' },
{ "unregistered", no_argument, NULL, 'u' },
{ 0,0,0,0 }
};
c = getopt_long(argc, argv, "hc:d:lqu", long_opts, NULL);
switch (c)
{
case EOF:
break;
case 'h':
usage();
exit(SUCCESS);
break;
case 'c':
count = atoi(optarg);
continue;
case 'd':
debug_level = atoi(optarg);
continue;
case 'g':
op = COLLECTOR_OP_GENERATE;
continue;
case 'l':
op = COLLECTOR_OP_LIST;
continue;
case 'q':
stderr_quiet = TRUE;
continue;
case 'u':
op = COLLECTOR_OP_UNREGISTERED;
continue;
default:
usage();
exit(EXIT_FAILURE);
}
break;
}
return op;
}
/**
* Extract software events from apt history log files
*/
static int extract_history(sw_collector_db_t *db)
{
sw_collector_history_t *history = NULL;
uint32_t epoch, last_eid, eid = 0;
char *history_path, *last_time = NULL, rfc_time[21];
chunk_t *h, history_chunk, line, cmd;
int status = EXIT_FAILURE;
bool skip = TRUE;
/* open history file for reading */
history_path= lib->settings->get_str(lib->settings, "%s.history", NULL,
lib->ns);
if (!history_path)
{
fprintf(stderr, "sw-collector.history path not set.\n");
return FALSE;
}
h = chunk_map(history_path, FALSE);
if (!h)
{
fprintf(stderr, "opening '%s' failed: %s", history, strerror(errno));
return FALSE;
}
history_chunk = *h;
/* Instantiate history extractor */
history = sw_collector_history_create(db, 1);
if (!history)
{
/* OS is not supported */
goto end;
}
/* retrieve last event in database */
if (!db->get_last_event(db, &last_eid, &epoch, &last_time) || !last_eid)
{
goto end;
}
DBG0(DBG_IMC, "Last-Event: %s, eid = %u, epoch = %u",
last_time, last_eid, epoch);
/* parse history file */
while (fetchline(&history_chunk, &line))
{
if (line.len == 0)
{
continue;
}
if (!extract_token(&cmd, ':', &line))
{
fprintf(stderr, "terminator symbol ':' not found.\n");
goto end;
}
if (match("Start-Date", &cmd))
{
if (!history->extract_timestamp(history, line, rfc_time))
{
goto end;
}
/* have we reached new history entries? */
if (skip && strcmp(rfc_time, last_time) > 0)
{
skip = FALSE;
}
if (skip)
{
continue;
}
/* insert new event into database */
eid = db->add_event(db, rfc_time);
if (!eid)
{
goto end;
}
DBG1(DBG_IMC, "Start-Date: %s, eid = %u, epoch = %u",
rfc_time, eid, epoch);
}
else if (skip)
{
/* skip old history entries which have already been processed */
continue;
}
else if (match("Install", &cmd))
{
DBG1(DBG_IMC, " Install:");
if (!history->extract_packages(history, line, eid, SW_OP_INSTALL))
{
goto end;
}
}
else if (match("Upgrade", &cmd))
{
DBG1(DBG_IMC, " Upgrade:");
if (!history->extract_packages(history, line, eid, SW_OP_UPGRADE))
{
goto end;
}
}
else if (match("Remove", &cmd))
{
DBG1(DBG_IMC, " Remove:");
if (!history->extract_packages(history, line, eid, SW_OP_REMOVE))
{
goto end;
}
}
else if (match("Purge", &cmd))
{
DBG1(DBG_IMC, " Purge:");
if (!history->extract_packages(history, line, eid, SW_OP_REMOVE))
{
goto end;
}
}
else if (match("End-Date", &cmd))
{
/* Process 'count' events at a time */
if (count > 0 && eid - last_eid == count)
{
fprintf(stderr, "added %d events\n", count);
goto end;
}
}
}
if (history->merge_installed_packages(history))
{
status = EXIT_SUCCESS;
}
end:
free(last_time);
DESTROY_IF(history);
chunk_unmap(h);
return status;
}
/**
* List all endpoint software identifiers stored in local collector database
*/
static int list_identifiers(sw_collector_db_t *db)
{
enumerator_t *e;
char *name, *package, *version;
uint32_t count = 0, installed_count = 0, installed;
e = db->create_sw_enumerator(db, SW_QUERY_ALL);
if (!e)
{
return EXIT_FAILURE;
}
while (e->enumerate(e, &name, &package, &version, &installed))
{
printf("%s,%s,%s,%d\n", name, package, version, installed);
if (installed)
{
installed_count++;
}
count++;
}
e->destroy(e);
DBG1(DBG_IMC, "retrieved %u software identities with %u installed and %u "
"deleted", count, installed_count, count - installed_count);
return EXIT_SUCCESS;
}
static bool query_registry(sw_collector_rest_api_t *rest_api, bool installed)
{
sw_collector_db_query_t type;
enumerator_t *enumerator;
char *sw_id;
int count = 0;
type = installed ? SW_QUERY_INSTALLED : SW_QUERY_DELETED;
enumerator = rest_api->create_sw_enumerator(rest_api, type);
if (!enumerator)
{
return FALSE;
}
while (enumerator->enumerate(enumerator, &sw_id))
{
printf("%s,%s\n", sw_id, installed ? "1" : "0");
count++;
}
enumerator->destroy(enumerator);
DBG1(DBG_IMC, "%d %s software identifiers not registered", count,
installed ? "installed" : "deleted");
return TRUE;
}
/**
* List all endpoint software identifiers stored in local collector database
* that are not registered yet in central collelector database
*/
static int unregistered_identifiers(sw_collector_db_t *db)
{
sw_collector_rest_api_t *rest_api;
int status = EXIT_SUCCESS;
rest_api = sw_collector_rest_api_create(db);
if (!rest_api)
{
return EXIT_FAILURE;
}
/* List installed software identifiers not registered centrally */
if (!query_registry(rest_api, TRUE))
{
status = EXIT_FAILURE;
}
/* List deleted software identifiers not registered centrally */
if (!query_registry(rest_api, FALSE))
{
status = EXIT_FAILURE;
}
rest_api->destroy(rest_api);
return status;
}
/**
* Generate a minimalistic ISO 19770-2:2015 SWID tag
*/
static char* generate_tag(char *name, char *package, char *version,
char* entity, char *regid, char *product)
{
char *tag_id, *tag;
int res;
tag_id = strstr(name, "__");
if (!tag_id)
{
return NULL;
}
tag_id += 2;
res = asprintf(&tag, "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<SoftwareIdentity name=\"%s\" tagId=\"%s\" version=\"%s\" "
"versionScheme=\"alphanumeric\" "
"xmlns=\"http://standards.iso.org/iso/19770/-2/2015/schema.xsd\">"
"<Entity name=\"%s\" regid=\"%s\" role=\"tagCreator\"/>"
"<Meta product=\"%s\"/>"
"</SoftwareIdentity>",
package, tag_id, version, entity, regid, product);
return (res == -1) ? NULL : tag;
}
static int generate_tags(sw_collector_db_t *db)
{
sw_collector_history_t *os_info;
sw_collector_rest_api_t *rest_api;
char *pos, *name, *package, *version, *entity, *regid, *product, *tag;
enumerator_t *enumerator;
uint32_t sw_id;
int status = EXIT_FAILURE;
entity = lib->settings->get_str(lib->settings, "%s.tag_creator.name",
"strongSwan Project", lib->ns);
regid = lib->settings->get_str(lib->settings, "%s.tag_creator.regid",
"strongswan.org", lib->ns);
os_info = sw_collector_history_create(db, 0);
if (!os_info)
{
return EXIT_FAILURE;
}
os_info->get_os(os_info, &product);
rest_api = sw_collector_rest_api_create(db);
if (!rest_api)
{
goto end;
}
enumerator = rest_api->create_sw_enumerator(rest_api, SW_QUERY_DELETED);
if (!enumerator)
{
goto end;
}
while (enumerator->enumerate(enumerator, &name))
{
sw_id = db->get_sw_id(db, name, &package, &version, NULL, NULL);
if (sw_id)
{
/* Remove architecture from package name */
pos = strchr(package, ':');
if (pos)
{
*pos = '\0';
}
tag = generate_tag(name, package, version, entity, regid, product);
if (tag)
{
printf("%s\n", tag);
free(tag);
count++;
}
free(package);
free(version);
}
}
enumerator->destroy(enumerator);
status = EXIT_SUCCESS;
DBG1(DBG_IMC, "%d tags for deleted unregistered software identifiers",
count);
end:
os_info->destroy(os_info);
DESTROY_IF(rest_api);
return status;
}
int main(int argc, char *argv[])
{
sw_collector_db_t *db = NULL;
collector_op_t op;
char *uri;
int status;
op = do_args(argc, argv);
/* enable sw_collector debugging hook */
dbg = sw_collector_dbg;
#ifdef HAVE_SYSLOG
openlog("sw-collector", 0, LOG_DEBUG);
#endif
atexit(cleanup);
/* initialize library */
if (!library_init(NULL, "sw-collector"))
{
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
/* load sw-collector plugins */
if (!lib->plugins->load(lib->plugins,
lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns)))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
/* connect to sw-collector database */
uri = lib->settings->get_str(lib->settings, "%s.database", NULL, lib->ns);
if (!uri)
{
fprintf(stderr, "sw-collector.database URI not set.\n");
exit(EXIT_FAILURE);
}
db = sw_collector_db_create(uri);
if (!db)
{
fprintf(stderr, "connection to sw-collector database failed.\n");
exit(EXIT_FAILURE);
}
switch (op)
{
case COLLECTOR_OP_EXTRACT:
status = extract_history(db);
break;
case COLLECTOR_OP_LIST:
status = list_identifiers(db);
break;
case COLLECTOR_OP_UNREGISTERED:
status = unregistered_identifiers(db);
break;
case COLLECTOR_OP_GENERATE:
status = generate_tags(db);
default:
break;
}
db->destroy(db);
exit(status);
}
@@ -0,0 +1,363 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "sw_collector_db.h"
#include "swima/swima_event.h"
typedef struct private_sw_collector_db_t private_sw_collector_db_t;
/**
* Private data of an sw_collector_db_t object.
*/
struct private_sw_collector_db_t {
/**
* Public members of sw_collector_db_state_t
*/
sw_collector_db_t public;
/**
* Epoch
*/
uint32_t epoch;
/**
* Event ID of last event stored in database
*/
uint32_t last_eid;
/**
* Software collector database
*/
database_t *db;
};
METHOD(sw_collector_db_t, add_event, uint32_t,
private_sw_collector_db_t *this, char *timestamp)
{
uint32_t eid = 0;
if (this->db->execute(this->db, &eid,
"INSERT INTO events (epoch, timestamp) VALUES (?, ?)",
DB_UINT, this->epoch, DB_TEXT, timestamp) != 1)
{
DBG1(DBG_IMC, "unable to insert event into database");
return 0;
}
return eid;
}
METHOD(sw_collector_db_t, get_last_event, bool,
private_sw_collector_db_t *this, uint32_t *eid, uint32_t *epoch,
char **last_time)
{
char *timestamp;
enumerator_t *e;
e = this->db->query(this->db,
"SELECT id, epoch, timestamp FROM events ORDER BY timestamp DESC",
DB_UINT, DB_UINT, DB_TEXT);
if (!e)
{
DBG1(DBG_IMC, "database query for event failed");
return FALSE;
}
if (e->enumerate(e, eid, epoch, &timestamp))
{
if (last_time)
{
*last_time = strdup(timestamp);
}
}
else
{
*eid = 0;
}
e->destroy(e);
return TRUE;
}
METHOD(sw_collector_db_t, add_sw_event, bool,
private_sw_collector_db_t *this, uint32_t eid, uint32_t sw_id,
uint8_t action)
{
if (this->db->execute(this->db, NULL,
"INSERT INTO sw_events (eid, sw_id, action) VALUES (?, ?, ?)",
DB_UINT, eid, DB_UINT, sw_id, DB_UINT, action) != 1)
{
DBG1(DBG_IMC, "unable to insert sw_event into database");
return FALSE;
}
return TRUE;
}
METHOD(sw_collector_db_t, set_sw_id, uint32_t,
private_sw_collector_db_t *this, char *name, char *package, char *version,
uint8_t source, bool installed, bool check)
{
uint32_t sw_id = 0, status;
enumerator_t *e;
/* Does software identifier already exist in database? */
e = this->db->query(this->db,
"SELECT id, installed FROM sw_identifiers WHERE name = ?",
DB_TEXT, name, DB_UINT, DB_UINT);
if (!e)
{
DBG1(DBG_IMC, "database query for sw_identifier failed");
return 0;
}
if (!e->enumerate(e, &sw_id, &status))
{
sw_id = 0;
}
e->destroy(e);
if (sw_id)
{
if (status == installed)
{
if (!check)
{
DBG1(DBG_IMC, " Warning: sw_id %u is already %s", sw_id,
status ? "installed" : "deleted");
}
return sw_id;
}
if (check)
{
DBG1(DBG_IMC, " Warning: sw_id %u is %s", sw_id,
status ? "installed" : "deleted");
}
/* Change installation status */
if (this->db->execute(this->db, NULL,
"UPDATE sw_identifiers SET installed = ? WHERE id = ?",
DB_UINT, installed, DB_UINT, sw_id) != 1)
{
DBG1(DBG_IMC, "unable to update sw_id status in database");
return 0;
}
}
else
{
/* Create new software identifier */
if (this->db->execute(this->db, &sw_id,
"INSERT INTO sw_identifiers "
"(name, package, version, source, installed) VALUES "
"(?, ?, ?, ?, ?)",
DB_TEXT, name, DB_TEXT, package, DB_TEXT, version,
DB_UINT, source, DB_UINT, installed) != 1)
{
DBG1(DBG_IMC, "unable to insert sw_id into database");
return 0;
}
if (check || !installed)
{
add_sw_event(this, 1, sw_id, SWIMA_EVENT_ACTION_CREATION);
}
}
return sw_id;
}
METHOD(sw_collector_db_t, get_sw_id, uint32_t,
private_sw_collector_db_t *this, char *name, char **package, char **version,
uint8_t *source, bool *installed)
{
char *sw_package, *sw_version;
uint32_t sw_id = 0, sw_source, sw_installed;
enumerator_t *e;
/* Does software identifier already exist in database? */
e = this->db->query(this->db,
"SELECT id, package, version, source, installed "
"FROM sw_identifiers WHERE name = ?",
DB_TEXT, name, DB_UINT, DB_TEXT, DB_TEXT, DB_UINT, DB_UINT);
if (!e)
{
DBG1(DBG_IMC, "database query for sw_identifier failed");
return 0;
}
if (e->enumerate(e, &sw_id, &sw_package, &sw_version, &sw_source,
&sw_installed))
{
if (package)
{
*package = strdup(sw_package);
}
if (version)
{
*version = strdup(sw_version);
}
if (source)
{
*source = sw_source;
}
if (installed)
{
*installed = sw_installed;
}
}
e->destroy(e);
return sw_id;
}
METHOD(sw_collector_db_t, get_sw_id_count, uint32_t,
private_sw_collector_db_t *this, sw_collector_db_query_t type)
{
uint32_t count, installed;
enumerator_t *e;
if (type == SW_QUERY_ALL)
{
e = this->db->query(this->db,
"SELECT COUNT(installed) FROM sw_identifiers", DB_UINT);
}
else
{
installed = (type == SW_QUERY_INSTALLED);
e = this->db->query(this->db,
"SELECT COUNT(installed) FROM sw_identifiers WHERE installed = ?",
DB_UINT, installed, DB_UINT);
}
if (!e)
{
DBG1(DBG_IMC, "database query for sw_identifier count failed");
return 0;
}
if (!e->enumerate(e, &count))
{
count = 0;
}
e->destroy(e);
return count;
}
METHOD(sw_collector_db_t, create_sw_enumerator, enumerator_t*,
private_sw_collector_db_t *this, sw_collector_db_query_t type)
{
enumerator_t *e;
uint32_t installed;
if (type == SW_QUERY_ALL)
{
e = this->db->query(this->db,
"SELECT name, package, version, installed FROM sw_identifiers "
"ORDER BY name ASC", DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
}
else
{
installed = (type == SW_QUERY_INSTALLED);
e = this->db->query(this->db,
"SELECT name, package, version, installed FROM sw_identifiers "
"WHERE installed = ? ORDER BY name ASC",
DB_UINT, installed, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
}
if (!e)
{
DBG1(DBG_IMC, "database query for sw_identifier count failed");
return NULL;
}
return e;
}
METHOD(sw_collector_db_t, destroy, void,
private_sw_collector_db_t *this)
{
this->db->destroy(this->db);
free(this);
}
/**
* Described in header.
*/
sw_collector_db_t *sw_collector_db_create(char *uri)
{
private_sw_collector_db_t *this;
uint32_t first_eid, last_eid;
char *first_time;
INIT(this,
.public = {
.add_event = _add_event,
.get_last_event = _get_last_event,
.add_sw_event = _add_sw_event,
.set_sw_id = _set_sw_id,
.get_sw_id = _get_sw_id,
.get_sw_id_count = _get_sw_id_count,
.create_sw_enumerator = _create_sw_enumerator,
.destroy = _destroy,
},
.db = lib->db->create(lib->db, uri),
);
if (!this->db)
{
DBG1(DBG_IMC, "opening database URI '%s' failed", uri);
return NULL;
}
/* Retrieve last event in database */
if (!get_last_event(this, &last_eid, &this->epoch, NULL))
{
destroy(this);
return NULL;
}
/* Create random epoch and first event if no events exist yet */
if (!last_eid)
{
rng_t *rng;
rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
if (!rng ||
!rng->get_bytes(rng, sizeof(uint32_t), (uint8_t*)&this->epoch))
{
DESTROY_IF(rng);
destroy(this);
DBG1(DBG_IMC, "generating random epoch value failed");
return NULL;
}
rng->destroy(rng);
/* strongTNC workaround - limit epoch to 31 bit unsigned integer */
this->epoch &= 0x7fffffff;
/* Create first event when the OS was installed */
first_time = lib->settings->get_str(lib->settings,
"sw-collector.first_time", "0000-00-00T00:00:00Z");
first_eid = add_event(this, first_time);
if (!first_eid)
{
destroy(this);
return NULL;
}
DBG0(DBG_IMC, "First-Date: %s, eid = %u, epoch = %u",
first_time, first_eid, this->epoch);
}
return &this->public;
}
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 sw_collector_db_t sw_collector_db
* @{ @ingroup imc_swima
*/
#ifndef SW_COLLECTOR_DB_H_
#define SW_COLLECTOR_DB_H_
#include <library.h>
typedef struct sw_collector_db_t sw_collector_db_t;
typedef enum sw_collector_db_query_t sw_collector_db_query_t;
/**
* Type of software identifier queries
*/
enum sw_collector_db_query_t {
SW_QUERY_ALL,
SW_QUERY_INSTALLED,
SW_QUERY_DELETED
};
/**
* Software collector database object
*/
struct sw_collector_db_t {
/**
* bAdd event to database
*
* @param timestamp Timestamp in 20 octet RFC 3339 format
* @return Primary key pointing to event ID or 0 if failed
*/
uint32_t (*add_event)(sw_collector_db_t *this, char *timestamp);
/**
* Get last event, zero EID if none exists
*
* @param eid Primary key pointing to last event
* @param epoch Epoch
* @param last_time Timestamp in 20 octet RFC 3339 format of last event
* @return
*/
bool (*get_last_event)(sw_collector_db_t *this, uint32_t *eid,
uint32_t *epoch, char **last_time);
/**
* Add software identifier event to database
*
* @param eid Foreign key pointing to an event ID
* @param sw_id Foreign key pointing to a software identifier
* @param action 1 for CREATION, 2 for deletion
* @return TRUE if successful
*/
bool (*add_sw_event)(sw_collector_db_t *this, uint32_t eid, uint32_t sw_id,
uint8_t action);
/**
* Set software_identifier, checking if the identifier already exists
*
* @param name Software identifier
* @param package Software package
* @param version Version of software package
* @param source Source ID of the software collector
* @param installed Installation status to be set, TRUE if installed
* @param check Check if SW ID is already installed
* @return Primary key pointing to SW ID or 0 if failed
*/
uint32_t (*set_sw_id)(sw_collector_db_t *this, char *name, char *package,
char *version, uint8_t source, bool installed,
bool check);
/**
* Get software_identifier record
*
* @param name Software identifier
* @param package Software package
* @param version Version of software package
* @param source Source ID of the software collector
* @param installed Installation status
* @return Primary key pointing to SW ID or 0 if failed
*/
uint32_t (*get_sw_id)(sw_collector_db_t *this, char *name, char **package,
char **version, uint8_t *source, bool *installed);
/**
* Get number of installed or deleted software identifiers
*
* @param type Query type (ALL, INSTALLED, DELETED)
* @return Count
*/
uint32_t (*get_sw_id_count)(sw_collector_db_t *this,
sw_collector_db_query_t type);
/**
* Enumerate over all collected [installed] software identities
*
* @param type Query type (ALL, INSTALLED, DELETED)
* @return Enumerator
*/
enumerator_t* (*create_sw_enumerator)(sw_collector_db_t *this,
sw_collector_db_query_t type);
/**
* Destroy sw_collector_db_t object
*/
void (*destroy)(sw_collector_db_t *this);
};
/**
* Create an sw_collector_db_t instance
*
* @param uri database URI
*/
sw_collector_db_t* sw_collector_db_create(char *uri);
#endif /** SW_COLLECTOR_DB_H_ @}*/
@@ -0,0 +1,495 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <time.h>
#include "sw_collector_history.h"
#include "imc/imc_os_info.h"
#include "swima/swima_event.h"
typedef struct private_sw_collector_history_t private_sw_collector_history_t;
/**
* Private data of an sw_collector_history_t object.
*/
struct private_sw_collector_history_t {
/**
* Public members of sw_collector_history_state_t
*/
sw_collector_history_t public;
/**
* tagCreator
*/
char *tag_creator;
/**
* OS string 'name_version-arch'
*/
char *os;
/**
* Product string 'name version arch'
*/
char *product;
/**
* OS info about endpoint
*/
imc_os_info_t *os_info;
/**
* Software Event Source Number
*/
uint8_t source;
/**
* Reference to collector database
*/
sw_collector_db_t *db;
};
METHOD(sw_collector_history_t, get_os, char*,
private_sw_collector_history_t *this, char **product)
{
if (product)
{
*product = this->product;
}
return this->os;
}
/**
* Define auxiliary package_t list item object
*/
typedef struct package_t package_t;
struct package_t {
char *package;
char *version;
char *old_version;
char *sw_id;
char *old_sw_id;
};
/**
* Replaces invalid character by a valid one
*/
static void sanitize_uri(char *uri, char a, char b)
{
char *pos = uri;
while (TRUE)
{
pos = strchr(pos, a);
if (!pos)
{
break;
}
*pos = b;
pos++;
}
}
/**
* Create software identifier
*/
char* create_sw_id(char *tag_creator, char *os, char *package, char *version)
{
char *pos, *sw_id;
size_t len;
/* Remove architecture from package name */
pos = strchr(package, ':');
len = pos ? (pos - package) : strlen(package);
/* Build software identifier */
if (asprintf(&sw_id, "%s__%s-%.*s%s%s", tag_creator, os, len, package,
strlen(version) ? "-" : "", version) == -1)
{
return NULL;
}
sanitize_uri(sw_id, ':', '~');
sanitize_uri(sw_id, '+', '~');
return sw_id;
}
/**
* Create package_t list item object
*/
static package_t* create_package(char* tag_creator, char *os, chunk_t package,
chunk_t version, chunk_t old_version)
{
package_t *this;
INIT(this,
.package = strndup(package.ptr, package.len),
.version = strndup(version.ptr, version.len),
.old_version = strndup(old_version.ptr, old_version.len),
)
this->sw_id = create_sw_id(tag_creator, os, this->package, this->version);
if (old_version.len)
{
this->old_sw_id = create_sw_id(tag_creator, os, this->package,
this->old_version);
}
return this;
}
/**
* Free package_t list item object
*/
static void free_package(package_t *this)
{
if (this)
{
free(this->package);
free(this->version);
free(this->old_version);
free(this->sw_id);
free(this->old_sw_id);
free(this);
}
}
/**
* Extract and parse a single package item
*/
static package_t* extract_package(chunk_t item, char *tag_creator, char *os,
sw_collector_history_op_t op)
{
chunk_t package, version, old_version;
package_t *p;
/* extract package name */
if (!extract_token(&package, ' ', &item))
{
fprintf(stderr, "version not found.\n");
return NULL;
}
item = chunk_skip(item, 1);
/* extract versions */
version = old_version = chunk_empty;
if (item.len > 0)
{
if (extract_token(&version, ',', &item))
{
eat_whitespace(&item);
if (!match("automatic", &item))
{
old_version = version;
version = item;
}
}
else
{
version = item;
}
}
p = create_package(tag_creator, os, package, version, old_version);
/* generate log entry */
if (op == SW_OP_UPGRADE)
{
DBG2(DBG_IMC, " %s (%s, %s)", p->package, p->old_version, p->version);
DBG2(DBG_IMC, " +%s", p->sw_id);
DBG2(DBG_IMC, " -%s", p->old_sw_id);
}
else
{
DBG2(DBG_IMC, " %s (%s)", p->package, p->version);
DBG2(DBG_IMC, " %s%s", (op == SW_OP_INSTALL) ? "+" : "-", p->sw_id);
}
return p;
}
METHOD(sw_collector_history_t, extract_timestamp, bool,
private_sw_collector_history_t *this, chunk_t args, char *buf)
{
struct tm loc, utc;
chunk_t t1, t2;
time_t t;
/* Break down local time with format t1 = yyyy-mm-dd and t2 = hh:mm:ss */
if (!eat_whitespace(&args) || !extract_token(&t1, ' ', &args) ||
!eat_whitespace(&args) || t1.len != 10 || args.len != 8)
{
DBG1(DBG_IMC, "unable to parse start-date");
return FALSE;
}
t2 = args;
if (sscanf(t1.ptr, "%4d-%2d-%2d",
&loc.tm_year, &loc.tm_mon, &loc.tm_mday) != 3)
{
DBG1(DBG_IMC, "unable to parse date format yyyy-mm-dd");
return FALSE;
}
loc.tm_year -= 1900;
loc.tm_mon -= 1;
loc.tm_isdst = -1;
if (sscanf(t2.ptr, "%2d:%2d:%2d",
&loc.tm_hour, &loc.tm_min, &loc.tm_sec) != 3)
{
DBG1(DBG_IMC, "unable to parse time format hh:mm:ss");
return FALSE;
}
/* Convert from local time to UTC */
t = mktime(&loc);
gmtime_r(&t, &utc);
utc.tm_year += 1900;
utc.tm_mon += 1;
/* Form timestamp according to RFC 3339 (20 characters) */
snprintf(buf, 21, "%4d-%02d-%02dT%02d:%02d:%02dZ",
utc.tm_year, utc.tm_mon, utc.tm_mday,
utc.tm_hour, utc.tm_min, utc.tm_sec);
return TRUE;
}
METHOD(sw_collector_history_t, extract_packages, bool,
private_sw_collector_history_t *this, chunk_t args, uint32_t eid,
sw_collector_history_op_t op)
{
package_t *p = NULL;
uint32_t sw_id;
chunk_t item;
bool success = FALSE;
eat_whitespace(&args);
while (extract_token(&item, ')', &args))
{
p = extract_package(item, this->tag_creator, this->os, op);
if (!p)
{
goto end;
}
/* packages without version information cannot be handled */
if (strlen(p->version) == 0)
{
free_package(p);
continue;
}
sw_id = this->db->set_sw_id(this->db, p->sw_id, p->package, p->version,
this->source, op != SW_OP_REMOVE, FALSE);
if (!sw_id)
{
goto end;
}
if (!this->db->add_sw_event(this->db, eid, sw_id, op != SW_OP_REMOVE ?
SWIMA_EVENT_ACTION_CREATION : SWIMA_EVENT_ACTION_DELETION))
{
goto end;
}
if (op == SW_OP_UPGRADE)
{
sw_id = this->db->set_sw_id(this->db, p->old_sw_id, p->package,
p->old_version, this->source, FALSE,
FALSE);
if (!sw_id)
{
goto end;
}
if (!this->db->add_sw_event(this->db, eid, sw_id,
SWIMA_EVENT_ACTION_DELETION))
{
goto end;
}
}
free_package(p);
if (args.len < 2)
{
break;
}
args = chunk_skip(args, 2);
}
p = NULL;
success = TRUE;
end:
free_package(p);
return success;
}
METHOD(sw_collector_history_t, merge_installed_packages, bool,
private_sw_collector_history_t *this)
{
FILE *file;
uint32_t sw_id, count = 0;
char line[BUF_LEN], *pos, *package, *version, *state, *name;
bool success = FALSE;
char cmd[] = "dpkg-query -W -f=\'${Package}\t${Version}\t${Status}\n\'";
DBG1(DBG_IMC, "Merging:");
file = popen(cmd, "r");
if (!file)
{
DBG1(DBG_IMC, "failed to run dpgk-query command");
return FALSE;
}
while (TRUE)
{
if (!fgets(line, sizeof(line), file))
{
break;
}
package = line;
pos = strchr(line, '\t');
if (!pos)
{
goto end;
}
*pos = '\0';
version = ++pos;
pos = strchr(pos, '\t');
if (!pos)
{
goto end;
}
*pos = '\0';
state = ++pos;
pos = strchr(pos, '\n');
if (!pos)
{
goto end;
}
*pos = '\0';
if (!streq(state, "install ok installed"))
{
continue;
}
name = create_sw_id(this->tag_creator, this->os, package, version);
DBG3(DBG_IMC, " %s merged", name);
sw_id = this->db->set_sw_id(this->db, name, package, version,
this->source, TRUE, TRUE);
free(name);
if (!sw_id)
{
goto end;
}
count++;
}
success = TRUE;
DBG1(DBG_IMC, " merged %u installed packages, %u registed in database",
count, this->db->get_sw_id_count(this->db, SW_QUERY_INSTALLED));
end:
pclose(file);
return success;
}
METHOD(sw_collector_history_t, destroy, void,
private_sw_collector_history_t *this)
{
this->os_info->destroy(this->os_info);
free(this->os);
free(this->product);
free(this);
}
/**
* Described in header.
*/
sw_collector_history_t *sw_collector_history_create(sw_collector_db_t *db,
uint8_t source)
{
private_sw_collector_history_t *this;
chunk_t os_name, os_version, os_arch;
os_type_t os_type;
INIT(this,
.public = {
.get_os = _get_os,
.extract_timestamp = _extract_timestamp,
.extract_packages = _extract_packages,
.merge_installed_packages = _merge_installed_packages,
.destroy = _destroy,
},
.db = db,
.source = source,
.os_info = imc_os_info_create(),
.tag_creator = lib->settings->get_str(lib->settings,
"%s.tag_creator.regid", "strongswan.org", lib->ns),
);
os_type = this->os_info->get_type(this->os_info);
os_name = this->os_info->get_name(this->os_info);
os_arch = this->os_info->get_version(this->os_info);
/* check if OS is supported */
if (os_type != OS_TYPE_DEBIAN && os_type != OS_TYPE_UBUNTU)
{
DBG1(DBG_IMC, "%.*s OS not supported", os_name.len, os_name.ptr);
destroy(this);
return NULL;
}
/* get_version() returns version followed by arch */
if (!extract_token(&os_version, ' ', &os_arch))
{
DBG1(DBG_IMC, "separation of OS version from arch failed");
destroy(this);
return NULL;
}
/* construct OS string */
if (asprintf(&this->os, "%.*s_%.*s-%.*s", os_name.len, os_name.ptr,
os_version.len, os_version.ptr,
os_arch.len, os_arch.ptr) == -1)
{
DBG1(DBG_IMC, "constructon of OS string failed");
destroy(this);
return NULL;
}
/* construct product string */
if (asprintf(&this->product, "%.*s %.*s %.*s", os_name.len, os_name.ptr,
os_version.len, os_version.ptr,
os_arch.len, os_arch.ptr) == -1)
{
DBG1(DBG_IMC, "constructon of product string failed");
destroy(this);
return NULL;
}
return &this->public;
}
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 sw_collector_history_t sw_collector_history
* @{ @ingroup imc_swima
*/
#ifndef SW_COLLECTOR_HISTORY_H_
#define SW_COLLECTOR_HISTORY_H_
#include "sw_collector_db.h"
#include <library.h>
#include <utils/debug.h>
#include <utils/lexparser.h>
typedef struct sw_collector_history_t sw_collector_history_t;
typedef enum sw_collector_history_op_t sw_collector_history_op_t;
/**
* Define major history event operations
*/
enum sw_collector_history_op_t {
SW_OP_INSTALL,
SW_OP_UPGRADE,
SW_OP_REMOVE
};
/**
* Software collector history object
*/
struct sw_collector_history_t {
/**
* Get OS and product strings
*
* @param product Product string formed from OS info
* @return OS string formed from OS info
*/
char* (*get_os)(sw_collector_history_t *this, char **product);
/**
* Extract timestamp from event in installation history
*
* @param args Arguments to be processed
* @param buf timestamp buffer for 21 byte RFC 3339 string
* @return TRUE if extraction succeeded
*/
bool (*extract_timestamp)(sw_collector_history_t *this, chunk_t args,
char *buf);
/**
* Extract packages from event in installation history
*
* @param args Arguments to be processed
* @param eid Primary key pointing to current event
* @param op Extraction operation
* @return TRUE if extraction succeeded
*/
bool (*extract_packages)(sw_collector_history_t *this, chunk_t args,
uint32_t eid, sw_collector_history_op_t op);
/**
* Merge packages from initial installation
*
* @return TRUE if merge succeeded
*/
bool (*merge_installed_packages)(sw_collector_history_t *this);
/**
* Destroy sw_collector_history_t object
*/
void (*destroy)(sw_collector_history_t *this);
};
/**
* Create an sw_collector_history_t instance
*
* @param db Internal reference to collector database
* @param source Software event source number
*/
sw_collector_history_t* sw_collector_history_create(sw_collector_db_t *db,
uint8_t source);
#endif /** SW_COLLECTOR_HISTORY_H_ @}*/
@@ -0,0 +1,200 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "sw_collector_rest_api.h"
#include <rest/rest.h>
#include <utils/debug.h>
typedef struct private_sw_collector_rest_api_t private_sw_collector_rest_api_t;
/**
* Private data of an sw_collector_rest_api_t object.
*/
struct private_sw_collector_rest_api_t {
/**
* Public members of sw_collector_rest_api_state_t
*/
sw_collector_rest_api_t public;
/**
* Software collector database
*/
sw_collector_db_t *db;
/**
* REST API of central collector database
*/
rest_t *rest_api;
};
/**
* Put all locally retrieved software identifiers into a json object
*/
static json_object* create_rest_request(private_sw_collector_rest_api_t *this,
sw_collector_db_query_t type)
{
json_object *jrequest, *jarray, *jstring;
char *name, *package, *version;
uint32_t i;
enumerator_t *e;
jrequest = json_object_new_object();
jarray = json_object_new_array();
json_object_object_add(jrequest, "data", jarray);
e = this->db->create_sw_enumerator(this->db, type);
if (!e)
{
return NULL;
}
while (e->enumerate(e, &name, &package, &version, &i))
{
jstring = json_object_new_string(name);
json_object_array_add(jarray, jstring);
}
e->destroy(e);
return jrequest;
}
typedef struct {
/** public enumerator interface */
enumerator_t public;
/** enumerated json array */
json_object *jarray;
/** current index +1, initialized at 0 */
int idx;
} json_array_enumerator_t;
METHOD(enumerator_t, enumerate, bool,
json_array_enumerator_t *this, va_list args)
{
json_object *jvalue;
char **out;
VA_ARGS_VGET(args, out);
if (this->idx >= json_object_array_length(this->jarray))
{
return FALSE;
}
jvalue = json_object_array_get_idx(this->jarray, this->idx++);
if (json_object_get_type(jvalue) != json_type_string)
{
DBG1(DBG_IMC, "json_string element expected in json_array");
return FALSE;
}
*out = (char*)json_object_get_string(jvalue);
return TRUE;
}
METHOD(enumerator_t, enumerator_destroy, void,
json_array_enumerator_t *this)
{
json_object_put(this->jarray);
free(this);
}
METHOD(sw_collector_rest_api_t, create_sw_enumerator, enumerator_t*,
private_sw_collector_rest_api_t *this, sw_collector_db_query_t type)
{
json_array_enumerator_t *enumerator;
json_object *jrequest, *jresponse;
char cmd[BUF_LEN];
status_t status;
jrequest = create_rest_request(this, type);
if (!jrequest)
{
return NULL;
}
snprintf(cmd, BUF_LEN, "sessions/0/swid-measurement/");
status = this->rest_api->post(this->rest_api, cmd, jrequest, &jresponse);
json_object_put(jrequest);
switch (status)
{
case SUCCESS:
case NOT_FOUND:
jresponse = json_object_new_array();
break;
case NEED_MORE:
if (json_object_get_type(jresponse) != json_type_array)
{
DBG1(DBG_IMC, "REST response was not a json_array");
json_object_put(jresponse);
return NULL;
}
break;
case FAILED:
default:
return NULL;
}
INIT(enumerator,
.public = {
.enumerate = enumerator_enumerate_default,
.venumerate = _enumerate,
.destroy = _enumerator_destroy,
},
.jarray = jresponse,
);
return &enumerator->public;
}
METHOD(sw_collector_rest_api_t, destroy, void,
private_sw_collector_rest_api_t *this)
{
this->rest_api->destroy(this->rest_api);
free(this);
}
/**
* Described in header.
*/
sw_collector_rest_api_t *sw_collector_rest_api_create(sw_collector_db_t *db)
{
private_sw_collector_rest_api_t *this;
int timeout;
char *uri;
uri = lib->settings->get_str(lib->settings, "%s.rest_api.uri", NULL,
lib->ns);
timeout = lib->settings->get_int(lib->settings, "%s.rest_api.timeout", 120,
lib->ns);
if (!uri)
{
DBG1(DBG_IMC, "REST URI to central collector database not set");
return NULL;
}
INIT(this,
.public = {
.create_sw_enumerator = _create_sw_enumerator,
.destroy = _destroy,
},
.db = db,
.rest_api = rest_create(uri, timeout),
);
return &this->public;
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 sw_collector_rest_api_t sw_collector_rest_api
* @{ @ingroup imc_swima
*/
#ifndef SW_COLLECTOR_REST_API_H_
#define SW_COLLECTOR_REST_API_H_
#include "sw_collector_db.h"
typedef struct sw_collector_rest_api_t sw_collector_rest_api_t;
/**
* Software collector database object
*/
struct sw_collector_rest_api_t {
/**
* List of locally stored software identifiers that are not registered
* in a central collector database
*
* @param type Query type (ALL, INSTALLED, DELETED)
* @return Enumerator
*/
enumerator_t* (*create_sw_enumerator)(sw_collector_rest_api_t *this,
sw_collector_db_query_t type);
/**
* Destroy sw_collector_rest_api_t object
*/
void (*destroy)(sw_collector_rest_api_t *this);
};
/**
* Create an sw_collector_rest_api_t instance
*
* @param db Software collector database to be used
*/
sw_collector_rest_api_t* sw_collector_rest_api_create(sw_collector_db_t *db);
#endif /** SW_COLLECTOR_REST_API_H_ @}*/
@@ -0,0 +1,31 @@
/* SQLit database for an Endpoint Collector */
DROP TABLE IF EXISTS "events";
CREATE TABLE "events" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"epoch" INTEGER NOT NULL,
"timestamp" CHAR(20) NOT NULL
);
DROP TABLE IF EXISTS "sw_identifiers";
CREATE TABLE "sw_identifiers" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" VARCHAR(255) NOT NULL,
"package" VARCHAR(255) NOT NULL,
"version" VARCHAR(255) NOT NULL,
"source" INTEGER DEFAULT 0,
"installed" INTEGER DEFAULT 1,
"tag" TEXT
);
DROP INDEX IF EXISTS "sw_identifiers_name";
CREATE INDEX "sw_identifiers_name" ON "sw_identifiers" (
"name"
);
DROP TABLE IF EXISTS "sw_events";
CREATE TABLE "sw_events" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"eid" INTEGER REFERENCES "events" ("id"),
"sw_id" INTEGER NOT NULL REFERENCES "sw_identifiers" ("id"),
"action" INTEGER NOT NULL
);
+155 -84
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -133,6 +133,11 @@ struct private_attest_db_t {
*/
char *version;
/**
* Primary key of software package version to be queried
*/
int vid;
/**
* TRUE if version has been set
*/
@@ -975,7 +980,7 @@ METHOD(attest_db_t, list_files, void,
{
while (e->enumerate(e, &fid, &file))
{
printf("%4d: %s\n", fid, file);
printf("%6d: %s\n", fid, file);
count++;
}
e->destroy(e);
@@ -996,10 +1001,10 @@ METHOD(attest_db_t, list_files, void,
{
if (did != last_did)
{
printf("%4d: %s\n", did, dir);
printf("%6d: %s\n", did, dir);
last_did = did;
}
printf("%4d: %s\n", fid, file);
printf("%6d: %s\n", fid, file);
count++;
}
e->destroy(e);
@@ -1182,24 +1187,24 @@ METHOD(attest_db_t, list_hashes, void,
private_attest_db_t *this)
{
enumerator_t *e;
chunk_t hash;
char *file, *dir, *product;
char *file, *dir, *product, *hash;
int id, fid, fid_old = 0, did, did_old = 0, pid, pid_old = 0, count = 0;
if (this->pid && this->fid && this->did)
{
printf("%4d: %s\n", this->did, this->dir);
printf("%4d: %s\n", this->fid, this->file);
printf("%6d: %s\n", this->did, this->dir);
printf("%6d: %s\n", this->fid, this->file);
e = this->db->query(this->db,
"SELECT id, hash FROM file_hashes "
"WHERE algo = ? AND file = ? AND product = ?",
"SELECT h.id, h.hash FROM file_hashes AS h "
"JOIN versions AS v ON h.version = v.id "
"WHERE h.algo = ? AND h.file = ? AND v.product = ?",
DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->pid,
DB_INT, DB_BLOB);
DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash))
{
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1216,25 +1221,26 @@ METHOD(attest_db_t, list_hashes, void,
"FROM file_hashes AS h "
"JOIN files AS f ON h.file = f.id "
"JOIN directories AS d ON f.dir = d.id "
"WHERE h.algo = ? AND h.product = ? AND f.name = ? "
"JOIN versions AS v ON h.version = v.id "
"WHERE h.algo = ? AND v.product = ? AND f.name = ? "
"ORDER BY d.path, f.name, h.hash",
DB_INT, this->algo, DB_INT, this->pid, DB_TEXT, this->file,
DB_INT, DB_BLOB, DB_INT, DB_INT, DB_TEXT);
DB_INT, DB_TEXT, DB_INT, DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash, &fid, &did, &dir))
{
if (did != did_old)
{
printf("%4d: %s\n", did, dir);
printf("%6d: %s\n", did, dir);
did_old = did;
}
if (fid != fid_old)
{
printf("%4d: %s\n", fid, this->file);
printf("%6d: %s\n", fid, this->file);
fid_old = fid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1246,25 +1252,26 @@ METHOD(attest_db_t, list_hashes, void,
}
else if (this->pid && this->did)
{
printf("%4d: %s\n", this->did, this->dir);
printf("%6d: %s\n", this->did, this->dir);
e = this->db->query(this->db,
"SELECT h.id, h.hash, f.id, f.name "
"FROM file_hashes AS h "
"JOIN files AS f ON h.file = f.id "
"WHERE h.algo = ? AND h.product = ? AND f.dir = ? "
"JOIN versions AS v ON h.version = v.id "
"WHERE h.algo = ? AND v.product = ? AND f.dir = ? "
"ORDER BY f.name, h.hash",
DB_INT, this->algo, DB_INT, this->pid, DB_INT, this->did,
DB_INT, DB_BLOB, DB_INT, DB_TEXT);
DB_INT, DB_TEXT, DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash, &fid, &file))
{
if (fid != fid_old)
{
printf("%4d: %s\n", fid, file);
printf("%6d: %s\n", fid, file);
fid_old = fid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1281,25 +1288,26 @@ METHOD(attest_db_t, list_hashes, void,
"FROM file_hashes AS h "
"JOIN files AS f ON h.file = f.id "
"JOIN directories AS d ON f.dir = d.id "
"WHERE h.algo = ? AND h.product = ? "
"JOIN versions AS v ON h.version = v.id "
"WHERE h.algo = ? AND v.product = ? "
"ORDER BY d.path, f.name, h.hash",
DB_INT, this->algo, DB_INT, this->pid,
DB_INT, DB_BLOB, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir))
{
if (did != did_old)
{
printf("%4d: %s\n", did, dir);
printf("%6d: %s\n", did, dir);
did_old = did;
}
if (fid != fid_old)
{
printf("%4d: %s\n", fid, file);
printf("%6d: %s\n", fid, file);
fid_old = fid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1313,21 +1321,22 @@ METHOD(attest_db_t, list_hashes, void,
{
e = this->db->query(this->db,
"SELECT h.id, h.hash, p.id, p.name FROM file_hashes AS h "
"JOIN products AS p ON h.product = p.id "
"JOIN versions AS v ON h.version = v.id "
"JOIN products AS p ON v.product = p.id "
"WHERE h.algo = ? AND h.file = ? "
"ORDER BY p.name, h.hash",
DB_INT, this->algo, DB_INT, this->fid,
DB_INT, DB_BLOB, DB_INT, DB_TEXT);
DB_INT, DB_TEXT, DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash, &pid, &product))
{
if (pid != pid_old)
{
printf("%4d: %s\n", pid, product);
printf("%6d: %s\n", pid, product);
pid_old = pid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1345,32 +1354,33 @@ METHOD(attest_db_t, list_hashes, void,
"FROM file_hashes AS h "
"JOIN files AS f ON h.file = f.id "
"JOIN directories AS d ON f.dir = d.id "
"JOIN products AS p ON h.product = p.id "
"JOIN versions AS v ON h.version = v.id "
"JOIN products AS p ON v.product = p.id "
"WHERE h.algo = ? AND f.name = ? "
"ORDER BY d.path, f.name, p.name, h.hash",
DB_INT, this->algo, DB_TEXT, this->file,
DB_INT, DB_BLOB, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
DB_INT, DB_TEXT, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash, &fid, &did, &dir, &pid, &product))
{
if (did != did_old)
{
printf("%4d: %s\n", did, dir);
printf("%6d: %s\n", did, dir);
did_old = did;
}
if (fid != fid_old)
{
printf("%4d: %s\n", fid, this->file);
printf("%6d: %s\n", fid, this->file);
fid_old = fid;
pid_old = 0;
}
if (pid != pid_old)
{
printf("%4d: %s\n", pid, product);
printf("%6d: %s\n", pid, product);
pid_old = pid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1386,27 +1396,28 @@ METHOD(attest_db_t, list_hashes, void,
"SELECT h.id, h.hash, f.id, f.name, p.id, p.name "
"FROM file_hashes AS h "
"JOIN files AS f ON h.file = f.id "
"JOIN products AS p ON h.product = p.id "
"JOIN versions AS v ON h.version = v.id "
"JOIN products AS p ON v.product = p.id "
"WHERE h.algo = ? AND f.dir = ? "
"ORDER BY f.name, p.name, h.hash",
DB_INT, this->algo, DB_INT, this->did,
DB_INT, DB_BLOB, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
DB_INT, DB_TEXT, DB_INT, DB_TEXT, DB_INT, DB_TEXT);
if (e)
{
while (e->enumerate(e, &id, &hash, &fid, &file, &pid, &product))
{
if (fid != fid_old)
{
printf("%4d: %s\n", fid, file);
printf("%6d: %s\n", fid, file);
fid_old = fid;
pid_old = 0;
}
if (pid != pid_old)
{
printf("%4d: %s\n", pid, product);
printf("%6d: %s\n", pid, product);
pid_old = pid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1423,10 +1434,11 @@ METHOD(attest_db_t, list_hashes, void,
"FROM file_hashes AS h "
"JOIN files AS f ON h.file = f.id "
"JOIN directories AS d ON f.dir = d.id "
"JOIN products AS p on h.product = p.id "
"JOIN versions AS v ON h.version = v.id "
"JOIN products AS p on v.product = p.id "
"WHERE h.algo = ? "
"ORDER BY d.path, f.name, p.name, h.hash",
DB_INT, this->algo, DB_INT, DB_BLOB, DB_INT, DB_TEXT,
DB_INT, this->algo, DB_INT, DB_TEXT, DB_INT, DB_TEXT,
DB_INT, DB_TEXT, DB_INT, DB_TEXT);
if (e)
{
@@ -1435,21 +1447,21 @@ METHOD(attest_db_t, list_hashes, void,
{
if (did != did_old)
{
printf("%4d: %s\n", did, dir);
printf("%6d: %s\n", did, dir);
did_old = did;
}
if (fid != fid_old)
{
printf("%4d: %s\n", fid, file);
printf("%6d: %s\n", fid, file);
fid_old = fid;
pid_old = 0;
}
if (pid != pid_old)
{
printf("%4d: %s\n", pid, product);
printf("%6d: %s\n", pid, product);
pid_old = pid;
}
printf("%4d: %#B\n", id, &hash);
printf("%6d: %s\n", id, hash);
count++;
}
e->destroy(e);
@@ -1610,28 +1622,32 @@ static bool insert_file_hash(private_attest_db_t *this,
int *hashes_added, int *hashes_updated)
{
enumerator_t *e;
chunk_t hash;
uint8_t hex_measurement_buf[2*HASH_SIZE_SHA512 + 1];
uint8_t *hex_hash_buf;
chunk_t hex_hash, hex_measurement;
char *label;
bool insert = TRUE, update = FALSE;
label = "could not be created";
e = this->db->query(this->db,
"SELECT hash FROM file_hashes WHERE algo = ? "
"AND file = ? AND product = ? AND device = 0",
DB_INT, algo, DB_UINT, fid, DB_UINT, this->pid, DB_BLOB);
"SELECT hash FROM file_hashes "
"WHERE algo = ? AND file = ? AND version = ?",
DB_INT, algo, DB_UINT, fid, DB_UINT, this->vid, DB_TEXT);
if (!e)
{
printf("file_hashes query failed\n");
return FALSE;
}
hex_measurement = chunk_to_hex(measurement, hex_measurement_buf, FALSE);
while (e->enumerate(e, &hash))
while (e->enumerate(e, &hex_hash_buf))
{
update = TRUE;
hex_hash = chunk_from_str(hex_hash_buf);
if (chunk_equals(measurement, hash))
if (chunk_equals(hex_measurement, hex_hash))
{
label = "exists and equals";
insert = FALSE;
@@ -1644,10 +1660,10 @@ static bool insert_file_hash(private_attest_db_t *this,
{
if (this->db->execute(this->db, NULL,
"INSERT INTO file_hashes "
"(file, product, device, algo, hash) "
"VALUES (?, ?, 0, ?, ?)",
DB_UINT, fid, DB_UINT, this->pid,
DB_INT, algo, DB_BLOB, measurement) != 1)
"(file, version, algo, hash) "
"VALUES (?, ?, ?, ?)",
DB_UINT, fid, DB_UINT, this->vid,
DB_INT, algo, DB_TEXT, hex_measurement) != 1)
{
printf("file_hash insertion failed\n");
return FALSE;
@@ -1667,6 +1683,75 @@ static bool insert_file_hash(private_attest_db_t *this,
return TRUE;
}
/**
* Add a package version
*/
static bool add_version(private_attest_db_t *this)
{
int vid, security_old, security, blacklist_old, blacklist;
time_t t = time(NULL);
enumerator_t *e;
bool success;
security = this->package_state == OS_PACKAGE_STATE_SECURITY;
blacklist = this->package_state == OS_PACKAGE_STATE_BLACKLIST;
e = this->db->query(this->db,
"SELECT id, security, blacklist FROM versions "
"WHERE package = ? AND product = ? AND release = ?",
DB_UINT, this->gid, DB_UINT, this->pid, DB_TEXT, this->version,
DB_INT, DB_INT, DB_INT, DB_INT);
if (e)
{
if (e->enumerate(e, &vid, &security_old, &blacklist_old))
{
this->vid = vid;
}
e->destroy(e);
}
if (this->vid)
{
if (security != security_old || blacklist != blacklist_old)
{
/* update security and/or blacklist flag */
success = this->db->execute(this->db, NULL, "UPDATE versions "
"SET security = ?, blacklist = ?, time = ? WHERE id = ?",
DB_INT, security, DB_INT, blacklist, DB_INT, t,
DB_INT, this->vid) == 1;
printf("'%s' package %s (%s)%N %s updated in database\n",
this->product, this->package, this->version,
os_package_state_names, this->package_state,
success ? "" : "could not be ");
}
else
{
success = TRUE;
printf("'%s' package %s (%s)%N exists in database\n",
this->product, this->package, this->version,
os_package_state_names, this->package_state);
}
return success;
}
/* create a new version */
success = this->db->execute(this->db, NULL,
"INSERT INTO versions "
"(package, product, release, security, blacklist, time) "
"VALUES (?, ?, ?, ?, ?, ?)",
DB_UINT, this->gid, DB_INT, this->pid, DB_TEXT,
this->version, DB_INT, security, DB_INT, blacklist,
DB_INT, t) == 1;
printf("'%s' package %s (%s)%N %sinserted into database\n",
this->product, this->package, this->version,
os_package_state_names, this->package_state,
success ? "" : "could not be ");
return success;
}
/**
* Add hash measurement for a single file or all files in a directory
*/
@@ -1771,7 +1856,14 @@ static bool add_hash(private_attest_db_t *this)
METHOD(attest_db_t, add, bool,
private_attest_db_t *this)
{
bool success = FALSE;
/* insert package version */
if (this->version_set && this->gid && this->pid)
{
if (!add_version(this))
{
return FALSE;
}
}
/* add directory or file hash measurement for a given product */
if (this->did && this->pid)
@@ -1779,29 +1871,7 @@ METHOD(attest_db_t, add, bool,
return add_hash(this);
}
/* insert package version */
if (this->version_set && this->gid && this->pid)
{
time_t t = time(NULL);
int security, blacklist;
security = this->package_state == OS_PACKAGE_STATE_SECURITY;
blacklist = this->package_state == OS_PACKAGE_STATE_BLACKLIST;
success = this->db->execute(this->db, NULL,
"INSERT INTO versions "
"(package, product, release, security, blacklist, time) "
"VALUES (?, ?, ?, ?, ?, ?)",
DB_UINT, this->gid, DB_INT, this->pid, DB_TEXT,
this->version, DB_INT, security, DB_INT, blacklist,
DB_INT, t) == 1;
printf("'%s' package %s (%s)%N %sinserted into database\n",
this->product, this->package, this->version,
os_package_state_names, this->package_state,
success ? "" : "could not be ");
}
return success;
return FALSE;
}
METHOD(attest_db_t, delete, bool,
@@ -1816,8 +1886,9 @@ METHOD(attest_db_t, delete, bool,
if (this->algo && this->pid && this->fid)
{
success = this->db->execute(this->db, NULL,
"DELETE FROM file_hashes "
"WHERE algo = ? AND product = ? AND file = ?",
"DELETE FROM file_hashes AS h "
"JOIN versions AS v ON h.version = v.id "
"WHERE h.algo = ? AND v.product = ? AND h.file = ?",
DB_UINT, this->algo, DB_UINT, this->pid,
DB_UINT, this->fid) > 0;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -77,8 +77,9 @@ Usage:\n\
ipsec attest --add [--owner <name>] --key <digest>|--aik <path>\n\
Add an AIK public key digest entry preceded by an optional owner name\n\
\n\
ipsec attest --add --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\
[--relative|--rel] --dir <path>|--file <path>\n\
ipsec attest --add --product <name>|--pid <id> --sha1|--sha256|--sha384\n\
[--relative|--rel] [--package <name> --version <string>]\n\
--dir <path>|--file <path>\n\
Add hashes of a single file or all files in a directory under absolute or relative filenames\n\
\n\
ipsec attest --add --key <digest|--kid <id> --component <cfn>|--cid <id> --sequence <no>|--seq <no>\n\
+1 -2
View File
@@ -16,7 +16,6 @@ imv_swid_la_LIBADD = \
imv_swid_la_SOURCES = \
imv_swid.c imv_swid_state.h imv_swid_state.c \
imv_swid_agent.h imv_swid_agent.c \
imv_swid_rest.h imv_swid_rest.c
imv_swid_agent.h imv_swid_agent.c
imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2016 Andreas Steffen
* Copyright (C) 2013-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,12 +18,12 @@
#include "imv_swid_agent.h"
#include "imv_swid_state.h"
#include "imv_swid_rest.h"
#include <imcv.h>
#include <imv/imv_agent.h>
#include <imv/imv_msg.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include "rest/rest.h"
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include "tcg/swid/tcg_swid_attr_req.h"
@@ -72,7 +72,7 @@ struct private_imv_swid_agent_t {
/**
* REST API to strongTNC manager
*/
imv_swid_rest_t *rest_api;
rest_t *rest_api;
};
@@ -719,7 +719,7 @@ imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id,
"%s.plugins.imv-swid.rest_api_timeout", 120, lib->ns);
if (rest_api_uri)
{
this->rest_api = imv_swid_rest_create(rest_api_uri, rest_api_timeout);
this->rest_api = rest_create(rest_api_uri, rest_api_timeout);
}
return &this->public;
@@ -1,124 +0,0 @@
/*
* Copyright (C) 2014 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "imv_swid_rest.h"
typedef struct private_imv_swid_rest_t private_imv_swid_rest_t;
/**
* Private data of an imv_swid_rest_t object.
*/
struct private_imv_swid_rest_t {
/**
* Public members of imv_swid_rest_t
*/
imv_swid_rest_t public;
/**
* URI of REST API
*/
char *uri;
/**
* Timeout of REST API connection
*/
u_int timeout;
};
#define HTTP_STATUS_CODE_PRECONDITION_FAILED 412
METHOD(imv_swid_rest_t, post, status_t,
private_imv_swid_rest_t *this, char *command, json_object *jrequest,
json_object **jresponse)
{
struct json_tokener *tokener;
chunk_t data, response = chunk_empty;
status_t status;
char *uri;
int code;
if (asprintf(&uri, "%s%s",this->uri, command) < 0)
{
return FAILED;
}
data = chunk_from_str((char*)json_object_to_json_string(jrequest));
status = lib->fetcher->fetch(lib->fetcher, uri, &response,
FETCH_TIMEOUT, this->timeout,
FETCH_REQUEST_DATA, data,
FETCH_REQUEST_TYPE, "application/json; charset=utf-8",
FETCH_REQUEST_HEADER, "Accept: application/json",
FETCH_REQUEST_HEADER, "Expect:",
FETCH_RESPONSE_CODE, &code,
FETCH_END);
free(uri);
if (status != SUCCESS)
{
if (code != HTTP_STATUS_CODE_PRECONDITION_FAILED || !response.ptr)
{
DBG2(DBG_IMV, "REST http request failed with status code: %d", code);
status = FAILED;
}
else
{
if (jresponse)
{
/* Parse HTTP response into a JSON object */
tokener = json_tokener_new();
*jresponse = json_tokener_parse_ex(tokener, response.ptr,
response.len);
json_tokener_free(tokener);
}
status = NEED_MORE;
}
}
free(response.ptr);
return status;
}
METHOD(imv_swid_rest_t, destroy, void,
private_imv_swid_rest_t *this)
{
free(this->uri);
free(this);
}
/**
* Described in header.
*/
imv_swid_rest_t *imv_swid_rest_create(char *uri, u_int timeout)
{
private_imv_swid_rest_t *this;
INIT(this,
.public = {
.post = _post,
.destroy = _destroy,
},
.uri = strdup(uri),
.timeout = timeout,
);
return &this->public;
}
+21
View File
@@ -0,0 +1,21 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libtpmtss \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
$(PLUGIN_CFLAGS) $(json_CFLAGS)
imcv_LTLIBRARIES = imv-swima.la
imv_swima_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(json_LIBS)
imv_swima_la_SOURCES = \
imv_swima.c imv_swima_state.h imv_swima_state.c \
imv_swima_agent.h imv_swima_agent.c
imv_swima_la_LDFLAGS = -module -avoid-version -no-undefined
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "imv_swima_agent.h"
static const char imv_name[] = "SWIMA";
static const imv_agent_create_t imv_agent_create = imv_swima_agent_create;
/* include generic TGC TNC IF-IMV API code below */
#include <imv/imv_if.h>
@@ -0,0 +1,804 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "imv_swima_agent.h"
#include "imv_swima_state.h"
#include <imcv.h>
#include <imv/imv_agent.h>
#include <imv/imv_msg.h>
#include "rest/rest.h"
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include "ietf/swima/ietf_swima_attr_req.h"
#include "ietf/swima/ietf_swima_attr_sw_inv.h"
#include "ietf/swima/ietf_swima_attr_sw_ev.h"
#include "swima/swima_error.h"
#include "swima/swima_inventory.h"
#include "swima/swima_events.h"
#include "swima/swima_data_model.h"
#include <tncif_names.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <bio/bio_reader.h>
typedef struct private_imv_swima_agent_t private_imv_swima_agent_t;
/* Subscribed PA-TNC message subtypes */
static pen_type_t msg_types[] = {
{ PEN_IETF, PA_SUBTYPE_IETF_SW }
};
/**
* Flag set when corresponding attribute has been received
*/
enum imv_swima_attr_t {
IMV_SWIMA_ATTR_SW_INV = (1<<0),
IMV_SWIMA_ATTR_SW_ID_INV = (1<<1),
IMV_SWIMA_ATTR_SW_EV = (1<<2),
IMV_SWIMA_ATTR_SW_ID_EV = (1<<2)
};
/**
* Private data of an imv_swima_agent_t object.
*/
struct private_imv_swima_agent_t {
/**
* Public members of imv_swima_agent_t
*/
imv_agent_if_t public;
/**
* IMV agent responsible for generic functions
*/
imv_agent_t *agent;
/**
* REST API to strongTNC manager
*/
rest_t *rest_api;
};
METHOD(imv_agent_if_t, bind_functions, TNC_Result,
private_imv_swima_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
{
return this->agent->bind_functions(this->agent, bind_function);
}
METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
private_imv_swima_agent_t *this, TNC_ConnectionID id,
TNC_ConnectionState new_state)
{
imv_state_t *state;
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imv_swima_state_create(id);
return this->agent->create_state(this->agent, state);
case TNC_CONNECTION_STATE_DELETE:
return this->agent->delete_state(this->agent, id);
default:
return this->agent->change_state(this->agent, id, new_state, NULL);
}
}
/**
* Process a received message
*/
static TNC_Result receive_msg(private_imv_swima_agent_t *this,
imv_state_t *state, imv_msg_t *in_msg)
{
imv_swima_state_t *swima_state;
imv_msg_t *out_msg;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imv_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
swima_state = (imv_swima_state_t*)state;
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
uint32_t request_id = 0, last_eid, eid_epoch;
swima_inventory_t *inventory;
swima_events_t *events;
pen_type_t type;
type = attr->get_type(attr);
if (type.vendor_id != PEN_IETF)
{
continue;
}
switch (type.type)
{
case IETF_ATTR_PA_TNC_ERROR:
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info, description;
bio_reader_t *reader;
uint32_t max_attr_size;
bool success;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id != PEN_IETF ||
error_code.type <= PA_ERROR_PA_TNC_MSG_ROOF)
{
continue;
}
msg_info = error_attr->get_msg_info(error_attr);
reader = bio_reader_create(msg_info);
success = reader->read_uint32(reader, &request_id);
DBG1(DBG_IMV, "received PA-TNC error '%N' for request %d",
pa_tnc_error_code_names, error_code.type, request_id);
if (!success)
{
reader->destroy(reader);
continue;
}
if (error_code.type == PA_ERROR_SW_RESPONSE_TOO_LARGE)
{
if (!reader->read_uint32(reader, &max_attr_size))
{
reader->destroy(reader);
continue;
}
DBG1(DBG_IMV, " maximum PA-TNC attribute size is %u bytes",
max_attr_size);
}
description = reader->peek(reader);
if (description.len)
{
DBG1(DBG_IMV, " description: %.*s", description.len,
description.ptr);
}
reader->destroy(reader);
break;
}
case IETF_ATTR_SW_ID_INVENTORY:
{
ietf_swima_attr_sw_inv_t *attr_cast;
uint32_t missing;
int sw_id_count;
state->set_action_flags(state, IMV_SWIMA_ATTR_SW_ID_INV);
attr_cast = (ietf_swima_attr_sw_inv_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
inventory = attr_cast->get_inventory(attr_cast);
last_eid = inventory->get_eid(inventory, &eid_epoch);
sw_id_count = inventory->get_count(inventory);
missing = attr_cast->get_record_count(attr_cast);
swima_state->set_missing(swima_state, missing);
DBG2(DBG_IMV, "received software ID inventory with "
"%d item%s for request %d at last eid %d of epoch 0x%08x, "
"%d item%s to follow", sw_id_count,
(sw_id_count == 1) ? "" : "s", request_id, last_eid,
eid_epoch, missing, (missing == 1) ? "" : "s");
if (request_id == swima_state->get_request_id(swima_state))
{
swima_state->set_inventory(swima_state, inventory);
swima_state->set_count(swima_state, sw_id_count, 0,
in_msg->get_src_id(in_msg));
}
else
{
DBG1(DBG_IMV, "no workitem found for software ID "
"inventory with request ID %d", request_id);
}
attr_cast->clear_inventory(attr_cast);
break;
}
case IETF_ATTR_SW_INVENTORY:
{
ietf_swima_attr_sw_inv_t *attr_cast;
swima_record_t *sw_record;
json_object *jobj, *jarray, *jstring;
pen_type_t data_model;
chunk_t tag;
char *tag_str;
uint32_t missing;
int sw_count;
enumerator_t *e;
state->set_action_flags(state, IMV_SWIMA_ATTR_SW_INV);
attr_cast = (ietf_swima_attr_sw_inv_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
inventory = attr_cast->get_inventory(attr_cast);
last_eid = inventory->get_eid(inventory, &eid_epoch);
sw_count = inventory->get_count(inventory);
missing = attr_cast->get_record_count(attr_cast);
swima_state->set_missing(swima_state, missing);
DBG2(DBG_IMV, "received software inventory with %d item%s for "
"request %d at last eid %d of epoch 0x%08x, %d item%s to "
"follow", sw_count, (sw_count == 1) ? "" : "s", request_id,
last_eid, eid_epoch, missing, (missing == 1) ? "" : "s");
if (request_id == swima_state->get_request_id(swima_state))
{
swima_state->set_count(swima_state, 0, sw_count,
in_msg->get_src_id(in_msg));
if (this->rest_api)
{
jobj = json_object_new_object();
jarray = json_object_new_array();
json_object_object_add(jobj, "data", jarray);
e = inventory->create_enumerator(inventory);
while (e->enumerate(e, &sw_record))
{
tag = sw_record->get_record(sw_record);
DBG3(DBG_IMV, "%.*s", tag.len, tag.ptr);
data_model = sw_record->get_data_model(sw_record);
if (!pen_type_equals(data_model,
swima_data_model_iso_2015_swid_xml))
{
DBG1(DBG_IMV, "only ISO/IEC 19770-2-2015 XML "
"data model supported");
continue;
}
tag_str = strndup(tag.ptr, tag.len);
jstring = json_object_new_string(tag_str);
json_object_array_add(jarray, jstring);
free(tag_str);
}
e->destroy(e);
if (this->rest_api->post(this->rest_api,
"swid/add-tags/", jobj, NULL) != SUCCESS)
{
DBG1(DBG_IMV, "error in REST API add-tags request");
}
json_object_put(jobj);
}
}
else
{
DBG1(DBG_IMV, "no workitem found for SWID tag inventory "
"with request ID %d", request_id);
}
attr_cast->clear_inventory(attr_cast);
break;
}
case IETF_ATTR_SW_ID_EVENTS:
{
ietf_swima_attr_sw_ev_t *attr_cast;
uint32_t missing;
int sw_ev_count;
state->set_action_flags(state, IMV_SWIMA_ATTR_SW_ID_EV);
attr_cast = (ietf_swima_attr_sw_ev_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
events = attr_cast->get_events(attr_cast);
last_eid = events->get_eid(events, &eid_epoch, NULL);
sw_ev_count = events->get_count(events);
missing = attr_cast->get_event_count(attr_cast);
swima_state->set_missing(swima_state, missing);
DBG2(DBG_IMV, "received software ID events with "
"%d item%s for request %d at last eid %d of epoch 0x%08x, "
"%d item%s to follow", sw_ev_count,
(sw_ev_count == 1) ? "" : "s", request_id, last_eid,
eid_epoch, missing, (missing == 1) ? "" : "s");
if (request_id == swima_state->get_request_id(swima_state))
{
swima_state->set_events(swima_state, events);
swima_state->set_count(swima_state, sw_ev_count, 0,
in_msg->get_src_id(in_msg));
}
else
{
DBG1(DBG_IMV, "no workitem found for software ID events "
"with request ID %d", request_id);
}
attr_cast->clear_events(attr_cast);
break;
}
default:
break;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
result = out_msg->send_assessment(out_msg);
if (result == TNC_RESULT_SUCCESS)
{
result = this->agent->provide_recommendation(this->agent, state);
}
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message, TNC_Result,
private_imv_swima_agent_t *this, TNC_ConnectionID id,
TNC_MessageType msg_type, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
private_imv_swima_agent_t *this, TNC_ConnectionID id,
TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_long_data(this->agent, state, id,
src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, batch_ending, TNC_Result,
private_imv_swima_agent_t *this, TNC_ConnectionID id)
{
imv_msg_t *out_msg;
imv_state_t *state;
imv_session_t *session;
imv_workitem_t *workitem;
imv_swima_state_t *swima_state;
imv_swima_handshake_state_t handshake_state;
pa_tnc_attr_t *attr;
TNC_IMVID imv_id;
TNC_Result result = TNC_RESULT_SUCCESS;
bool no_workitems = TRUE;
uint32_t request_id, received;
uint8_t flags;
enumerator_t *enumerator;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
swima_state = (imv_swima_state_t*)state;
handshake_state = swima_state->get_handshake_state(swima_state);
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
if (handshake_state == IMV_SWIMA_STATE_END)
{
return TNC_RESULT_SUCCESS;
}
/* Create an empty out message - we might need it */
out_msg = imv_msg_create(this->agent, state, id, imv_id,
swima_state->get_imc_id(swima_state),
msg_types[0]);
if (!imcv_db)
{
DBG2(DBG_IMV, "no workitems available - no evaluation possible");
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
swima_state->set_handshake_state(swima_state, IMV_SWIMA_STATE_END);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* Look for SWID tag workitem and create SWID tag request */
if (handshake_state == IMV_SWIMA_STATE_INIT &&
session->get_policy_started(session))
{
size_t max_attr_size = SWIMA_MAX_ATTR_SIZE;
size_t max_seg_size;
ietf_swima_attr_req_t *cast_attr;
seg_contract_t *contract;
seg_contract_manager_t *contracts;
swima_inventory_t *targets;
uint32_t earliest_eid = 0;
char buf[BUF_LEN];
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY ||
workitem->get_type(workitem) != IMV_WORKITEM_SWID_TAGS)
{
continue;
}
flags = IETF_SWIMA_ATTR_REQ_FLAG_NONE;
if (strchr(workitem->get_arg_str(workitem), 'R'))
{
flags |= IETF_SWIMA_ATTR_REQ_FLAG_R;
}
if (strchr(workitem->get_arg_str(workitem), 'S'))
{
flags |= IETF_SWIMA_ATTR_REQ_FLAG_S;
}
if (strchr(workitem->get_arg_str(workitem), 'C'))
{
flags |= IETF_SWIMA_ATTR_REQ_FLAG_C;
}
earliest_eid = workitem->get_arg_int(workitem);
/* Determine maximum PA-TNC attribute segment size */
max_seg_size = state->get_max_msg_len(state)
- PA_TNC_HEADER_SIZE
- PA_TNC_ATTR_HEADER_SIZE
- TCG_SEG_ATTR_SEG_ENV_HEADER;
/* Announce support of PA-TNC segmentation to IMC */
contract = seg_contract_create(msg_types[0], max_attr_size,
max_seg_size, TRUE, imv_id, FALSE);
contract->get_info_string(contract, buf, BUF_LEN, TRUE);
DBG2(DBG_IMV, "%s", buf);
contracts = state->get_contracts(state);
contracts->add_contract(contracts, contract);
attr = tcg_seg_attr_max_size_create(max_attr_size,
max_seg_size, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Issue a SWID request */
request_id = workitem->get_id(workitem);
swima_state->set_request_id(swima_state, request_id);
attr = ietf_swima_attr_req_create(flags, request_id);
/* Request software identifier events */
targets = swima_inventory_create();
targets->set_eid(targets, earliest_eid, 0);
cast_attr = (ietf_swima_attr_req_t*)attr;
cast_attr->set_targets(cast_attr, targets);
targets->destroy(targets);
out_msg->add_attribute(out_msg, attr);
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
DBG2(DBG_IMV, "IMV %d issues sw request %d with earliest eid %d",
imv_id, request_id, earliest_eid);
break;
}
enumerator->destroy(enumerator);
if (no_workitems)
{
DBG2(DBG_IMV, "IMV %d has no workitems - "
"no evaluation requested", imv_id);
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
}
handshake_state = IMV_SWIMA_STATE_WORKITEMS;
swima_state->set_handshake_state(swima_state, handshake_state);
}
}
received = state->get_action_flags(state);
if (handshake_state == IMV_SWIMA_STATE_WORKITEMS &&
(received & (IMV_SWIMA_ATTR_SW_INV|IMV_SWIMA_ATTR_SW_ID_INV|
IMV_SWIMA_ATTR_SW_EV |IMV_SWIMA_ATTR_SW_ID_EV)) &&
swima_state->get_missing(swima_state) == 0)
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
char result_str[BUF_LEN], *format = NULL, *cmd = NULL, *command;
char *target_str, *error_str = "";
int sw_id_count, tag_count, i, res;
json_object *jrequest, *jresponse, *jvalue;
ietf_swima_attr_req_t *cast_attr;
swima_inventory_t *targets;
swima_record_t *target;
status_t status = SUCCESS;
if (received & IMV_SWIMA_ATTR_SW_ID_INV)
{
cmd = "swid-measurement";
format = "received inventory of %d SW ID%s and %d SWID tag%s";
}
else if (received & IMV_SWIMA_ATTR_SW_ID_EV)
{
cmd = "swid-events";
format = "received %d SW ID event%s and %d SWID tag%s";
}
if (cmd && this->rest_api)
{
res = asprintf(&command, "sessions/%d/%s/",
session->get_session_id(session, NULL, NULL), cmd);
if (res < 0)
{
error_str = "allocation of command string failed";
status = FAILED;
}
else
{
jrequest = swima_state->get_jrequest(swima_state);
status = this->rest_api->post(this->rest_api, command,
jrequest, &jresponse);
if (status == FAILED)
{
error_str = "error in REST API request";
}
free(command);
}
}
switch (status)
{
case SUCCESS:
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
{
swima_state->get_count(swima_state, &sw_id_count,
&tag_count);
if (format)
{
snprintf(result_str, BUF_LEN, format,
sw_id_count, (sw_id_count == 1) ? "" : "s",
tag_count, (tag_count == 1) ? "" : "s");
}
else
{
snprintf(result_str, BUF_LEN, "received %d SWID tag"
"%s", tag_count, (tag_count == 1) ? "" : "s");
}
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
break;
}
}
enumerator->destroy(enumerator);
break;
case NEED_MORE:
if (received & IMV_SWIMA_ATTR_SW_INV)
{
error_str = "not all requested SWID tags were received";
status = FAILED;
json_object_put(jresponse);
break;
}
if (json_object_get_type(jresponse) != json_type_array)
{
error_str = "response was not a json_array";
status = FAILED;
json_object_put(jresponse);
break;
}
/* Create an IETF SW Request attribute */
attr = ietf_swima_attr_req_create(IETF_SWIMA_ATTR_REQ_FLAG_NONE,
swima_state->get_request_id(swima_state));
sw_id_count = json_object_array_length(jresponse);
DBG1(DBG_IMV, "%d SWID tag target%s", sw_id_count,
(sw_id_count == 1) ? "" : "s");
swima_state->set_missing(swima_state, sw_id_count);
targets = swima_inventory_create();
for (i = 0; i < sw_id_count; i++)
{
jvalue = json_object_array_get_idx(jresponse, i);
if (json_object_get_type(jvalue) != json_type_string)
{
error_str = "json_string element expected in json_array";
status = FAILED;
json_object_put(jresponse);
break;
}
target_str = (char*)json_object_get_string(jvalue);
DBG1(DBG_IMV, " %s", target_str);
target = swima_record_create(0, chunk_from_str(target_str),
chunk_empty);
targets->add(targets, target);
}
json_object_put(jresponse);
cast_attr = (ietf_swima_attr_req_t*)attr;
cast_attr->set_targets(cast_attr, targets);
targets->destroy(targets);
out_msg->add_attribute(out_msg, attr);
break;
case FAILED:
default:
break;
}
if (status == FAILED)
{
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
{
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
rec = workitem->set_result(workitem, error_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
break;
}
}
enumerator->destroy(enumerator);
}
}
/* finalized all workitems ? */
if (handshake_state == IMV_SWIMA_STATE_WORKITEMS &&
session->get_workitem_count(session, imv_id) == 0)
{
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
swima_state->set_handshake_state(swima_state, IMV_SWIMA_STATE_END);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* send non-empty PA-TNC message with excl flag not set */
if (out_msg->get_attribute_count(out_msg))
{
result = out_msg->send(out_msg, FALSE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
private_imv_swima_agent_t *this, TNC_ConnectionID id)
{
imv_state_t *state;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
return this->agent->provide_recommendation(this->agent, state);
}
METHOD(imv_agent_if_t, destroy, void,
private_imv_swima_agent_t *this)
{
DESTROY_IF(this->rest_api);
this->agent->destroy(this->agent);
free(this);
}
/**
* Described in header.
*/
imv_agent_if_t *imv_swima_agent_create(const char *name, TNC_IMVID id,
TNC_Version *actual_version)
{
private_imv_swima_agent_t *this;
imv_agent_t *agent;
char *uri;
u_int timeout;
agent = imv_agent_create(name, msg_types, countof(msg_types), id,
actual_version);
if (!agent)
{
return NULL;
}
agent->add_non_fatal_attr_type(agent,
pen_type_create(PEN_TCG, TCG_SEG_MAX_ATTR_SIZE_REQ));
INIT(this,
.public = {
.bind_functions = _bind_functions,
.notify_connection_change = _notify_connection_change,
.receive_message = _receive_message,
.receive_message_long = _receive_message_long,
.batch_ending = _batch_ending,
.solicit_recommendation = _solicit_recommendation,
.destroy = _destroy,
},
.agent = agent,
);
uri = lib->settings->get_str(lib->settings,
"%s.plugins.imv-swima.rest_api.uri", NULL, lib->ns);
timeout = lib->settings->get_int(lib->settings,
"%s.plugins.imv-swima.rest_api.timeout", 120, lib->ns);
if (uri)
{
this->rest_api = rest_create(uri, timeout);
}
return &this->public;
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 imv_swima_agent_t imv_swima_agent
* @{ @ingroup imv_swima
*/
#ifndef IMV_SWIMA_AGENT_H_
#define IMV_SWIMA_AGENT_H_
#include <imv/imv_agent_if.h>
/**
* Creates an SWID IMV agent
*
* @param name Name of the IMV
* @param id ID of the IMV
* @param actual_version TNC IF-IMV version
*/
imv_agent_if_t* imv_swima_agent_create(const char* name, TNC_IMVID id,
TNC_Version *actual_version);
#endif /** IMV_SWIMA_AGENT_H_ @}*/
@@ -0,0 +1,483 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "imv_swima_state.h"
#include <imv/imv_lang_string.h>
#include <imv/imv_reason_string.h>
#include <imv/imv_remediation_string.h>
#include <tncif_policy.h>
#include <utils/debug.h>
typedef struct private_imv_swima_state_t private_imv_swima_state_t;
/**
* Private data of an imv_swima_state_t object.
*/
struct private_imv_swima_state_t {
/**
* Public members of imv_swima_state_t
*/
imv_swima_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
uint32_t max_msg_len;
/**
* Flags set for completed actions
*/
uint32_t action_flags;
/**
* IMV database session associated with TNCCS connection
*/
imv_session_t *session;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
/**
* IMV evaluation result
*/
TNC_IMV_Evaluation_Result eval;
/**
* IMV Scanner handshake state
*/
imv_swima_handshake_state_t handshake_state;
/**
* TNC Reason String
*/
imv_reason_string_t *reason_string;
/**
* IETF Remediation Instructions String
*/
imv_remediation_string_t *remediation_string;
/**
* SWID Tag Request ID
*/
uint32_t request_id;
/**
* Number of processed Software Identifiers
*/
int sw_id_count;
/**
* Number of processed SWID Tags
*/
int tag_count;
/**
* Number of missing Software Identifiers or SWID Tags
*/
uint32_t missing;
/**
* SWID IMC ID
*/
TNC_UInt32 imc_id;
/**
* Top level JSON object
*/
json_object *jobj;
/**
* JSON array containing either a SW [ID] inventory or SW ID events
*/
json_object *jarray;
};
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
private_imv_swima_state_t *this)
{
return this->connection_id;
}
METHOD(imv_state_t, has_long, bool,
private_imv_swima_state_t *this)
{
return this->has_long;
}
METHOD(imv_state_t, has_excl, bool,
private_imv_swima_state_t *this)
{
return this->has_excl;
}
METHOD(imv_state_t, set_flags, void,
private_imv_swima_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imv_state_t, set_max_msg_len, void,
private_imv_swima_state_t *this, uint32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imv_state_t, get_max_msg_len, uint32_t,
private_imv_swima_state_t *this)
{
return this->max_msg_len;
}
METHOD(imv_state_t, set_action_flags, void,
private_imv_swima_state_t *this, uint32_t flags)
{
this->action_flags |= flags;
}
METHOD(imv_state_t, get_action_flags, uint32_t,
private_imv_swima_state_t *this)
{
return this->action_flags;
}
METHOD(imv_state_t, set_session, void,
private_imv_swima_state_t *this, imv_session_t *session)
{
this->session = session;
}
METHOD(imv_state_t, get_session, imv_session_t*,
private_imv_swima_state_t *this)
{
return this->session;
}
METHOD(imv_state_t, get_contracts, seg_contract_manager_t*,
private_imv_swima_state_t *this)
{
return this->contracts;
}
METHOD(imv_state_t, change_state, void,
private_imv_swima_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imv_state_t, get_recommendation, void,
private_imv_swima_state_t *this, TNC_IMV_Action_Recommendation *rec,
TNC_IMV_Evaluation_Result *eval)
{
*rec = this->rec;
*eval = this->eval;
}
METHOD(imv_state_t, set_recommendation, void,
private_imv_swima_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = rec;
this->eval = eval;
}
METHOD(imv_state_t, update_recommendation, void,
private_imv_swima_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = tncif_policy_update_recommendation(this->rec, rec);
this->eval = tncif_policy_update_evaluation(this->eval, eval);
}
METHOD(imv_state_t, get_reason_string, bool,
private_imv_swima_state_t *this, enumerator_t *language_enumerator,
chunk_t *reason_string, char **reason_language)
{
return FALSE;
}
METHOD(imv_state_t, get_remediation_instructions, bool,
private_imv_swima_state_t *this, enumerator_t *language_enumerator,
chunk_t *string, char **lang_code, char **uri)
{
return FALSE;
}
METHOD(imv_state_t, destroy, void,
private_imv_swima_state_t *this)
{
json_object_put(this->jobj);
DESTROY_IF(this->session);
DESTROY_IF(this->reason_string);
DESTROY_IF(this->remediation_string);
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imv_swima_state_t, set_handshake_state, void,
private_imv_swima_state_t *this, imv_swima_handshake_state_t new_state)
{
this->handshake_state = new_state;
}
METHOD(imv_swima_state_t, get_handshake_state, imv_swima_handshake_state_t,
private_imv_swima_state_t *this)
{
return this->handshake_state;
}
METHOD(imv_swima_state_t, set_request_id, void,
private_imv_swima_state_t *this, uint32_t request_id)
{
this->request_id = request_id;
}
METHOD(imv_swima_state_t, get_request_id, uint32_t,
private_imv_swima_state_t *this)
{
return this->request_id;
}
METHOD(imv_swima_state_t, set_inventory, void,
private_imv_swima_state_t *this, swima_inventory_t *inventory)
{
chunk_t sw_id, sw_locator;
uint32_t record_id;
char *sw_id_str;
json_object *jstring;
swima_record_t *sw_record;
enumerator_t *enumerator;
if (this->sw_id_count == 0)
{
this->jarray = json_object_new_array();
json_object_object_add(this->jobj, "data", this->jarray);
}
enumerator = inventory->create_enumerator(inventory);
while (enumerator->enumerate(enumerator, &sw_record))
{
record_id = sw_record->get_record_id(sw_record);
sw_id = sw_record->get_sw_id(sw_record, &sw_locator);
sw_id_str = strndup(sw_id.ptr, sw_id.len);
if (sw_locator.len)
{
DBG3(DBG_IMV, "%6u: %s @ %.*s", record_id, sw_id_str,
sw_locator.len, sw_locator.ptr);
}
else
{
DBG3(DBG_IMV, "%6u: %s", record_id, sw_id_str);
}
/* Add software identity to JSON array */
jstring = json_object_new_string(sw_id_str);
json_object_array_add(this->jarray, jstring);
free(sw_id_str);
}
enumerator->destroy(enumerator);
}
METHOD(imv_swima_state_t, set_events, void,
private_imv_swima_state_t *this, swima_events_t *events)
{
chunk_t sw_id, timestamp;
uint32_t record_id, eid, last_eid, epoch, source_id, action;
char *sw_id_str, *timestamp_str;
json_object *jevent, *jvalue, *jstring;
swima_event_t *sw_event;
swima_record_t *sw_record;
enumerator_t *enumerator;
if (this->sw_id_count == 0)
{
last_eid = events->get_eid(events, &epoch, NULL);
jvalue = json_object_new_int(epoch);
json_object_object_add(this->jobj, "epoch", jvalue);
jvalue = json_object_new_int(last_eid);
json_object_object_add(this->jobj, "lastEid", jvalue);
this->jarray = json_object_new_array();
json_object_object_add(this->jobj, "events", this->jarray);
}
enumerator = events->create_enumerator(events);
while (enumerator->enumerate(enumerator, &sw_event))
{
eid = sw_event->get_eid(sw_event, &timestamp);
timestamp_str = strndup(timestamp.ptr, timestamp.len);
action = sw_event->get_action(sw_event);
sw_record = sw_event->get_sw_record(sw_event);
record_id = sw_record->get_record_id(sw_record);
source_id = sw_record->get_source_id(sw_record);
sw_id = sw_record->get_sw_id(sw_record, NULL);
sw_id_str = strndup(sw_id.ptr, sw_id.len);
DBG3(DBG_IMV, "%3u %.*s %u %5u: %s", eid, timestamp.len, timestamp.ptr,
action, record_id, sw_id_str);
/* Add software event to JSON array */
jevent = json_object_new_object();
jvalue = json_object_new_int(eid);
json_object_object_add(jevent, "eid", jvalue);
jstring = json_object_new_string(timestamp_str);
json_object_object_add(jevent, "timestamp", jstring);
jvalue = json_object_new_int(record_id);
json_object_object_add(jevent, "recordId", jvalue);
jvalue = json_object_new_int(source_id);
json_object_object_add(jevent, "sourceId", jvalue);
jvalue = json_object_new_int(action);
json_object_object_add(jevent, "action", jvalue);
jstring = json_object_new_string(sw_id_str);
json_object_object_add(jevent, "softwareId", jstring);
json_object_array_add(this->jarray, jevent);
free(timestamp_str);
free(sw_id_str);
}
enumerator->destroy(enumerator);
}
METHOD(imv_swima_state_t, get_jrequest, json_object*,
private_imv_swima_state_t *this)
{
return this->jobj;
}
METHOD(imv_swima_state_t, set_missing, void,
private_imv_swima_state_t *this, uint32_t count)
{
this->missing = count;
}
METHOD(imv_swima_state_t, get_missing, uint32_t,
private_imv_swima_state_t *this)
{
return this->missing;
}
METHOD(imv_swima_state_t, set_count, void,
private_imv_swima_state_t *this, int sw_id_count, int tag_count,
TNC_UInt32 imc_id)
{
this->sw_id_count += sw_id_count;
this->tag_count += tag_count;
this->imc_id = imc_id;
}
METHOD(imv_swima_state_t, get_count, void,
private_imv_swima_state_t *this, int *sw_id_count, int *tag_count)
{
if (sw_id_count)
{
*sw_id_count = this->sw_id_count;
}
if (tag_count)
{
*tag_count = this->tag_count;
}
}
METHOD(imv_swima_state_t, get_imc_id, TNC_UInt32,
private_imv_swima_state_t *this)
{
return this->imc_id;
}
/**
* Described in header.
*/
imv_state_t *imv_swima_state_create(TNC_ConnectionID connection_id)
{
private_imv_swima_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.set_action_flags = _set_action_flags,
.get_action_flags = _get_action_flags,
.set_session = _set_session,
.get_session= _get_session,
.get_contracts = _get_contracts,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
.update_recommendation = _update_recommendation,
.get_reason_string = _get_reason_string,
.get_remediation_instructions = _get_remediation_instructions,
.destroy = _destroy,
},
.set_handshake_state = _set_handshake_state,
.get_handshake_state = _get_handshake_state,
.set_request_id = _set_request_id,
.get_request_id = _get_request_id,
.set_inventory = _set_inventory,
.set_events = _set_events,
.get_jrequest = _get_jrequest,
.set_missing = _set_missing,
.get_missing = _get_missing,
.set_count = _set_count,
.get_count = _get_count,
.get_imc_id = _get_imc_id,
},
.state = TNC_CONNECTION_STATE_CREATE,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.contracts = seg_contract_manager_create(),
.imc_id = TNC_IMCID_ANY,
.jobj = json_object_new_object(),
);
return &this->public.interface;
}
@@ -0,0 +1,153 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 imv_swima imv_swima
* @ingroup libimcv_plugins
*
* @defgroup imv_swima_state_t imv_swima_state
* @{ @ingroup imv_swima
*/
#ifndef IMV_SWIMA_STATE_H_
#define IMV_SWIMA_STATE_H_
#include <imv/imv_state.h>
#include <swima/swima_inventory.h>
#include <swima/swima_events.h>
#include <library.h>
#include <json.h>
typedef struct imv_swima_state_t imv_swima_state_t;
typedef enum imv_swima_handshake_state_t imv_swima_handshake_state_t;
/**
* IMV OS Handshake States (state machine)
*/
enum imv_swima_handshake_state_t {
IMV_SWIMA_STATE_INIT,
IMV_SWIMA_STATE_WORKITEMS,
IMV_SWIMA_STATE_END
};
/**
* Internal state of an imv_swima_t connection instance
*/
struct imv_swima_state_t {
/**
* imv_state_t interface
*/
imv_state_t interface;
/**
* Set state of the handshake
*
* @param new_state the handshake state of IMV
*/
void (*set_handshake_state)(imv_swima_state_t *this,
imv_swima_handshake_state_t new_state);
/**
* Get state of the handshake
*
* @return the handshake state of IMV
*/
imv_swima_handshake_state_t (*get_handshake_state)(imv_swima_state_t *this);
/**
* Set the SWID request ID
*
* @param request_id SWID request ID to be set
*/
void (*set_request_id)(imv_swima_state_t *this, uint32_t request_id);
/**
* Get the SWID request ID
*
* @return SWID request ID
*/
uint32_t (*get_request_id)(imv_swima_state_t *this);
/**
* Set or extend the SW ID inventory in the state
*
* @param inventory SW ID inventory to be added
*/
void (*set_inventory)(imv_swima_state_t *this, swima_inventory_t *inventory);
/**
* Set or extend the SW ID events in the state
*
* @param events SW ID events to be added
*/
void (*set_events)(imv_swima_state_t *this, swima_events_t *events);
/**
* Get the JSON encoding of the complete SW ID inventory or SW ID events
*
* @return JSON encoding
*/
json_object* (*get_jrequest)(imv_swima_state_t *this);
/**
* Set the number of still missing SW [ID] records or envents
*
* @param count Number of missing SW [ID] records or envents
*/
void (*set_missing)(imv_swima_state_t *this, uint32_t count);
/**
* Get the number of still missing SWID Tags or Tag IDs
*
* @result Number of missing SWID Tags or Tag IDs
*/
uint32_t (*get_missing)(imv_swima_state_t *this);
/**
* Set [or with multiple attributes increment] SWID Tag [ID] counters
*
* @param tag_id_count Number of received SWID Tag IDs
* @param tag_count Number of received SWID Tags
* @param imc_id SWID IMC ID
*/
void (*set_count)(imv_swima_state_t *this, int tag_id_count, int tag_count,
TNC_UInt32 imc_id);
/**
* Set [or with multiple attributes increment] SWID Tag [ID] counters
*
* @param tag_id_count Number of received SWID Tag IDs
* @param tag_count Number of received SWID Tags
*/
void (*get_count)(imv_swima_state_t *this, int *tag_id_count, int *tag_count);
/**
* Get SWID IMC ID
*
* @return SWID IMC ID
*/
TNC_UInt32 (*get_imc_id)(imv_swima_state_t *this);
};
/**
* Create an imv_swima_state_t instance
*
* @param id connection ID
*/
imv_state_t* imv_swima_state_create(TNC_ConnectionID id);
#endif /** IMV_SWIMA_STATE_H_ @}*/
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -667,7 +667,8 @@ METHOD(pts_component_t, verify, status_t,
case IMA_STATE_RUNTIME:
{
uint8_t hash_buf[HASH_SIZE_SHA512];
chunk_t digest, hash;
uint8_t digest_buf[HASH_SIZE_SHA512], *hex_digest_buf;
chunk_t hex_digest, digest, hash;
enumerator_t *e;
this->count++;
@@ -685,8 +686,10 @@ METHOD(pts_component_t, verify, status_t,
hash_algo, ima_name);
if (e)
{
while (e->enumerate(e, &digest))
while (e->enumerate(e, &hex_digest_buf))
{
hex_digest = chunk_from_str(hex_digest_buf);
digest = chunk_from_hex(hex_digest, digest_buf);
if (!ima_hash(digest, ima_algo, ima_name,
FALSE, algo, hash_buf))
{
+17 -10
View File
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2012-2014 Andreas Steffen
* Copyright (C) 2012-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -104,17 +104,19 @@ METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
"SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"JOIN directories as d ON d.id = f.dir "
"WHERE fh.product = ? AND fh.algo = ? AND d.id = ? "
"JOIN versions as v ON v.id = fh.version "
"WHERE v.product = ? AND fh.algo = ? AND d.id = ? "
"ORDER BY f.name",
DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB);
DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_TEXT);
}
else
{
e = this->db->query(this->db,
"SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?",
DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB);
"JOIN versions AS v ON v.id = fh.version "
"WHERE v.product = ? AND fh.algo = ? AND fh.file = ?",
DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_TEXT);
}
return e;
}
@@ -179,7 +181,8 @@ METHOD(pts_database_t, add_file_measurement, status_t,
/* does hash measurement value already exist? */
e = this->db->query(this->db,
"SELECT fh.id, fh.hash FROM file_hashes AS fh "
"WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?",
"JOIN versions AS v ON v.id = fh.version "
"WHERE v.product = ? AND fh.algo = ? AND fh.file = ?",
DB_INT, pid, DB_INT, algo, DB_INT, fid, DB_INT, DB_BLOB);
if (!e)
{
@@ -235,8 +238,10 @@ METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
e = this->db->query(this->db,
"SELECT fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"WHERE fh.product = ? AND f.name = ? AND fh.algo = ?",
DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_BLOB);
"JOIN versions AS v ON v.id = fh.version "
"WHERE v.product = ? AND f.name = ? AND fh.algo = ? "
"ORDER BY v.time DESC",
DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_TEXT);
}
else
{ /* absolute pathname */
@@ -256,8 +261,10 @@ METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
e = this->db->query(this->db,
"SELECT fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"WHERE fh.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ?",
DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_BLOB);
"JOIN versions AS v ON v.id = fh.version "
"WHERE v.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ? "
"ORDER BY v.time DESC",
DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_TEXT);
}
err:
+167
View File
@@ -0,0 +1,167 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#ifdef USE_JSON
#define _GNU_SOURCE
#include <stdio.h>
#include "rest.h"
typedef struct private_rest_t private_rest_t;
/**
* Private data of an rest_t object.
*/
struct private_rest_t {
/**
* Public members of rest_t
*/
rest_t public;
/**
* URI of REST API
*/
char *uri;
/**
* Timeout of REST API connection
*/
u_int timeout;
};
METHOD(rest_t, get, status_t,
private_rest_t *this, char *command, json_object **jresponse)
{
struct json_tokener *tokener;
chunk_t response = chunk_empty;
status_t status;
char *uri;
if (asprintf(&uri, "%s%s",this->uri, command) < 0)
{
return FAILED;
}
status = lib->fetcher->fetch(lib->fetcher, uri, &response,
FETCH_TIMEOUT, this->timeout,
FETCH_END);
free(uri);
if (status == SUCCESS && jresponse)
{
/* Parse HTTP response into a JSON object */
tokener = json_tokener_new();
*jresponse = json_tokener_parse_ex(tokener, response.ptr, response.len);
json_tokener_free(tokener);
}
free(response.ptr);
return status;
}
#define HTTP_STATUS_CODE_NOT_FOUND 404
#define HTTP_STATUS_CODE_PRECONDITION_FAILED 412
METHOD(rest_t, post, status_t,
private_rest_t *this, char *command, json_object *jrequest,
json_object **jresponse)
{
struct json_tokener *tokener;
chunk_t data, response = chunk_empty;
status_t status;
char *uri;
int code;
if (asprintf(&uri, "%s%s",this->uri, command) < 0)
{
return FAILED;
}
data = chunk_from_str((char*)json_object_to_json_string(jrequest));
status = lib->fetcher->fetch(lib->fetcher, uri, &response,
FETCH_TIMEOUT, this->timeout,
FETCH_REQUEST_DATA, data,
FETCH_REQUEST_TYPE, "application/json; charset=utf-8",
FETCH_REQUEST_HEADER, "Accept: application/json",
FETCH_REQUEST_HEADER, "Expect:",
FETCH_RESPONSE_CODE, &code,
FETCH_END);
free(uri);
if (status != SUCCESS)
{
switch (code)
{
case HTTP_STATUS_CODE_NOT_FOUND:
status = NOT_FOUND;
break;
case HTTP_STATUS_CODE_PRECONDITION_FAILED:
if (!response.ptr)
{
return FAILED;
}
if (jresponse)
{
/* Parse HTTP response into a JSON object */
tokener = json_tokener_new();
*jresponse = json_tokener_parse_ex(tokener, response.ptr,
response.len);
json_tokener_free(tokener);
}
status = NEED_MORE;
break;
default:
DBG2(DBG_IMV, "REST http request failed with status code: %d",
code);
status = FAILED;
break;
}
}
free(response.ptr);
return status;
}
METHOD(rest_t, destroy, void,
private_rest_t *this)
{
free(this->uri);
free(this);
}
/**
* Described in header.
*/
rest_t *rest_create(char *uri, u_int timeout)
{
private_rest_t *this;
INIT(this,
.public = {
.get = _get,
.post = _post,
.destroy = _destroy,
},
.uri = strdup(uri),
.timeout = timeout,
);
return &this->public;
}
#endif /* USE_JSON */
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* Copyright (C) 2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,50 +14,61 @@
*/
/**
* @defgroup imv_swid imv_swid
* @defgroup imv_swima imv_swima
* @ingroup libimcv_plugins
*
* @defgroup imv_swid_rest_t imv_swid_rest
* @{ @ingroup imv_swid
* @defgroup rest_t rest
* @{ @ingroup imv_swima
*/
#ifndef IMV_SWID_REST_H_
#define IMV_SWID_REST_H_
#ifndef REST_H_
#define REST_H_
#ifdef USE_JSON
#include <library.h>
#include <json.h>
typedef struct imv_swid_rest_t imv_swid_rest_t;
typedef struct rest_t rest_t;
/**
* Public REST interface
*/
struct imv_swid_rest_t {
struct rest_t {
/**
* Post a HTTP request including a JSON object
* Send an HTTP GET request returning a JSON object
*
* @param jresp JSON object in HTTP
* @return Status (SUCCESS or FAILED)
*/
status_t (*get)(rest_t *this, char *command, json_object **jresp);
/**
* Send an HTTP POST request including a JSON object
*
* @param jreq JSON object in HTTP request
* @param jresp JSON object in HTTP response if NEED_MORE
* @return Status (SUCCESS, NEED_MORE or FAILED)
*/
status_t (*post)(imv_swid_rest_t *this, char *command, json_object *jreq,
status_t (*post)(rest_t *this, char *command, json_object *jreq,
json_object **jresp);
/**
* Destroy imv_swid_rest_t object
* Destroy rest_t object
*/
void (*destroy)(imv_swid_rest_t *this);
void (*destroy)(rest_t *this);
};
/**
* Create an imv_swid_rest_t instance
* Create an rest_t instance
*
* @param uri REST URI (http://username:password@hostname[:port]/api/)
* @param timeout Timeout of the REST connection
*/
imv_swid_rest_t* imv_swid_rest_create(char *uri, u_int timeout);
rest_t* rest_create(char *uri, u_int timeout);
#endif /** IMV_SWID_REST_H_ @}*/
#endif /* USE_JSON */
#endif /** REST_H_ @}*/
File diff suppressed because it is too large Load Diff
+32 -52
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* Copyright (C) 2013-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -237,7 +237,7 @@ static status_t generate_tags(private_swid_inventory_t *this, char *generator,
}
static bool collect_tags(private_swid_inventory_t *this, char *pathname,
swid_inventory_t *targets)
swid_inventory_t *targets, bool is_swidtag_dir)
{
char *rel_name, *abs_name;
struct stat st;
@@ -251,72 +251,49 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname,
pathname, strerror(errno));
return FALSE;
}
DBG2(DBG_IMC, "entering %s", pathname);
if (is_swidtag_dir)
{
DBG2(DBG_IMC, "entering %s", pathname);
}
while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
{
char * start, *stop;
char *separator, *suffix;
chunk_t tag_creator;
chunk_t unique_sw_id = chunk_empty, tag_file_path = chunk_empty;
if (!strstr(rel_name, "regid."))
{
continue;
}
if (S_ISDIR(st.st_mode))
{
/* In case of a targeted request */
if (targets->get_count(targets))
{
enumerator_t *target_enumerator;
swid_tag_id_t *tag_id;
bool match = FALSE;
target_enumerator = targets->create_enumerator(targets);
while (target_enumerator->enumerate(target_enumerator, &tag_id))
{
if (chunk_equals(tag_id->get_tag_creator(tag_id),
chunk_from_str(rel_name)))
{
match = TRUE;
break;
}
}
target_enumerator->destroy(target_enumerator);
if (!match)
{
continue;
}
}
if (!collect_tags(this, abs_name, targets))
if (!collect_tags(this, abs_name, targets, is_swidtag_dir ||
streq(rel_name, "swidtag")))
{
goto end;
}
continue;
}
if (!is_swidtag_dir)
{
continue;
}
/* parse the regid filename into its components */
start = rel_name;
stop = strchr(start, '_');
if (!stop)
/* found a swidtag file? */
suffix = strstr(rel_name, ".swidtag");
if (!suffix)
{
continue;
}
/* parse the swidtag filename into its components */
separator = strchr(rel_name, '_');
if (!separator)
{
DBG1(DBG_IMC, " %s", rel_name);
DBG1(DBG_IMC, " '_' separator not found");
goto end;
}
tag_creator = chunk_create(start, stop-start);
start = stop + 1;
tag_creator = chunk_create(rel_name, separator-rel_name);
stop = strstr(start, ".swidtag");
if (!stop)
{
DBG1(DBG_IMC, " %s", rel_name);
DBG1(DBG_IMC, " swidtag postfix not found");
goto end;
}
unique_sw_id = chunk_create(start, stop-start);
unique_sw_id = chunk_create(separator+1, suffix-separator-1);
tag_file_path = chunk_from_str(abs_name);
/* In case of a targeted request */
@@ -334,7 +311,7 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname,
target_tag_creator = tag_id->get_tag_creator(tag_id);
if (chunk_equals(target_unique_sw_id, unique_sw_id) &&
chunk_equals(target_tag_creator, tag_creator))
chunk_equals(target_tag_creator, tag_creator))
{
match = TRUE;
break;
@@ -358,7 +335,7 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname,
if (!xml_tag)
{
DBG1(DBG_IMC, " opening '%s' failed: %s", abs_name,
strerror(errno));
strerror(errno));
goto end;
}
@@ -378,7 +355,10 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname,
end:
enumerator->destroy(enumerator);
DBG2(DBG_IMC, "leaving %s", pathname);
if (is_swidtag_dir)
{
DBG2(DBG_IMC, "leaving %s", pathname);
}
return success;
}
@@ -396,7 +376,7 @@ METHOD(swid_inventory_t, collect, bool,
* Collect swidtag files by iteratively entering all directories in
* the tree under the "directory" path.
*/
return collect_tags(this, directory, targets);
return collect_tags(this, directory, targets, FALSE);
}
METHOD(swid_inventory_t, add, void,
+647
View File
@@ -0,0 +1,647 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima_collector.h"
#include <collections/linked_list.h>
#include <bio/bio_writer.h>
#include <utils/debug.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <libgen.h>
#include <errno.h>
#define SOURCE_ID_GENERATOR 1
#define SOURCE_ID_COLLECTOR 2
#define SWID_GENERATOR "/usr/local/bin/swid_generator"
/**
* Directories to be skipped by collector
*/
static const char* skip_directories[] = {
"/usr/share/doc",
"/usr/share/help",
"/usr/share/icons",
"/usr/share/gnome/help"
};
typedef struct private_swima_collector_t private_swima_collector_t;
/**
* Private data of a swima_collector_t object.
*
*/
struct private_swima_collector_t {
/**
* Public swima_collector_t interface.
*/
swima_collector_t public;
/**
* Collect Software Identifiers only
*/
bool sw_id_only;
/**
* Software Collector Database [if it exists]
*/
database_t *db;
/**
* List of Software [Identifier] records
*/
swima_inventory_t *inventory;
/**
* List of Software [Identifier] events
*/
swima_events_t *events;
};
/**
* Extract Software Identifier from SWID tag
*/
static status_t extract_sw_id(chunk_t swid_tag, chunk_t *sw_id)
{
char *pos, *tag, *tagid, *regid;
size_t len, tagid_len, regid_len;
status_t status = NOT_FOUND;
/* Copy at most 1023 bytes of the SWID tag and null-terminate it */
len = min(1023, swid_tag.len);
pos = tag = strndup(swid_tag.ptr, len);
tagid= strstr(pos, "tagId=\"");
if (tagid == NULL)
{
goto end;
}
tagid += 7;
len -= tagid - pos - 7;
pos = strchr(tagid, '"');
if (pos == NULL)
{
goto end;
}
tagid_len = pos - tagid;
regid= strstr(pos, "regid=\"");
if (regid == NULL)
{
goto end;
}
regid += 7;
len -= regid - pos - 7;
pos = strchr(regid, '"');
if (pos == NULL)
{
goto end;
}
regid_len = pos - regid;
*sw_id = chunk_cat("ccc", chunk_create(regid, regid_len),
chunk_from_chars('_','_'),
chunk_create(tagid, tagid_len));
status = SUCCESS;
end:
free(tag);
return status;
}
/**
* Read SWID tags issued by the swid_generator tool
*/
static status_t read_swid_tags(private_swima_collector_t *this, FILE *file)
{
swima_record_t *sw_record;
bio_writer_t *writer;
chunk_t sw_id, swid_tag;
bool more_tags = TRUE, last_newline;
char line[8192];
size_t len;
status_t status;
while (more_tags)
{
last_newline = TRUE;
writer = bio_writer_create(512);
while (TRUE)
{
if (!fgets(line, sizeof(line), file))
{
more_tags = FALSE;
break;
}
len = strlen(line);
if (last_newline && line[0] == '\n')
{
break;
}
else
{
last_newline = (line[len-1] == '\n');
writer->write_data(writer, chunk_create(line, len));
}
}
swid_tag = writer->get_buf(writer);
if (swid_tag.len > 1)
{
/* remove trailing newline if present */
if (swid_tag.ptr[swid_tag.len - 1] == '\n')
{
swid_tag.len--;
}
DBG3(DBG_IMC, " %.*s", swid_tag.len, swid_tag.ptr);
status = extract_sw_id(swid_tag, &sw_id);
if (status != SUCCESS)
{
DBG1(DBG_IMC, "software id could not be extracted from tag");
writer->destroy(writer);
return status;
}
sw_record = swima_record_create(0, sw_id, chunk_empty);
sw_record->set_source_id(sw_record, SOURCE_ID_GENERATOR);
sw_record->set_record(sw_record, swid_tag);
this->inventory->add(this->inventory, sw_record);
chunk_free(&sw_id);
}
writer->destroy(writer);
}
return SUCCESS;
}
/**
* Read Software Identifiers issued by the swid_generator tool
*/
static status_t read_swid_tag_ids(private_swima_collector_t *this, FILE *file)
{
swima_record_t *sw_record;
chunk_t sw_id;
char line[BUF_LEN];
size_t len;
while (TRUE)
{
if (!fgets(line, sizeof(line), file))
{
return SUCCESS;
}
len = strlen(line);
/* remove trailing newline if present */
if (len > 0 && line[len - 1] == '\n')
{
len--;
}
DBG3(DBG_IMC, " %.*s", len, line);
sw_id = chunk_create(line, len);
sw_record = swima_record_create(0, sw_id, chunk_empty);
sw_record->set_source_id(sw_record, SOURCE_ID_GENERATOR);
this->inventory->add(this->inventory, sw_record);
}
}
static status_t retrieve_inventory(private_swima_collector_t *this,
swima_inventory_t *targets)
{
char *name;
uint32_t record_id, source;
swima_record_t *sw_record;
chunk_t sw_id;
enumerator_t *e;
/* Retrieve complete software identifier inventory */
e = this->db->query(this->db,
"SELECT id, name, source FROM sw_identifiers WHERE installed = 1 "
"ORDER BY name ASC", DB_UINT, DB_TEXT, DB_UINT);
if (!e)
{
DBG1(DBG_IMC, "database query for installed sw_identifiers failed");
return FAILED;
}
while (e->enumerate(e, &record_id, &name, &source))
{
sw_id = chunk_from_str(name);
sw_record = swima_record_create(record_id, sw_id, chunk_empty);
sw_record->set_source_id(sw_record, source);
this->inventory->add(this->inventory, sw_record);
}
e->destroy(e);
return SUCCESS;
}
static status_t retrieve_events(private_swima_collector_t *this,
swima_inventory_t *targets)
{
enumerator_t *e;
char *name, *timestamp;
uint32_t record_id, source, action, eid, earliest_eid;
chunk_t sw_id, ev_ts;
swima_record_t *sw_record;
swima_event_t *sw_event;
earliest_eid = targets->get_eid(targets, NULL);
/* Retrieve complete software identifier inventory */
e = this->db->query(this->db,
"SELECT e.id, e.timestamp, i.id, i.name, i.source, s.action "
"FROM sw_events as s JOIN events AS e ON s.eid = e.id "
"JOIN sw_identifiers as i ON s.sw_id = i.id WHERE s.eid >= ?"
"ORDER BY s.eid, i.name, s.action ASC", DB_UINT, earliest_eid,
DB_UINT, DB_TEXT, DB_UINT, DB_TEXT, DB_UINT, DB_UINT);
if (!e)
{
DBG1(DBG_IMC, "database query for sw_events failed");
return FAILED;
}
while (e->enumerate(e, &eid, &timestamp, &record_id, &name, &source, &action))
{
sw_id = chunk_from_str(name);
ev_ts = chunk_from_str(timestamp);
sw_record = swima_record_create(record_id, sw_id, chunk_empty);
sw_record->set_source_id(sw_record, source);
sw_event = swima_event_create(eid, ev_ts, action, sw_record);
this->events->add(this->events, sw_event);
}
e->destroy(e);
return SUCCESS;
}
static status_t generate_tags(private_swima_collector_t *this, char *generator,
swima_inventory_t *targets, bool pretty, bool full)
{
FILE *file;
char command[BUF_LEN];
char doc_separator[] = "'\n\n'";
status_t status = SUCCESS;
if (targets->get_count(targets) == 0)
{
/* Assemble the SWID generator command */
if (this->sw_id_only)
{
snprintf(command, BUF_LEN, "%s software-id", generator);
}
else
{
snprintf(command, BUF_LEN, "%s swid --doc-separator %s%s%s",
generator, doc_separator, pretty ? " --pretty" : "",
full ? " --full" : "");
}
/* Open a pipe stream for reading the SWID generator output */
file = popen(command, "r");
if (!file)
{
DBG1(DBG_IMC, "failed to run swid_generator command");
return NOT_SUPPORTED;
}
if (this->sw_id_only)
{
DBG2(DBG_IMC, "SWID tag ID generation by package manager");
status = read_swid_tag_ids(this, file);
}
else
{
DBG2(DBG_IMC, "SWID tag generation by package manager");
status = read_swid_tags(this, file);
}
pclose(file);
}
else if (!this->sw_id_only)
{
swima_record_t *target;
enumerator_t *enumerator;
chunk_t sw_id;
enumerator = targets->create_enumerator(targets);
while (enumerator->enumerate(enumerator, &target))
{
sw_id = target->get_sw_id(target, NULL);
/* Assemble the SWID generator command */
snprintf(command, BUF_LEN, "%s swid --software-id %.*s%s%s",
generator, sw_id.len, sw_id.ptr,
pretty ? " --pretty" : "", full ? " --full" : "");
/* Open a pipe stream for reading the SWID generator output */
file = popen(command, "r");
if (!file)
{
DBG1(DBG_IMC, "failed to run swid_generator command");
return NOT_SUPPORTED;
}
status = read_swid_tags(this, file);
pclose(file);
if (status != SUCCESS)
{
break;
}
}
enumerator->destroy(enumerator);
}
return status;
}
static bool collect_tags(private_swima_collector_t *this, char *pathname,
swima_inventory_t *targets, bool is_swidtag_dir)
{
char *rel_name, *abs_name, *suffix, *pos;
chunk_t *swid_tag, sw_id, sw_locator;
swima_record_t *sw_record;
struct stat st;
bool success = FALSE, skip, is_new_swidtag_dir;
enumerator_t *enumerator;
int i;
enumerator = enumerator_create_directory(pathname);
if (!enumerator)
{
DBG1(DBG_IMC, "directory '%s' can not be opened, %s",
pathname, strerror(errno));
return FALSE;
}
while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
{
if (S_ISDIR(st.st_mode))
{
skip = FALSE;
for (i = 0; i < countof(skip_directories); i++)
{
if (streq(abs_name, skip_directories[i]))
{
skip = TRUE;
break;
}
}
if (skip)
{
continue;
}
is_new_swidtag_dir = streq(rel_name, "swidtag");
if (is_new_swidtag_dir)
{
DBG2(DBG_IMC, "entering %s", pathname);
}
if (!collect_tags(this, abs_name, targets, is_swidtag_dir ||
is_new_swidtag_dir))
{
goto end;
}
if (is_new_swidtag_dir)
{
DBG2(DBG_IMC, "leaving %s", pathname);
}
}
if (!is_swidtag_dir)
{
continue;
}
/* found a swidtag file? */
suffix = strstr(rel_name, ".swidtag");
if (!suffix)
{
continue;
}
/* load the swidtag file */
swid_tag = chunk_map(abs_name, FALSE);
if (!swid_tag)
{
DBG1(DBG_IMC, " opening '%s' failed: %s", abs_name,
strerror(errno));
goto end;
}
/* extract software identity from SWID tag */
if (extract_sw_id(*swid_tag, &sw_id) != SUCCESS)
{
DBG1(DBG_IMC, "software id could not be extracted from SWID tag");
chunk_unmap(swid_tag);
goto end;
}
/* In case of a targeted request */
if (targets->get_count(targets))
{
enumerator_t *target_enumerator;
swima_record_t *target;
bool match = FALSE;
target_enumerator = targets->create_enumerator(targets);
while (target_enumerator->enumerate(target_enumerator, &target))
{
if (chunk_equals(target->get_sw_id(target, NULL), sw_id))
{
match = TRUE;
break;
}
}
target_enumerator->destroy(target_enumerator);
if (!match)
{
chunk_unmap(swid_tag);
chunk_free(&sw_id);
continue;
}
}
DBG2(DBG_IMC, " %s", rel_name);
pos = strstr(pathname, "/swidtag");
sw_locator = pos ? chunk_create(pathname, pos - pathname) : chunk_empty;
sw_record = swima_record_create(0, sw_id, sw_locator);
sw_record->set_source_id(sw_record, SOURCE_ID_COLLECTOR);
if (!this->sw_id_only)
{
sw_record->set_record(sw_record, *swid_tag);
}
this->inventory->add(this->inventory, sw_record);
chunk_unmap(swid_tag);
chunk_free(&sw_id);
}
success = TRUE;
end:
enumerator->destroy(enumerator);
return success;
}
METHOD(swima_collector_t, collect_inventory, swima_inventory_t*,
private_swima_collector_t *this, bool sw_id_only, swima_inventory_t *targets)
{
char *directory, *generator;
bool pretty, full;
status_t status;
directory = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swima.swid_directory",
SWID_DIRECTORY, lib->ns);
generator = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swima.swid_generator",
SWID_GENERATOR, lib->ns);
pretty = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-swima.swid_pretty",
FALSE, lib->ns);
full = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-swima.swid_full",
FALSE, lib->ns);
/**
* Re-initialize collector
*/
this->sw_id_only = sw_id_only;
this->inventory->clear(this->inventory);
/**
* Source 1: Tags are generated by a package manager
*/
if (sw_id_only && this->db)
{
status = retrieve_inventory(this, targets);
}
else
{
status = generate_tags(this, generator, targets, pretty, full);
}
/**
* Source 2: Collect swidtag files by iteratively entering all
* directories in the tree under the "directory" path.
*/
collect_tags(this, directory, targets, FALSE);
return status == SUCCESS ? this->inventory : NULL;
}
METHOD(swima_collector_t, collect_events, swima_events_t*,
private_swima_collector_t *this, bool sw_id_only, swima_inventory_t *targets)
{
if (!sw_id_only || !this->db)
{
return NULL;
}
/**
* Re-initialize collector
*/
this->sw_id_only = sw_id_only;
this->events->clear(this->events);
return retrieve_events(this, targets) == SUCCESS ? this->events : NULL;
}
METHOD(swima_collector_t, destroy, void,
private_swima_collector_t *this)
{
DESTROY_IF(this->db);
this->inventory->destroy(this->inventory);
this->events->destroy(this->events);
free(this);
}
/**
* See header
*/
swima_collector_t *swima_collector_create(void)
{
private_swima_collector_t *this;
char *database;
uint32_t last_eid = 1, eid_epoch = 0x11223344;
INIT(this,
.public = {
.collect_inventory = _collect_inventory,
.collect_events = _collect_events,
.destroy = _destroy,
},
.inventory = swima_inventory_create(),
.events = swima_events_create(),
);
database = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swima.swid_database", NULL, lib->ns);
/* If we have an URI, try to connect to sw_collector database */
if (database)
{
database_t *db = lib->db->create(lib->db, database);
if (db)
{
enumerator_t *e;
/* Get last event ID and corresponding epoch */
e = db->query(db,
"SELECT id, epoch FROM events ORDER BY timestamp DESC",
DB_UINT, DB_UINT);
if (!e || !e->enumerate(e, &last_eid, &eid_epoch))
{
DBG1(DBG_IMC, "database query for last event failed");
DESTROY_IF(e);
db->destroy(db);
}
else
{
/* The query worked, attach collector database permanently */
e->destroy(e);
this->db = db;
}
}
else
{
DBG1(DBG_IMC, "opening sw-collector database URI '%s' failed",
database);
}
}
if (!this->db)
{
/* Set the event ID epoch and last event ID smanually */
eid_epoch = lib->settings->get_int(lib->settings,
"%s.plugins.imc-swima.eid_epoch",
eid_epoch, lib->ns);
}
this->inventory->set_eid(this->inventory, last_eid, eid_epoch);
this->events->set_eid(this->events, last_eid, eid_epoch);
return &this->public;
}
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_collector swima_collector
* @{ @ingroup libimcv_swima
*/
#ifndef SWIMA_COLLECTOR_H_
#define SWIMA_COLLECTOR_H_
#include "swima/swima_inventory.h"
#include "swima/swima_events.h"
typedef struct swima_collector_t swima_collector_t;
/**
* Class collecting Software [Identity] Inventory
*/
struct swima_collector_t {
/**
* Collect the Software [Identity] Inventory
*
* @param sw_id_only TRUE to request Software Identity Inventory only
* @param targets Software Identity targets
* @return Software [Identity] Inventory
*/
swima_inventory_t* (*collect_inventory)(swima_collector_t *this,
bool sw_id_only,
swima_inventory_t *targets);
/**
* Collect Software [Identity] Events
*
* @param sw_id_only TRUE to request Software Identity Inventory only
* @param targets Software Identity targets
* @return Software [Identity] Events
*/
swima_events_t* (*collect_events)(swima_collector_t *this,
bool sw_id_only,
swima_inventory_t *targets);
/**
* Destroys a swima_collector_t object.
*/
void (*destroy)(swima_collector_t *this);
};
/**
* Creates a swima_collector_t object
*/
swima_collector_t* swima_collector_create(void);
#endif /** SWIMA_COLLECTOR_H_ @}*/
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima/swima_data_model.h"
/**
* ISO/IEC 19770-2-2015: Information Technology - Software Asset Management -
* Part 2: Software Identification Tag
*/
pen_type_t swima_data_model_iso_2015_swid_xml = { PEN_IETF, 1 };
/**
* ISO/IEC 19770-2-2009: Information Technology - Software Asset Management -
* Part 2: Software Identification Tag
*/
pen_type_t swima_data_model_iso_2009_swid_xml = { PEN_IETF, 2 };
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_data_model swima_data_model
* @{ @ingroup libimcv_swima
*/
#ifndef SWIMA_DATA_MODEL_H_
#define SWIMA_DATA_MODEL_H_
#include <pen/pen.h>
/**
* ISO/IEC 19770-2-2015: Information Technology - Software Asset Management -
* Part 2: Software Identification Tag
*/
extern pen_type_t swima_data_model_iso_2015_swid_xml;
/**
* ISO/IEC 19770-2-2009: Information Technology - Software Asset Management -
* Part 2: Software Identification Tag
*/
extern pen_type_t swima_data_model_iso_2009_swid_xml;
#endif /** SWIMA_DATA_MODEL_H_ @}*/
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima_error.h"
#include <bio/bio_writer.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
/**
* SW_ERROR, SW_SUBSCRIPTION_DENIED_ERROR and SW_SUBSCRIPTION_ID_REUSE_ERROR
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Copy of Request ID / Subscription ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Description (variable length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* SW_RESPONSE_TOO_LARGE_ERROR
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Copy of Request ID / Subscription ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Maximum Allowed Size |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Description (variable length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
* Described in header.
*/
pa_tnc_attr_t* swima_error_create(pa_tnc_error_code_t code, uint32_t request_id,
uint32_t max_attr_size, char *description)
{
bio_writer_t *writer;
chunk_t msg_info;
pa_tnc_attr_t *attr;
pen_type_t error_code;
error_code = pen_type_create( PEN_IETF, code);
writer = bio_writer_create(4);
writer->write_uint32(writer, request_id);
if (code == PA_ERROR_SW_RESPONSE_TOO_LARGE)
{
writer->write_uint32(writer, max_attr_size);
}
if (description)
{
writer->write_data(writer, chunk_from_str(description));
}
msg_info = writer->get_buf(writer);
attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
}
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_error swima_error
* @{ @ingroup libimcv_swid
*/
#ifndef SWIMA_ERROR_H_
#define SWIMA_ERROR_H_
typedef enum swima_error_code_t swima_error_code_t;
#include "pa_tnc/pa_tnc_attr.h"
#include "ietf/ietf_attr_pa_tnc_error.h"
#include <library.h>
/**
* Creates a SWIMA Error Attribute
* see section 5.16 of IETF SW Inventory Message and Attributes for PA-TNC
*
* @param code PA-TNC error code
* @param request SWID request ID
* @param max_attr_size Maximum PA-TNC attribute size (if applicable)
* @param description Optional description string or NULL
*/
pa_tnc_attr_t* swima_error_create(pa_tnc_error_code_t code, uint32_t request,
uint32_t max_attr_size, char *description);
#endif /** SWIMA_ERROR_H_ @}*/
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima_event.h"
#include "swima_data_model.h"
typedef struct private_swima_event_t private_swima_event_t;
/**
* Private data of a swima_event_t object.
*
*/
struct private_swima_event_t {
/**
* Public swima_event_t interface.
*/
swima_event_t public;
/**
* Event ID
*/
uint32_t eid;
/**
* Timestamp
*/
chunk_t timestamp;
/**
* Action
*/
uint8_t action;
/**
* Software [Identifier] record
*/
swima_record_t *sw_record;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(swima_event_t, get_eid, uint32_t,
private_swima_event_t *this, chunk_t *timestamp)
{
if (timestamp)
{
*timestamp = this->timestamp;
}
return this->eid;
}
METHOD(swima_event_t, get_action, uint8_t,
private_swima_event_t *this)
{
return this->action;
}
METHOD(swima_event_t, get_sw_record, swima_record_t*,
private_swima_event_t *this)
{
return this->sw_record;
}
METHOD(swima_event_t, get_ref, swima_event_t*,
private_swima_event_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(swima_event_t, destroy, void,
private_swima_event_t *this)
{
if (ref_put(&this->ref))
{
this->sw_record->destroy(this->sw_record);
free(this->timestamp.ptr);
free(this);
}
}
/**
* See header
*/
swima_event_t *swima_event_create(uint32_t eid, chunk_t timestamp,
uint8_t action, swima_record_t *sw_record)
{
private_swima_event_t *this;
INIT(this,
.public = {
.get_eid = _get_eid,
.get_action = _get_action,
.get_sw_record = _get_sw_record,
.get_ref = _get_ref,
.destroy = _destroy,
},
.eid = eid,
.timestamp = chunk_clone(timestamp),
.action = action,
.sw_record = sw_record,
.ref = 1,
);
return &this->public;
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_event swima_event
* @{ @ingroup libimcv_swima
*/
#ifndef SWIMA_EVENT_H_
#define SWIMA_EVENT_H_
#include "swima_record.h"
#include <library.h>
#define SWIMA_EVENT_ACTION_CREATION 1
#define SWIMA_EVENT_ACTION_DELETION 2
#define SWIMA_EVENT_ACTION_ALTERATION 3
#define SWIMA_EVENT_ACTION_LAST 3
typedef struct swima_event_t swima_event_t;
/**
* Class storing a Software [Identifier] event
*/
struct swima_event_t {
/**
* Get Event ID and optionally the associated timestamp
*
* @param timestamp Timestamp associated with Event
* @return Event ID
*/
uint32_t (*get_eid)(swima_event_t *this, chunk_t *timestamp);
/**
* Get Action associated with Event
*
* @return Action associated with event
*/
uint8_t (*get_action)(swima_event_t *this);
/**
* Get Software [Identifier] record
*
* @return Software [Identifier] record
*/
swima_record_t* (*get_sw_record)(swima_event_t *this);
/**
* Get a new reference to a swima_event object
*
* @return this, with an increased refcount
*/
swima_event_t* (*get_ref)(swima_event_t *this);
/**
* Destroys a swima_event_t object.
*/
void (*destroy)(swima_event_t *this);
};
/**
* Creates a swima_event_t object
*
* @param eid Event ID
* @param timestamp Time of Event
* @param action Action (CREATION, DELETION, ALTERATION)
* @param sw_record Software [Identifier] record
*/
swima_event_t* swima_event_create(uint32_t eid, chunk_t timestamp,
uint8_t action, swima_record_t *sw_record);
#endif /** SWIMA_EVENT_H_ @}*/
+155
View File
@@ -0,0 +1,155 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima_events.h"
#include "swima_record.h"
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_swima_events_t private_swima_events_t;
/**
* Private data of a swima_events_t object.
*
*/
struct private_swima_events_t {
/**
* Public swima_events_t interface.
*/
swima_events_t public;
/**
* Epoch of Event IDs
*/
uint32_t epoch;
/**
* Last Event ID
*/
uint32_t last_eid;
/**
* Last Consulted Event ID
*/
uint32_t last_consulted_eid;
/**
* List of SW records
*/
linked_list_t *list;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(swima_events_t, add, void,
private_swima_events_t *this, swima_event_t *event)
{
this->list->insert_last(this->list, event);
}
METHOD(swima_events_t, get_count, int,
private_swima_events_t *this)
{
return this->list->get_count(this->list);
}
METHOD(swima_events_t, set_eid, void,
private_swima_events_t *this, uint32_t eid, uint32_t epoch)
{
this->last_eid = this->last_consulted_eid = eid;
this->epoch = epoch;
}
METHOD(swima_events_t, set_last_eid, void,
private_swima_events_t *this, uint32_t last_eid)
{
this->last_eid = last_eid;
}
METHOD(swima_events_t, get_eid, uint32_t,
private_swima_events_t *this, uint32_t *epoch, uint32_t *last_eid)
{
if (epoch)
{
*epoch = this->epoch;
}
if (last_eid)
{
*last_eid = this->last_eid;
}
return this->last_consulted_eid;
}
METHOD(swima_events_t, create_enumerator, enumerator_t*,
private_swima_events_t *this)
{
return this->list->create_enumerator(this->list);
}
METHOD(swima_events_t, get_ref, swima_events_t*,
private_swima_events_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(swima_events_t, clear, void,
private_swima_events_t *this)
{
this->list->destroy_offset(this->list, offsetof(swima_event_t, destroy));
this->list = linked_list_create();
}
METHOD(swima_events_t, destroy, void,
private_swima_events_t *this)
{
if (ref_put(&this->ref))
{
this->list->destroy_offset(this->list, offsetof(swima_event_t, destroy));
free(this);
}
}
/**
* See header
*/
swima_events_t *swima_events_create(void)
{
private_swima_events_t *this;
INIT(this,
.public = {
.add = _add,
.get_count = _get_count,
.set_eid = _set_eid,
.set_last_eid = _set_last_eid,
.get_eid = _get_eid,
.create_enumerator = _create_enumerator,
.get_ref = _get_ref,
.clear = _clear,
.destroy = _destroy,
},
.list = linked_list_create(),
.ref = 1,
);
return &this->public;
}
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_events swima_events
* @{ @ingroup libimcv_swima
*/
#ifndef SWIMA_EVENTS_H_
#define SWIMA_EVENTS_H_
#define SWIMA_MAX_ATTR_SIZE 10000000
#include "swima_event.h"
#include <library.h>
typedef struct swima_events_t swima_events_t;
/**
* Class managing list of Software [Identifier] Events
*/
struct swima_events_t {
/**
* Add event to list
*
* @param event Event to be added
*/
void (*add)(swima_events_t *this, swima_event_t *event);
/**
* Get the number of events in the event list
*
* @return Number of events
*/
int (*get_count)(swima_events_t *this);
/**
* Set both the Last and Last Consulted Event ID
*
* @param Last [Consulted] Event ID
* @param Epoch of event IDs
*/
void (*set_eid)(swima_events_t *this, uint32_t eid, uint32_t epoch);
/**
* Set Last Event ID if different from Last Consulted Event ID
*
* @param last_eid Last Event ID
*/
void (*set_last_eid)(swima_events_t *this, uint32_t last_eid);
/**
* Get both the Last and Last Consulted Event ID
*
* @param eid_epoch Event ID Epoch
* @param last_eid Last Event ID
* @return Last Consulted Event ID
*/
uint32_t (*get_eid)(swima_events_t *this, uint32_t *epoch, uint32_t *last_eid);
/**
* Create an event enumerator
*
* @return Enumerator returning events
*/
enumerator_t* (*create_enumerator)(swima_events_t *this);
/**
* Get a new reference to a swima_events object
*
* @return this, with an increased refcount
*/
swima_events_t* (*get_ref)(swima_events_t *this);
/**
* Clears the events, keeping the eid and epoch values.
*/
void (*clear)(swima_events_t *this);
/**
* Destroys a swima_events_t object.
*/
void (*destroy)(swima_events_t *this);
};
/**
* Creates a swima_events_t object
*/
swima_events_t* swima_events_create(void);
#endif /** SWIMA_EVENTS_H_ @}*/
+140
View File
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima_inventory.h"
#include "swima_record.h"
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_swima_inventory_t private_swima_inventory_t;
/**
* Private data of a swima_inventory_t object.
*
*/
struct private_swima_inventory_t {
/**
* Public swima_inventory_t interface.
*/
swima_inventory_t public;
/**
* Earliest or last event ID of the inventory
*/
uint32_t eid;
/**
* Epoch of event IDs
*/
uint32_t epoch;
/**
* List of SW records
*/
linked_list_t *list;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(swima_inventory_t, add, void,
private_swima_inventory_t *this, swima_record_t *record)
{
this->list->insert_last(this->list, record);
}
METHOD(swima_inventory_t, get_count, int,
private_swima_inventory_t *this)
{
return this->list->get_count(this->list);
}
METHOD(swima_inventory_t, set_eid, void,
private_swima_inventory_t *this, uint32_t eid, uint32_t epoch)
{
this->eid = eid;
this->epoch = epoch;
}
METHOD(swima_inventory_t, get_eid, uint32_t,
private_swima_inventory_t *this, uint32_t *epoch)
{
if (epoch)
{
*epoch = this->epoch;
}
return this->eid;
}
METHOD(swima_inventory_t, create_enumerator, enumerator_t*,
private_swima_inventory_t *this)
{
return this->list->create_enumerator(this->list);
}
METHOD(swima_inventory_t, get_ref, swima_inventory_t*,
private_swima_inventory_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(swima_inventory_t, clear, void,
private_swima_inventory_t *this)
{
this->list->destroy_offset(this->list, offsetof(swima_record_t, destroy));
this->list = linked_list_create();
}
METHOD(swima_inventory_t, destroy, void,
private_swima_inventory_t *this)
{
if (ref_put(&this->ref))
{
this->list->destroy_offset(this->list, offsetof(swima_record_t, destroy));
free(this);
}
}
/**
* See header
*/
swima_inventory_t *swima_inventory_create(void)
{
private_swima_inventory_t *this;
INIT(this,
.public = {
.add = _add,
.get_count = _get_count,
.set_eid = _set_eid,
.get_eid = _get_eid,
.create_enumerator = _create_enumerator,
.get_ref = _get_ref,
.clear = _clear,
.destroy = _destroy,
},
.list = linked_list_create(),
.ref = 1,
);
return &this->public;
}
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_inventory swima_inventory
* @{ @ingroup libimcv_swima
*/
#ifndef SWIMA_INVENTORY_H_
#define SWIMA_INVENTORY_H_
#define SWIMA_MAX_ATTR_SIZE 10000000
#include "swima_record.h"
#include <library.h>
typedef struct swima_inventory_t swima_inventory_t;
/**
* Class managing software inventory
*/
struct swima_inventory_t {
/**
* Add evidence record to software inventory
*
* @param record Software evidence record to be added
*/
void (*add)(swima_inventory_t *this, swima_record_t *record);
/**
* Get the number of evidence records in the software inventory
*
* @return Number evidence records
*/
int (*get_count)(swima_inventory_t *this);
/**
* Set the earliest or last event ID of the inventory
*
* @param Event ID
* @param Epoch of event IDs
*/
void (*set_eid)(swima_inventory_t *this, uint32_t eid, uint32_t epoch);
/**
* Get the earliest or last event ID of the inventory
*
* @param Epoch of event IDs
* @return Event ID
*/
uint32_t (*get_eid)(swima_inventory_t *this, uint32_t *epoch);
/**
* Create a software inventory evidence record enumerator
*
* @return Enumerator returning evidence records
*/
enumerator_t* (*create_enumerator)(swima_inventory_t *this);
/**
* Get a new reference to a swima_inventory object
*
* @return This, with an increased refcount
*/
swima_inventory_t* (*get_ref)(swima_inventory_t *this);
/**
* Clears the inventory, keeping the eid and epoch values
*/
void (*clear)(swima_inventory_t *this);
/**
* Destroys a swima_inventory_t object
*/
void (*destroy)(swima_inventory_t *this);
};
/**
* Creates a swima_inventory_t object
*
*/
swima_inventory_t* swima_inventory_create(void);
#endif /** SWIMA_INVENTORY_H_ @}*/
+174
View File
@@ -0,0 +1,174 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 "swima_record.h"
#include "swima_data_model.h"
typedef struct private_swima_record_t private_swima_record_t;
/**
* Private data of a swima_record_t object.
*
*/
struct private_swima_record_t {
/**
* Public swima_record_t interface.
*/
swima_record_t public;
/**
* Record ID
*/
uint32_t record_id;
/**
* Software Identity
*/
chunk_t sw_id;
/**
* Optional Software Locator
*/
chunk_t sw_locator;
/**
* Data Model
*/
pen_type_t data_model;
/**
* Source ID
*/
uint8_t source_id;
/**g
* Optional Software Inventory Evidence Record
*/
chunk_t record;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(swima_record_t, get_record_id, uint32_t,
private_swima_record_t *this)
{
return this->record_id;
}
METHOD(swima_record_t, get_sw_id, chunk_t,
private_swima_record_t *this, chunk_t *sw_locator)
{
if (sw_locator)
{
*sw_locator = this->sw_locator;
}
return this->sw_id;
}
METHOD(swima_record_t, set_data_model, void,
private_swima_record_t *this, pen_type_t data_model)
{
this->data_model = data_model;
}
METHOD(swima_record_t, get_data_model, pen_type_t,
private_swima_record_t *this)
{
return this->data_model;
}
METHOD(swima_record_t, set_source_id, void,
private_swima_record_t *this, uint8_t source_id)
{
this->source_id = source_id;
}
METHOD(swima_record_t, get_source_id, uint8_t,
private_swima_record_t *this)
{
return this->source_id;
}
METHOD(swima_record_t, set_record, void,
private_swima_record_t *this, chunk_t record)
{
chunk_free(&this->record);
this->record = chunk_clone(record);
}
METHOD(swima_record_t, get_record, chunk_t,
private_swima_record_t *this)
{
return this->record;
}
METHOD(swima_record_t, get_ref, swima_record_t*,
private_swima_record_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(swima_record_t, destroy, void,
private_swima_record_t *this)
{
if (ref_put(&this->ref))
{
free(this->sw_id.ptr);
free(this->sw_locator.ptr);
free(this->record.ptr);
free(this);
}
}
/**
* See header
*/
swima_record_t *swima_record_create(uint32_t record_id, chunk_t sw_id,
chunk_t sw_locator)
{
private_swima_record_t *this;
INIT(this,
.public = {
.get_record_id = _get_record_id,
.get_sw_id = _get_sw_id,
.set_data_model = _set_data_model,
.get_data_model = _get_data_model,
.set_source_id = _set_source_id,
.get_source_id = _get_source_id,
.set_record = _set_record,
.get_record = _get_record,
.get_ref = _get_ref,
.destroy = _destroy,
},
.record_id = record_id,
.data_model = swima_data_model_iso_2015_swid_xml,
.sw_id = chunk_clone(sw_id),
.ref = 1,
);
if (sw_locator.len > 0)
{
this->sw_locator = chunk_clone(sw_locator);
}
return &this->public;
}
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2017 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 swima_record swima_record
* @{ @ingroup libimcv_swima
*/
#ifndef SWIMA_RECORD_H_
#define SWIMA_RECORD_H_
#include <library.h>
#include <pen/pen.h>
typedef struct swima_record_t swima_record_t;
/**
* Class storing a Software Inventory Evidence Collection record
*/
struct swima_record_t {
/**
* Get Software Identifier and optional Software Location
*
* @return Record ID
*/
uint32_t (*get_record_id)(swima_record_t *this);
/**
* Get Software Identifier and optional Software Location
*
* @param sw_locator Optional Software Locator
* @return Software Identifier
*/
chunk_t (*get_sw_id)(swima_record_t *this, chunk_t *sw_locator);
/**
* Set Data Model
*
* @param Data model type in PEN namespace
*/
void (*set_data_model)(swima_record_t *this, pen_type_t data_model);
/**
* Get Data Model
*
* @return Data model type in PEN namespace
*/
pen_type_t (*get_data_model)(swima_record_t *this);
/**
* Set Source ID
*
* @param Source ID
*/
void (*set_source_id)(swima_record_t *this, uint8_t source_id);
/**
* Get Source ID
*
* @return Source ID
*/
uint8_t (*get_source_id)(swima_record_t *this);
/**
* Set Software Inventory Evidence Record
*
* @param Software Inventory Evidence Record
*/
void (*set_record)(swima_record_t *this, chunk_t record);
/**
* Get Software Inventory Evidence Record
*
* @return Software Inventory Evidence Record
*/
chunk_t (*get_record)(swima_record_t *this);
/**
* Get a new reference to a swima_record object
*
* @return this, with an increased refcount
*/
swima_record_t* (*get_ref)(swima_record_t *this);
/**
* Destroys a swima_record_t object.
*/
void (*destroy)(swima_record_t *this);
};
/**
* Creates a swima_record_t object
*
* @param record_id Record ID
* @param sw_id Software Identifierl
* @param sw_locator Software Locator or empty chunk
*/
swima_record_t* swima_record_create(uint32_t record_id, chunk_t sw_id,
chunk_t sw_locator);
#endif /** SWIMA_RECORD_H_ @}*/
+3 -1
View File
@@ -32,7 +32,7 @@ typedef struct private_tcg_swid_attr_req_t private_tcg_swid_attr_req_t;
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |R|S|C| Reserved| Tag ID Count |
* |C|S|R| Reserved| Tag ID Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Request ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -201,6 +201,7 @@ METHOD(pa_tnc_attr_t, process, status_t,
if (!reader->read_data16(reader, &tag_creator))
{
DBG1(DBG_TNC, "insufficient data for Tag Creator field");
reader->destroy(reader);
return FAILED;
}
*offset += 2 + tag_creator.len;
@@ -208,6 +209,7 @@ METHOD(pa_tnc_attr_t, process, status_t,
if (!reader->read_data16(reader, &unique_sw_id))
{
DBG1(DBG_TNC, "insufficient data for Unique Software ID");
reader->destroy(reader);
return FAILED;
}
*offset += 2 + unique_sw_id.len;
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* Copyright (C) 2013-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,9 +28,9 @@ typedef enum tcg_swid_attr_req_flag_t tcg_swid_attr_req_flag_t;
enum tcg_swid_attr_req_flag_t {
TCG_SWID_ATTR_REQ_FLAG_NONE = 0,
TCG_SWID_ATTR_REQ_FLAG_R = (1 << 7),
TCG_SWID_ATTR_REQ_FLAG_C = (1 << 7),
TCG_SWID_ATTR_REQ_FLAG_S = (1 << 6),
TCG_SWID_ATTR_REQ_FLAG_C = (1 << 5)
TCG_SWID_ATTR_REQ_FLAG_R = (1 << 5)
};
#include "tcg/tcg_attr.h"
+12 -2
View File
@@ -85,7 +85,7 @@ static size_t curl_cb(void *ptr, size_t size, size_t nmemb, cb_data_t *data)
METHOD(fetcher_t, fetch, status_t,
private_curl_fetcher_t *this, char *uri, void *userdata)
{
char error[CURL_ERROR_SIZE], *enc_uri;
char error[CURL_ERROR_SIZE], *enc_uri, *p1, *p2;
CURLcode curl_status;
status_t status;
long result = 0;
@@ -123,7 +123,17 @@ METHOD(fetcher_t, fetch, status_t,
curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, this->headers);
}
DBG2(DBG_LIB, " sending request to '%s'...", uri);
/* if the URI contains a username[:password] prefix then mask it */
p1 = strstr(uri, "://");
p2 = strchr(uri, '@');
if (p1 && p2)
{
DBG2(DBG_LIB, " sending request to '%.*sxxxx%s'...", p1+3-uri, uri, p2);
}
else
{
DBG2(DBG_LIB, " sending request to '%s'...", uri);
}
curl_status = curl_easy_perform(this->curl);
switch (curl_status)
{
+5 -5
View File
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2010-2015 Andreas Steffen
*
* Copyright (C) 2010-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -17,7 +16,7 @@
#include "tncif_pa_subtypes.h"
/* IETF PA Subtype names */
ENUM_BEGIN(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_CLIENT,
ENUM_BEGIN(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_SW,
"Testing",
"Operating System",
"Anti-Virus",
@@ -26,10 +25,11 @@ ENUM_BEGIN(pa_subtype_ietf_names, PA_SUBTYPE_IETF_TESTING, PA_SUBTYPE_IETF_NEA_C
"Firewall",
"IDPS",
"VPN",
"NEA Client"
"NEA Client",
"Software"
);
ENUM_NEXT(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY, PA_SUBTYPE_IETF_ANY,
PA_SUBTYPE_IETF_NEA_CLIENT,
PA_SUBTYPE_IETF_SW,
"ANY"
);
ENUM_END(pa_subtype_ietf_names, PA_SUBTYPE_IETF_ANY);
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2015 Andreas Steffen
* Copyright (C) 2011-2017 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -43,6 +43,7 @@ typedef enum pa_subtype_ita_t pa_subtype_ita_t;
PA_SUBTYPE_IETF_IDPS = 0x06,
PA_SUBTYPE_IETF_VPN = 0x07,
PA_SUBTYPE_IETF_NEA_CLIENT = 0x08,
PA_SUBTYPE_IETF_SW = 0x09,
PA_SUBTYPE_IETF_ANY = 0xff
};
+27 -10
View File
@@ -42,9 +42,10 @@ static void usage(FILE *out)
{
fprintf(out,
"Usage: pt-tls --connect <hostname|address> [--port <port>]\n"
" [--cert <file>]+ [--key <file>] [--key-type rsa|ecdsa]\n"
" [--client <client-id>] [--secret <password>]\n"
" [--optionsfrom <filename>] [--quiet] [--debug <level>]\n");
" [--cert <file>]+ [--keyid <hex>|--key <file>]\n"
" [--key-type rsa|ecdsa] [--client <client-id>]\n"
" [--secret <password>] [--optionsfrom <filename>]\n"
" [--quiet] [--debug <level>]\n");
}
/**
@@ -121,15 +122,26 @@ static bool load_certificate(char *filename)
/**
* Load private key from file
*/
static bool load_key(char *filename, key_type_t type)
static bool load_key(char *keyid, char *filename, key_type_t type)
{
private_key_t *key;
chunk_t chunk;
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
BUILD_FROM_FILE, filename, BUILD_END);
if (keyid)
{
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
BUILD_PKCS11_KEYID, chunk, BUILD_END);
chunk_free(&chunk);
}
else
{
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
BUILD_FROM_FILE, filename, BUILD_END);
}
if (!key)
{
DBG1(DBG_TLS, "loading key from '%s' failed", filename);
DBG1(DBG_TLS, "loading key from '%s' failed", keyid ? keyid : filename);
return FALSE;
}
creds->add_key(creds, key);
@@ -255,7 +267,8 @@ static void init()
int main(int argc, char *argv[])
{
char *address = NULL, *identity = "%any", *secret = NULL, *key_file = NULL;
char *address = NULL, *identity = "%any", *secret = NULL;
char *keyid = NULL, *key_file = NULL;
key_type_t key_type = KEY_RSA;
int port = PT_TLS_PORT;
@@ -270,8 +283,9 @@ int main(int argc, char *argv[])
{"secret", required_argument, NULL, 's' },
{"port", required_argument, NULL, 'p' },
{"cert", required_argument, NULL, 'x' },
{"keyid", required_argument, NULL, 'K' },
{"key", required_argument, NULL, 'k' },
{"key-type", required_argument, NULL, 't' },
{"key-type", required_argument, NULL, 't' },
{"mutual", no_argument, NULL, 'm' },
{"quiet", no_argument, NULL, 'q' },
{"debug", required_argument, NULL, 'd' },
@@ -291,6 +305,9 @@ int main(int argc, char *argv[])
return 1;
}
continue;
case 'K': /* --keyid <hex> */
keyid = optarg;
continue;
case 'k': /* --key <file> */
key_file = optarg;
continue;
@@ -352,7 +369,7 @@ int main(int argc, char *argv[])
usage(stderr);
return 1;
}
if (key_file && !load_key(key_file, key_type))
if ((keyid || key_file) && !load_key(keyid, key_file, key_type))
{
return 1;
}
@@ -56,6 +56,8 @@ CONFIG_OPTS = \
--enable-imv-attestation \
--enable-imc-swid \
--enable-imv-swid \
--enable-imc-swima \
--enable-imv-swima \
--enable-imc-hcd \
--enable-imv-hcd \
--enable-sql \
@@ -0,0 +1,9 @@
The PT-TLS (RFC 6876) clients <b>carol</b> and <b>dave</b> set up a connection each to the policy decision
point (PDP) <b>alice</b>. Endpoint <b>carol</b> uses password-based SASL PLAIN client authentication during the
<b>PT-TLS negotiation phase</b> whereas endpoint <b>dave</b> uses certificate-based TLS client authentication
during the <b>TLS setup phase</b>.
<p/>
During the ensuing <b>PT-TLS data transport phase</b> the <b>OS</b> and <b>SWIMA</b> IMC/IMV pairs
loaded by the PT-TLS clients and PDP, respectively, exchange PA-TNC (RFC 5792) messages
embedded in PB-TNC (RFC 5793) batches. The <b>SWIMA</b> IMC on <b>carol</b> is requested to deliver
a concise <b>Software ID Inventory</b> whereas <b>dave</b> must send a full <b>Software Inventory</b>.
@@ -0,0 +1,25 @@
dave:: cat /var/log/auth.log::sending TLS CertificateVerify handshake::YES
dave:: cat /var/log/auth.log::collected ... SW records::YES
carol::cat /var/log/auth.log::received SASL Success result::YES
carol::cat /var/log/auth.log::collected ... SW ID records::YES
carol::cat /var/log/auth.log::strongswan.org__strongSwan.*swidtag::YES
carol::cat /var/log/auth.log::collected 1 SW record::YES
alice::cat /var/log/daemon.log::accepting PT-TLS stream from PH_IP_DAVE::YES
alice::cat /var/log/daemon.log::checking certificate status of.*C=CH, O=Linux strongSwan, OU=Accounting, [email protected]::YES
alice::cat /var/log/daemon.log::certificate status is good::YES
alice::cat /var/log/daemon.log::skipping SASL, client already authenticated by TLS certificate::YES
alice::cat /var/log/daemon.log::user AR identity.*C=CH, O=Linux strongSwan, OU=Accounting, [email protected].*authenticated by certificate::YES
alice::cat /var/log/daemon.log::received software inventory with ... items for request 3 at last eid 1 of epoch::YES
alice::cat /var/log/daemon.log::successful system command: ssh root@moon.*logger -t charon -p auth.alert.*host with IP address 192.168.0.200 is blocked::YES
moon:: cat /var/log/auth.log::host with IP address 192.168.0.200 is blocked::YES
alice::cat /var/log/daemon.log::accepting PT-TLS stream from PH_IP_CAROL::YES
alice::cat /var/log/daemon.log::SASL PLAIN authentication successful::YES
alice::cat /var/log/daemon.log::SASL client identity is.*carol::YES
alice::cat /var/log/daemon.log::user AR identity.*carol.*authenticated by password::YES
alice::cat /var/log/daemon.log::failed to collect SW ID events, fallback to SW ID inventory::YES
alice::cat /var/log/daemon.log::received software ID inventory with ... items for request 9 at last eid 1 of epoch::YES
alice::cat /var/log/daemon.log::1 SWID tag target::YES
alice::cat /var/log/daemon.log::received software inventory with 1 item for request 9 at last eid 1 of epoch::YES
alice::cat /var/log/daemon.log::strongswan.org__strongSwan.*@ /usr/local/share/strongswan::YES
alice::cat /var/log/daemon.log::successful system command: ssh root@moon.*logger -t charon -p auth.alert.*host with IP address 192.168.0.100 is allowed::YES
moon::cat /var/log/auth.log::host with IP address 192.168.0.100 is allowed::YES
@@ -0,0 +1,31 @@
WSGIPythonPath /var/www/tnc
<VirtualHost *:80>
ServerName tnc.strongswan.org
ServerAlias tnc
ServerAdmin webmaster@localhost
DocumentRoot /var/www/tnc
<Directory /var/www/tnc/config>
<Files wsgi.py>
<IfModule mod_authz_core.c>
Require all granted
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Allow from all
</IfModule>
</Files>
</Directory>
WSGIScriptAlias / /var/www/tnc/config/wsgi.py
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
Alias /static/ /var/www/tnc/static/
ErrorLog ${APACHE_LOG_DIR}/tnc/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/tnc/access.log combined
</VirtualHost>
@@ -0,0 +1 @@
Include sites-available/000-default.conf
@@ -0,0 +1,28 @@
*filter
# default policy is DROP
-P INPUT DROP
-P OUTPUT DROP
-P FORWARD DROP
# open loopback interface
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
# allow PT-TLS
-A INPUT -i eth0 -p tcp --dport 271 -j ACCEPT
-A OUTPUT -o eth0 -p tcp --sport 271 -j ACCEPT
# allow inbound ssh
-A INPUT -p tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp --sport 22 -j ACCEPT
# allow outbound ssh
-A OUTPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p tcp --sport 22 -j ACCEPT
# allow crl fetch from winnetou
-A INPUT -i eth0 -p tcp --sport 80 -s 192.168.0.150 -j ACCEPT
-A OUTPUT -o eth0 -p tcp --dport 80 -d 192.168.0.150 -j ACCEPT
COMMIT
@@ -0,0 +1,61 @@
/* Devices */
INSERT INTO devices ( /* 1 */
value, product, created
)
SELECT 'aabbccddeeff11223344556677889900', id, 1372330615
FROM products WHERE name = 'Debian DEBIAN_VERSION x86_64';
/* Groups Members */
INSERT INTO groups_members (
group_id, device_id
) VALUES (
10, 1
);
/* Identities */
INSERT INTO identities (
type, value
) VALUES ( /* [email protected] */
4, X'64617665407374726f6e677377616e2e6f7267'
);
/* Sessions */
INSERT INTO sessions (
time, connection, identity, device, product, rec
)
SELECT NOW, 1, 1, 1, id, 0
FROM products WHERE name = 'Debian DEBIAN_VERSION x86_64';
/* Results */
INSERT INTO results (
session, policy, rec, result
) VALUES (
1, 1, 0, 'processed 355 packages: 0 not updated, 0 blacklisted, 4 ok, 351 not found'
);
/* Enforcements */
INSERT INTO enforcements (
policy, group_id, max_age, rec_fail, rec_noresult
) VALUES (
3, 10, 0, 2, 2
);
INSERT INTO enforcements (
policy, group_id, max_age
) VALUES (
17, 2, 86400
);
INSERT INTO enforcements (
policy, group_id, max_age
) VALUES (
18, 10, 86400
);
DELETE FROM enforcements WHERE id = 1;
@@ -0,0 +1,19 @@
[debug]
DEBUG=0
TEMPLATE_DEBUG=0
DEBUG_TOOLBAR=0
[db]
DJANGO_DB_URL=sqlite:////var/www/tnc/django.db
STRONGTNC_DB_URL = sqlite:////etc/db.d/config.db
[localization]
LANGUAGE_CODE=en-us
TIME_ZONE=Europe/Zurich
[admins]
Your Name: [email protected]
[security]
SECRET_KEY=strongSwan
ALLOWED_HOSTS=127.0.0.1,10.1.0.10,tnc.strongswan.org,tnc
@@ -0,0 +1,49 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = random nonce pem pkcs1 x509 openssl revocation constraints curl vici socket-default kernel-netlink tnc-pdp tnc-imv tnc-tnccs tnccs-20 sqlite
syslog {
auth {
default = 0
}
daemon {
tls = 2
tnc = 2
imv = 3
}
}
plugins {
tnc-pdp {
server = aaa.strongswan.org
radius {
secret = gv6URkSs
}
}
tnc-imv {
dlclose = no
}
}
}
libtls {
suites = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
}
libimcv {
database = sqlite:///etc/db.d/config.db
policy_script = /usr/local/libexec/ipsec/imv_policy_manager
plugins {
imv-swima {
rest_api {
uri = http://admin-user:[email protected]/api/
}
}
}
}
imv_policy_manager {
command_allow = ssh root@moon 'logger -t charon -p auth.alert "\"host with IP address %s is allowed\""'
command_block = ssh root@moon 'logger -t charon -p auth.alert "\"host with IP address %s is blocked\""'
}
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtxfP0jM8wZqtJvNmYar+WmB5GkzZbm431C5YWpSc/4vjCMXl
h/7VuGPkOeuEqU4KOKL3l0OQt1Exh77ii9ekg0X//4n132fI/hg0sKVRPCK8HC8l
0LdwnLLNI7uO5ObYY1KtAVnDeI/cfFbLV0z38/X7GWCpKi7ocmVMNalpD5w7c/9a
VgpO70O9NPr+OPhs1Lp9uJQQbQzQlhydhK3SLA1bJEcyXYMqOamJud+EcM1Hjq3S
W5JpKhuroDSxGzMntRF0TgrGXf8ctNfz/52repoUh2GrFfOhkpXrKUErf46NNtnD
e4FXvyprZNQO4wJBWKCSS3p16UWEL+1LFwiDPQIDAQABAoIBAQCNeNG0+rA0bF7k
nOf8CZL1pFuOzdin8nQi+Bh/DRvufVlU+wyrM2ZSTqUXd/sOkuVk889ZyvQ0IYGj
AQStx1cvs9Pl0OTx1ZDBfVShNWv6imBNasTObB+QhLvro037Yr/KpyRUydY2/vn/
/VSrRSbGE8gMyNqNZKdpVQo44Ij0bJXxx7kVJ7CfftB65bujkRSK5u7eGjFVyHGs
P9v4n72Pt0mVdC8yeiMjJAmmKLWaDf7U2SUoaxf0IRjRNPdVBuPjbYjfnJ0sGlxF
sCQtu+3JQ4b7vyxrAyUtImbTLwvFqQHTGIahZUvhGd/1aO0Zmls1mvuZ+VhUIsek
uBJh54jFAoGBAN7M08mBkA8oUns0IzzG+A0JYDmdbvOWbKtyQDRl7LkXOq/PckIj
PoliI/5aNZe9+Q8kq8xnvLVcsup7EX6Ovaqc6S3ODNEjy4XEqGMM9tkrz4R4N5f5
hLayOg3MfdJiPOn3HF+cVvHp0Vwpt8K5TgVmOWkVSKTa+6eX4mhQUuKjAoGBANJg
Rmka90zo+7PPze4oo5ePeqwZrwQ3/6OeD/G1lqMFPOgk3MLGuv9HvtQA5gyyAH7+
Qy/t+rdPSC7PZi29s8/cERmWTdbZ1ocuKa6xxSvktl7Ibv51d0sW1n+kfVin7cLL
SskoK8BRXjXsZg7jjZjE5f6iqdHq+JPA2JWM10CfAoGAOXTvJScxhIcshjNS5wiU
zZ/eXd1Y0J65VZl4L0sdujngW5iO6bl3FizmBWE0Mva99QbK+0LBarAGP+wO/elH
xmkCxVo++exWPyARIMImIqlmsc3i4GFrtUXPLOHQjOHivZ+JhKqnzWk0IaVsi14I
XeIX6h6gBkum3HiR3b7hMSsCgYEAtq7ftbmy8liG6hgTzTIBDUWM0xHihxlRpnVF
hzGWw61yvGv2QDVugOt+bH7zRib0g1KsaVyQkMoJ9ownQKUxFdkWCFAa++1iezS9
AXRhscIEE76dk93RX6VPUrw2FNyOfM8n/BIkG/cMhmroHRnBBd5Fkp8SNLWEclnO
Od95tCUCgYEAgvohkyZAAKMRUFYEvHgwyxeXHifHVPIoK9UN022DJmIEJE2ISGtH
yHnBKgF52tlYhC9ijKwMG43C9IvycydRUtViOxDV8AiE4BV1tXuQHLl0jD2R7yq5
9pNtnYgXW+ZKlx9705ltHj8hhKl6r2I8oXdR9KFGO83wq8fr6tyjqHc=
-----END RSA PRIVATE KEY-----
@@ -0,0 +1,7 @@
secrets {
eap-carol {
id = carol
secret = "Ar3etTnp"
}
}
@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEIDCCAwigAwIBAgIBMzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJDSDEZ
MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS
b290IENBMB4XDTE1MDgwNDE0NTUzMVoXDTE5MDkwNjE0NTUzMVowRTELMAkGA1UE
BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEmFhYS5z
dHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcX
z9IzPMGarSbzZmGq/lpgeRpM2W5uN9QuWFqUnP+L4wjF5Yf+1bhj5DnrhKlOCjii
95dDkLdRMYe+4ovXpINF//+J9d9nyP4YNLClUTwivBwvJdC3cJyyzSO7juTm2GNS
rQFZw3iP3HxWy1dM9/P1+xlgqSou6HJlTDWpaQ+cO3P/WlYKTu9DvTT6/jj4bNS6
fbiUEG0M0JYcnYSt0iwNWyRHMl2DKjmpibnfhHDNR46t0luSaSobq6A0sRszJ7UR
dE4Kxl3/HLTX8/+dq3qaFIdhqxXzoZKV6ylBK3+OjTbZw3uBV78qa2TUDuMCQVig
kkt6delFhC/tSxcIgz0CAwEAAaOCARkwggEVMAkGA1UdEwQCMAAwCwYDVR0PBAQD
AgOoMB0GA1UdDgQWBBRFNnP26ELy5j7KMOO+a8dh5pLe6DBtBgNVHSMEZjBkgBRd
p91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoT
EExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIB
ADAdBgNVHREEFjAUghJhYWEuc3Ryb25nc3dhbi5vcmcwEwYDVR0lBAwwCgYIKwYB
BQUHAwEwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5zdHJvbmdzd2FuLm9y
Zy9zdHJvbmdzd2FuLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAsncNPDCCDd4mzIHs
nHY7b6H1tVQtFSbAQntV06D4D7vOp6Y+M5S8ta50hJu4f4GEeH5c7/hm8gbRdHt/
TcjlV/UWBfhU3c/hNJo2LpmmtdmYUABLA3rdZ+FzOnAHX9H8eI988G7eHpI9T7L2
FY2YEnWhIUVjFrojtH2+NbuA/Ori1QwSBiVhvJQgvUPjhKkjUtC+8zIdaCmJFErQ
GGObpAMtnTcQ74md9BQ791RPMp77tDe1fgm7m8QWIsoIyYEhvzyfk2VTBn1VlWyH
sbT0Vb3X9ubt0KXn2Xr491WTCpc5rzDWj9CNUYUgW7RaPxgw5cj2HK6oiLnGpO73
xyr/Qw==
-----END CERTIFICATE-----
@@ -0,0 +1,4 @@
#IMV configuration file for strongSwan client
IMV "OS" /usr/local/lib/ipsec/imcvs/imv-os.so
IMV "SWIMA" /usr/local/lib/ipsec/imcvs/imv-swima.so
@@ -0,0 +1,4 @@
/* strongSwan SQLite database */
/* configuration is read from the command line */
/* credentials are read from the command line */
@@ -0,0 +1,20 @@
*filter
# default policy is DROP
-P INPUT DROP
-P OUTPUT DROP
-P FORWARD DROP
# allow PT-TLS
-A INPUT -i eth0 -s 10.1.0.10 -p tcp --sport 271 -j ACCEPT
-A OUTPUT -o eth0 -d 10.1.0.10 -p tcp --dport 271 -j ACCEPT
# allow ssh
-A INPUT -p tcp --dport 22 -j ACCEPT
-A OUTPUT -p tcp --sport 22 -j ACCEPT
# allow crl fetch from winnetou
-A INPUT -i eth0 -p tcp --sport 80 -s 192.168.0.150 -j ACCEPT
-A OUTPUT -o eth0 -p tcp --dport 80 -d 192.168.0.150 -j ACCEPT
COMMIT
@@ -0,0 +1,6 @@
--connect aaa.strongswan.org
--client carol
--secret "Ar3etTnp"
--cert /etc/swanctl/x509ca/strongswanCert.pem
--quiet
--debug 2
@@ -0,0 +1,9 @@
# /etc/strongswan.conf - strongSwan configuration file
libtls {
suites = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
}
pt-tls-client {
load = revocation constraints pem openssl curl nonce tnc-tnccs tnc-imc tnccs-20
}
@@ -0,0 +1 @@
# the PT-TLS client reads its configuration and secrets via the command line

Some files were not shown because too many files have changed in this diff Show More