libimcv: Implemented IETF SW PA-TNC attributes
authorAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 22 May 2017 14:04:06 +0000 (16:04 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 8 Jul 2017 21:19:51 +0000 (23:19 +0200)
26 files changed:
src/libimcv/Makefile.am
src/libimcv/ietf/ietf_attr.c
src/libimcv/ietf/ietf_attr_pa_tnc_error.c
src/libimcv/ietf/ietf_attr_pa_tnc_error.h
src/libimcv/ietf/swima/ietf_swima_attr_req.c [new file with mode: 0644]
src/libimcv/ietf/swima/ietf_swima_attr_req.h [new file with mode: 0644]
src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.c [new file with mode: 0644]
src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.h [new file with mode: 0644]
src/libimcv/ietf/swima/ietf_swima_attr_sw_inv.c [new file with mode: 0644]
src/libimcv/ietf/swima/ietf_swima_attr_sw_inv.h [new file with mode: 0644]
src/libimcv/imv/tables.sql
src/libimcv/pa_tnc/pa_tnc_msg.c
src/libimcv/swima/swima_collector.c [new file with mode: 0644]
src/libimcv/swima/swima_collector.h [new file with mode: 0644]
src/libimcv/swima/swima_data_model.c [new file with mode: 0644]
src/libimcv/swima/swima_data_model.h [new file with mode: 0644]
src/libimcv/swima/swima_error.c [new file with mode: 0644]
src/libimcv/swima/swima_error.h [new file with mode: 0644]
src/libimcv/swima/swima_event.c [new file with mode: 0644]
src/libimcv/swima/swima_event.h [new file with mode: 0644]
src/libimcv/swima/swima_events.c [new file with mode: 0644]
src/libimcv/swima/swima_events.h [new file with mode: 0644]
src/libimcv/swima/swima_inventory.c [new file with mode: 0644]
src/libimcv/swima/swima_inventory.h [new file with mode: 0644]
src/libimcv/swima/swima_record.c [new file with mode: 0644]
src/libimcv/swima/swima_record.h [new file with mode: 0644]

index 8cde4b7..eb8c778 100644 (file)
@@ -2,7 +2,8 @@ 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\"
 
 ipseclib_LTLIBRARIES = libimcv.la
 
@@ -49,6 +50,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 \
@@ -91,6 +95,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 \
@@ -192,6 +203,8 @@ imcv_tests_SOURCES = \
        seg/seg_contract_manager.c \
        suites/test_imcv_seg.c \
        ietf/ietf_attr_pa_tnc_error.c \
+       ietf/swima/ietf_swima_attr_req.c \
+       ietf/swima/ietf_swima_attr_sw_inv.c \
        tcg/seg/tcg_seg_attr_seg_env.c \
        imcv.c imcv_tests.h imcv_tests.c
 
index 074bd11..9e3e83d 100644 (file)
@@ -25,6 +25,9 @@
 #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"
 
 
@@ -94,14 +97,19 @@ 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_TESTING:
-               case IETF_ATTR_RESERVED:
-               /* unsupported IETF/SWIMA attributes */
                case IETF_ATTR_SW_REQUEST:
+                       return ietf_swima_attr_req_create_from_data(length, value);
                case IETF_ATTR_SW_ID_INVENTORY:
-               case IETF_ATTR_SW_ID_EVENTS:
+                       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:
index 8f21628..966c095 100644 (file)
@@ -256,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))
                {
@@ -406,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;
        }
index 9a88276..7dbc338 100644 (file)
@@ -37,6 +37,7 @@ enum  pa_tnc_error_code_t {
        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,
diff --git a/src/libimcv/ietf/swima/ietf_swima_attr_req.c b/src/libimcv/ietf/swima/ietf_swima_attr_req.c
new file mode 100644 (file)
index 0000000..07d0b0c
--- /dev/null
@@ -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;
+}
diff --git a/src/libimcv/ietf/swima/ietf_swima_attr_req.h b/src/libimcv/ietf/swima/ietf_swima_attr_req.h
new file mode 100644 (file)
index 0000000..21155d6
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.c b/src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.c
new file mode 100644 (file)
index 0000000..e315c3d
--- /dev/null
@@ -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;
+}
diff --git a/src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.h b/src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.h
new file mode 100644 (file)
index 0000000..00f64dd
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/ietf/swima/ietf_swima_attr_sw_inv.c b/src/libimcv/ietf/swima/ietf_swima_attr_sw_inv.c
new file mode 100644 (file)
index 0000000..ee5b16b
--- /dev/null
@@ -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;
+}
diff --git a/src/libimcv/ietf/swima/ietf_swima_attr_sw_inv.h b/src/libimcv/ietf/swima/ietf_swima_attr_sw_inv.h
new file mode 100644 (file)
index 0000000..a50cf29
--- /dev/null
@@ -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_ @}*/
index 1ac51ef..749eb60 100644 (file)
@@ -304,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"
+);
index 17c649d..5f5add7 100644 (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;
                        }
diff --git a/src/libimcv/swima/swima_collector.c b/src/libimcv/swima/swima_collector.c
new file mode 100644 (file)
index 0000000..ab5a7b6
--- /dev/null
@@ -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;
+}
diff --git a/src/libimcv/swima/swima_collector.h b/src/libimcv/swima/swima_collector.h
new file mode 100644 (file)
index 0000000..848dc16
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/swima/swima_data_model.c b/src/libimcv/swima/swima_data_model.c
new file mode 100644 (file)
index 0000000..f444724
--- /dev/null
@@ -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 };
diff --git a/src/libimcv/swima/swima_data_model.h b/src/libimcv/swima/swima_data_model.h
new file mode 100644 (file)
index 0000000..40f0ba7
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/swima/swima_error.c b/src/libimcv/swima/swima_error.c
new file mode 100644 (file)
index 0000000..2aed296
--- /dev/null
@@ -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;
+}
+
diff --git a/src/libimcv/swima/swima_error.h b/src/libimcv/swima/swima_error.h
new file mode 100644 (file)
index 0000000..7371131
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/swima/swima_event.c b/src/libimcv/swima/swima_event.c
new file mode 100644 (file)
index 0000000..20cfa8d
--- /dev/null
@@ -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;
+}
+
diff --git a/src/libimcv/swima/swima_event.h b/src/libimcv/swima/swima_event.h
new file mode 100644 (file)
index 0000000..fe69d6a
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/swima/swima_events.c b/src/libimcv/swima/swima_events.c
new file mode 100644 (file)
index 0000000..ba0810d
--- /dev/null
@@ -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;
+}
diff --git a/src/libimcv/swima/swima_events.h b/src/libimcv/swima/swima_events.h
new file mode 100644 (file)
index 0000000..66bbedf
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/swima/swima_inventory.c b/src/libimcv/swima/swima_inventory.c
new file mode 100644 (file)
index 0000000..acb69b9
--- /dev/null
@@ -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;
+}
diff --git a/src/libimcv/swima/swima_inventory.h b/src/libimcv/swima/swima_inventory.h
new file mode 100644 (file)
index 0000000..21953bb
--- /dev/null
@@ -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_ @}*/
diff --git a/src/libimcv/swima/swima_record.c b/src/libimcv/swima/swima_record.c
new file mode 100644 (file)
index 0000000..dc6a541
--- /dev/null
@@ -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;
+}
+
diff --git a/src/libimcv/swima/swima_record.h b/src/libimcv/swima/swima_record.h
new file mode 100644 (file)
index 0000000..c26ffdf
--- /dev/null
@@ -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_ @}*/