summaryrefslogtreecommitdiff
path: root/src/libimcv/swima
diff options
context:
space:
mode:
Diffstat (limited to 'src/libimcv/swima')
-rw-r--r--src/libimcv/swima/swima_collector.c592
-rw-r--r--src/libimcv/swima/swima_collector.h68
-rw-r--r--src/libimcv/swima/swima_data_model.c28
-rw-r--r--src/libimcv/swima/swima_data_model.h38
-rw-r--r--src/libimcv/swima/swima_error.c77
-rw-r--r--src/libimcv/swima/swima_error.h43
-rw-r--r--src/libimcv/swima/swima_event.c124
-rw-r--r--src/libimcv/swima/swima_event.h87
-rw-r--r--src/libimcv/swima/swima_events.c155
-rw-r--r--src/libimcv/swima/swima_events.h106
-rw-r--r--src/libimcv/swima/swima_inventory.c140
-rw-r--r--src/libimcv/swima/swima_inventory.h99
-rw-r--r--src/libimcv/swima/swima_record.c174
-rw-r--r--src/libimcv/swima/swima_record.h115
14 files changed, 1846 insertions, 0 deletions
diff --git a/src/libimcv/swima/swima_collector.c b/src/libimcv/swima/swima_collector.c
new file mode 100644
index 000000000..096093b01
--- /dev/null
+++ b/src/libimcv/swima/swima_collector.c
@@ -0,0 +1,592 @@
+/*
+ * 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 <swid_gen/swid_gen.h>
+
+#include <collections/linked_list.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
+
+#ifndef SWID_DIRECTORY
+#define SWID_DIRECTORY NULL
+#endif
+
+/**
+ * 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;
+}
+
+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,
+ swima_inventory_t *targets, bool pretty, bool full)
+{
+ swid_gen_t *swid_gen;
+ swima_record_t *target, *sw_record;
+ enumerator_t *enumerator;
+ status_t status = SUCCESS;
+
+ swid_gen = swid_gen_create();
+
+ if (targets->get_count(targets) == 0)
+ {
+ chunk_t out, sw_id, swid_tag = chunk_empty;
+
+ DBG2(DBG_IMC, "SWID tag%s generation by package manager",
+ this->sw_id_only ? " ID" : "");
+
+ enumerator = swid_gen->create_tag_enumerator(swid_gen, this->sw_id_only,
+ full, pretty);
+ if (enumerator)
+ {
+ while (enumerator->enumerate(enumerator, &out))
+ {
+ if (this->sw_id_only)
+ {
+ sw_id = out;
+ }
+ else
+ {
+ swid_tag = out;
+ status = extract_sw_id(swid_tag, &sw_id);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IMC, "software id could not be extracted "
+ "from tag");
+ chunk_free(&swid_tag);
+ break;
+ }
+ }
+ sw_record = swima_record_create(0, sw_id, chunk_empty);
+ sw_record->set_source_id(sw_record, SOURCE_ID_GENERATOR);
+ if (!this->sw_id_only)
+ {
+ sw_record->set_record(sw_record, swid_tag);
+ chunk_free(&swid_tag);
+ }
+ this->inventory->add(this->inventory, sw_record);
+ chunk_free(&sw_id);
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ status = NOT_SUPPORTED;
+ }
+ }
+ else if (!this->sw_id_only)
+ {
+ DBG2(DBG_IMC, "targeted SWID tag generation");
+
+ enumerator = targets->create_enumerator(targets);
+ while (enumerator->enumerate(enumerator, &target))
+ {
+ swima_record_t *sw_record;
+ char *tag = NULL, *name, *package, *version;
+ u_int installed;
+ chunk_t sw_id;
+ enumerator_t *e;
+
+ sw_id = target->get_sw_id(target, NULL);
+ name = strndup(sw_id.ptr, sw_id.len);
+
+ if (this->db)
+ {
+ e = this->db->query(this->db,
+ "SELECT package, version, installed "
+ "FROM sw_identifiers WHERE name = ?", DB_TEXT, name,
+ DB_TEXT, DB_TEXT, DB_UINT);
+ if (!e)
+ {
+ DBG1(DBG_IMC, "database query for sw_identifiers failed");
+ status = FAILED;
+ free(name);
+ break;
+ }
+ if (e->enumerate(e, &package, &version, &installed))
+ {
+ tag = swid_gen->generate_tag(swid_gen, name, package,
+ version, full && installed, pretty);
+ }
+ e->destroy(e);
+ }
+ else
+ {
+ tag = swid_gen->generate_tag(swid_gen, name, NULL, NULL,
+ full, pretty);
+ }
+ free(name);
+
+ if (tag)
+ {
+ DBG2(DBG_IMC, " %.*s", sw_id.len, sw_id.ptr);
+ 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, chunk_from_str(tag));
+ this->inventory->add(this->inventory, sw_record);
+ free(tag);
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ swid_gen->destroy(swid_gen);
+
+ 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;
+
+ if (!pathname)
+ {
+ return TRUE;
+ }
+
+ 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))
+ {
+ DBG2(DBG_IMC, " %.*s", sw_id.len, sw_id.ptr);
+ 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)
+{
+ bool pretty, full;
+ char *directory;
+ status_t status;
+
+ directory = lib->settings->get_str(lib->settings,
+ "%s.plugins.imc-swima.swid_directory",
+ SWID_DIRECTORY, 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, targets, pretty, full);
+ }
+
+ /**
+ * Source 2: Collect swidtag files by iteratively entering all
+ * directories in the tree under the "directory" path.
+ */
+ DBG2(DBG_IMC, "SWID tag%s collection", sw_id_only ? " ID" : "");
+ 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
index 000000000..848dc1696
--- /dev/null
+++ b/src/libimcv/swima/swima_collector.h
@@ -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
index 000000000..f444724c1
--- /dev/null
+++ b/src/libimcv/swima/swima_data_model.c
@@ -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
index 000000000..40f0ba7b9
--- /dev/null
+++ b/src/libimcv/swima/swima_data_model.h
@@ -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
index 000000000..2aed2966b
--- /dev/null
+++ b/src/libimcv/swima/swima_error.c
@@ -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
index 000000000..4073b075f
--- /dev/null
+++ b/src/libimcv/swima/swima_error.h
@@ -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_swima
+ */
+
+#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
index 000000000..20cfa8da7
--- /dev/null
+++ b/src/libimcv/swima/swima_event.c
@@ -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
index 000000000..fe69d6aad
--- /dev/null
+++ b/src/libimcv/swima/swima_event.h
@@ -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
index 000000000..ba0810d5f
--- /dev/null
+++ b/src/libimcv/swima/swima_events.c
@@ -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
index 000000000..66bbedf7e
--- /dev/null
+++ b/src/libimcv/swima/swima_events.h
@@ -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
index 000000000..acb69b95d
--- /dev/null
+++ b/src/libimcv/swima/swima_inventory.c
@@ -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
index 000000000..21953bbd2
--- /dev/null
+++ b/src/libimcv/swima/swima_inventory.h
@@ -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
index 000000000..dc6a5413a
--- /dev/null
+++ b/src/libimcv/swima/swima_record.c
@@ -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
index 000000000..c26ffdf64
--- /dev/null
+++ b/src/libimcv/swima/swima_record.h
@@ -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_ @}*/