swid-gen: Share SWID generator between sw-collector, imc-swima and imc-swid
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 3 Aug 2017 07:00:59 +0000 (09:00 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 4 Aug 2017 17:15:26 +0000 (19:15 +0200)
15 files changed:
conf/options/imcv.opt
conf/options/sw-collector.opt
conf/plugins/imc-swid.opt
conf/plugins/imc-swima.opt
src/libimcv/Makefile.am
src/libimcv/plugins/imc_swid/imc_swid.c
src/libimcv/plugins/imv_swid/imv_swid_agent.c
src/libimcv/plugins/imv_swid/imv_swid_state.c
src/libimcv/swid/swid_inventory.c
src/libimcv/swid/swid_inventory.h
src/libimcv/swid_gen/swid_gen.c [new file with mode: 0644]
src/libimcv/swid_gen/swid_gen.h [new file with mode: 0644]
src/libimcv/swima/swima_collector.c
src/sw-collector/sw-collector.8.in
src/sw-collector/sw-collector.c

index 33ab74b..177781f 100644 (file)
@@ -21,6 +21,15 @@ charon.imcv.os_info.default_password_enabled = no
 charon.imcv.policy_script = ipsec _imv_policy
        Script called for each TNC connection to generate IMV policies.
 
+libimcv.swid_gen.command = /usr/local/bin/swid_generator
+       SWID generator command to be executed.
+
+libimcv.swid_gen.tag_creator.name = strongSwan Project
+       Name of the tagCreator entity.
+
+libimcv.swid_gen.tag_creator.regid = strongswan.org
+       regid of the tagCreator entity.
+
 libimcv.debug_level = 1
        Debug level for a stand-alone _libimcv_ library.
 
index 3cd714f..52baaba 100644 (file)
@@ -22,14 +22,5 @@ sw-collector.rest_api.uri =
 sw-collector.rest_api.timeout = 120
        Timeout of REST API HTTP POST transaction.
 
-sw-collector.tag_creator.name = strongSwan Project
-       Name of the tagCreator entity.
-
-sw-collector.tag_creator.regid = strongswan.org
-       regid of the tagCreator entity.
-
-sw-collector.swid_generator = /usr/local/bin/swid_generator
-       SWID generator command to be executed.
-
 sw-collector.load =
        Plugins to load in sw-collector tool.
index 74490c1..55e0e88 100644 (file)
@@ -1,9 +1,6 @@
 libimcv.plugins.imc-swid.swid_directory = ${prefix}/share
        Directory where SWID tags are located.
 
-libimcv.plugins.imc-swid.swid_generator = /usr/local/bin/swid_generator
-       SWID generator command to be executed.
-
 libimcv.plugins.imc-swid.swid_pretty = FALSE
        Generate XML-encoded SWID tags with pretty indentation.
 
index 73643f4..5dc3411 100644 (file)
@@ -9,9 +9,6 @@ libimcv.plugins.imc-swima.swid_epoch = 0x11223344
 libimcv.plugins.imc-swima.swid_directory = ${prefix}/share
        Directory where SWID tags are located.
 
-libimcv.plugins.imc-swima.swid_generator = /usr/local/bin/swid_generator
-       SWID generator command to be executed.
-
 libimcv.plugins.imc-swima.swid_pretty = FALSE
        Generate XML-encoded SWID tags with pretty indentation.
 
index dda0c2c..457a2f5 100644 (file)
@@ -100,6 +100,7 @@ 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 \
+       swid_gen/swid_gen.h swid_gen/swid_gen.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 \
@@ -214,6 +215,7 @@ imcv_tests_SOURCES = \
        pa_tnc/pa_tnc_attr_manager.c \
        seg/seg_env.c seg/seg_contract.c \
        seg/seg_contract_manager.c \
+       swid_gen/swid_gen.c \
        swima/swima_data_model.c \
        swima/swima_event.c \
        swima/swima_events.c \
index 0dcb9af..1468a59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Andreas Steffen
+ * Copyright (C) 2013-2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -30,8 +30,6 @@
 #include <pen/pen.h>
 #include <utils/debug.h>
 
-#define SWID_GENERATOR "/usr/local/bin/swid_generator"
-
 /* IMC definitions */
 
 static const char imc_name[] = "SWID";
@@ -165,7 +163,7 @@ static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
        pa_tnc_attr_t *attr, *attr_error;
        imc_swid_state_t *swid_state;
        swid_inventory_t *swid_inventory;
-       char *swid_directory, *swid_generator;
+       char *swid_directory;
        uint32_t eid_epoch;
        bool swid_pretty, swid_full;
        enumerator_t *enumerator;
@@ -173,9 +171,6 @@ static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
        swid_directory = lib->settings->get_str(lib->settings,
                                                                "%s.plugins.imc-swid.swid_directory",
                                                                 SWID_DIRECTORY, lib->ns);
-       swid_generator = lib->settings->get_str(lib->settings,
-                                                               "%s.plugins.imc-swid.swid_generator",
-                                                                SWID_GENERATOR, lib->ns);
        swid_pretty = lib->settings->get_bool(lib->settings,
                                                                "%s.plugins.imc-swid.swid_pretty",
                                                                 FALSE, lib->ns);
@@ -184,8 +179,8 @@ static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
                                                                 FALSE, lib->ns);
 
        swid_inventory = swid_inventory_create(full_tags);
-       if (!swid_inventory->collect(swid_inventory, swid_directory, swid_generator,
-                                                                targets, swid_pretty, swid_full))
+       if (!swid_inventory->collect(swid_inventory, swid_directory, targets,
+                                                                swid_pretty, swid_full))
        {
                swid_inventory->destroy(swid_inventory);
                attr_error = swid_error_create(TCG_SWID_ERROR, request_id,
index 09a387f..2884a16 100644 (file)
@@ -590,7 +590,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                                        DBG1(DBG_IMV, "  %s", target);
 
                                        /* Separate target into tag_creator and unique_sw_id */
-                                       separator = strchr(target, '_');
+                                       separator = strstr(target, "__");
                                        if (!separator)
                                        {
                                                error_str = "separation of regid from "
@@ -598,9 +598,9 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                                                break;
                                        }
                                        tag_creator = chunk_create(target, separator - target);
-                                       separator++;
+                                       separator += 2;
                                        unique_sw_id = chunk_create(separator, strlen(target) -
-                                                                                               tag_creator.len - 1);
+                                                                                               tag_creator.len - 2);
                                        tag_id = swid_tag_id_create(tag_creator, unique_sw_id,
                                                                                                chunk_empty);
                                        cast_attr = (tcg_swid_attr_req_t*)attr;
index fb9493a..2b270b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 Andreas Steffen
+ * Copyright (C) 2013-2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -288,8 +288,8 @@ METHOD(imv_swid_state_t, get_request_id, uint32_t,
 METHOD(imv_swid_state_t, set_swid_inventory, void,
     private_imv_swid_state_t *this, swid_inventory_t *inventory)
 {
-       chunk_t tag_creator, unique_sw_id;
-       char software_id[256];
+       chunk_t tag_creator, sw_id;
+       char software_id[BUF_LEN];
        json_object *jstring;
        swid_tag_id_t *tag_id;
        enumerator_t *enumerator;
@@ -299,10 +299,9 @@ METHOD(imv_swid_state_t, set_swid_inventory, void,
        {
                /* Construct software ID from tag creator and unique software ID */
                tag_creator = tag_id->get_tag_creator(tag_id);
-               unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
-               snprintf(software_id, 256, "%.*s_%.*s",
-                                tag_creator.len, tag_creator.ptr,
-                                unique_sw_id.len, unique_sw_id.ptr);
+               sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
+               snprintf(software_id, BUF_LEN, "%.*s__%.*s",
+                                tag_creator.len, tag_creator.ptr, sw_id.len, sw_id.ptr);
                DBG3(DBG_IMV, "  %s", software_id);
 
                /* Add software ID to JSON array */
index 7b05e83..4adbb39 100644 (file)
 #include "swid_inventory.h"
 #include "swid_tag.h"
 #include "swid_tag_id.h"
+#include "swid_gen/swid_gen.h"
 
 #include <collections/linked_list.h>
-#include <bio/bio_writer.h>
+#include <utils/lexparser.h>
 #include <utils/debug.h>
 
 #include <stdio.h>
@@ -52,186 +53,92 @@ struct private_swid_inventory_t {
        linked_list_t *list;
 };
 
-/**
- * Read SWID tags issued by the swid_generator tool
- */
-static status_t read_swid_tags(private_swid_inventory_t *this, FILE *file)
+static status_t generate_tags(private_swid_inventory_t *this,
+                                                         swid_inventory_t *targets, bool pretty, bool full)
 {
+       swid_gen_t *swid_gen;
        swid_tag_t *tag;
-       bio_writer_t *writer;
-       chunk_t tag_encoding, tag_file_path = chunk_empty;
-       bool more_tags = TRUE, last_newline;
-       char line[8192];
-       size_t len;
-
-       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));
-                       }
-               }
-
-               tag_encoding = writer->get_buf(writer);
-
-               if (tag_encoding.len > 1)
-               {
-                       /* remove trailing newline if present */
-                       if (tag_encoding.ptr[tag_encoding.len - 1] == '\n')
-                       {
-                               tag_encoding.len--;
-                       }
-                       DBG3(DBG_IMC, "  %.*s", tag_encoding.len, tag_encoding.ptr);
-
-                       tag = swid_tag_create(tag_encoding, tag_file_path);
-                       this->list->insert_last(this->list, tag);
-               }
-               writer->destroy(writer);
-       }
-
-       return SUCCESS;
-}
-
-/**
- * Read SWID tag or software IDs issued by the swid_generator tool
- */
-static status_t read_swid_tag_ids(private_swid_inventory_t *this, FILE *file)
-{
        swid_tag_id_t *tag_id;
-       chunk_t tag_creator, unique_sw_id, tag_file_path = chunk_empty;
-       char line[BUF_LEN];
-
-       while (TRUE)
-       {
-               char *separator;
-               size_t len;
-
-               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);
-
-               separator = strchr(line, '_');
-               if (!separator)
-               {
-                       DBG1(DBG_IMC, "separation of regid from unique software ID failed");
-                       return FAILED;
-               }
-               tag_creator = chunk_create(line, separator - line);
-               separator++;
-
-               unique_sw_id = chunk_create(separator, len - (separator - line));
-               tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
-               this->list->insert_last(this->list, tag_id);
-       }
-}
-
-static status_t generate_tags(private_swid_inventory_t *this, char *generator,
-                                                         swid_inventory_t *targets, bool pretty, bool full)
-{
-       FILE *file;
-       char command[BUF_LEN];
-       char doc_separator[] = "'\n\n'";
-
+       enumerator_t *enumerator;
        status_t status = SUCCESS;
+       chunk_t out;
+
+       swid_gen = swid_gen_create();
 
        if (targets->get_count(targets) == 0)
        {
-               /* Assemble the SWID generator command */
-               if (this->full_tags)
-               {
-                       snprintf(command, BUF_LEN, "%s swid --doc-separator %s%s%s",
-                                        generator, doc_separator, pretty ? " --pretty" : "",
-                                                                                          full   ? " --full"   : "");
-               }
-               else
-               {
-                       snprintf(command, BUF_LEN, "%s software-id", generator);
-               }
+               DBG2(DBG_IMC, "SWID tag%s generation by package manager",
+                                          this->full_tags ? "" : " ID");
 
-               /* Open a pipe stream for reading the SWID generator output */
-               file = popen(command, "r");
-               if (!file)
+               enumerator = swid_gen->create_tag_enumerator(swid_gen, !this->full_tags,
+                                                                                                        full, pretty);
+               if (enumerator)
                {
-                       DBG1(DBG_IMC, "failed to run swid_generator command");
-                       return NOT_SUPPORTED;
-               }
+                       while (enumerator->enumerate(enumerator, &out))
+                       {
+                               if (this->full_tags)
+                               {
+                                       chunk_t swid_tag = out;
 
-               if (this->full_tags)
-               {
-                       DBG2(DBG_IMC, "SWID tag generation by package manager");
-                       status = read_swid_tags(this, file);
+                                       tag = swid_tag_create(swid_tag, chunk_empty);
+                                       this->list->insert_last(this->list, tag);
+                               }
+                               else
+                               {
+                                       chunk_t tag_creator, sw_id = out;
+
+                                       if (extract_token_str(&tag_creator, "__", &sw_id))
+                                       {
+                                               tag_id = swid_tag_id_create(tag_creator, sw_id,
+                                                                                                       chunk_empty);
+                                               this->list->insert_last(this->list, tag_id);
+                                       }
+                                       else
+                                       {
+                                               DBG1(DBG_IMC, "separation of regid from unique "
+                                                                         "software ID failed");
+                                               status = FAILED;
+                                               chunk_free(&out);
+                                               break;
+                                       }
+                               }
+                               chunk_free(&out);
+                       }
+                       enumerator->destroy(enumerator);
                }
                else
                {
-                       DBG2(DBG_IMC, "SWID tag ID generation by package manager");
-                       status = read_swid_tag_ids(this, file);
+                       status = NOT_SUPPORTED;
                }
-               pclose(file);
        }
        else if (this->full_tags)
        {
-               swid_tag_id_t *tag_id;
-               enumerator_t *enumerator;
+               DBG2(DBG_IMC, "targeted SWID tag generation");
 
                enumerator = targets->create_enumerator(targets);
                while (enumerator->enumerate(enumerator, &tag_id))
                {
-                       char software_id[BUF_LEN];
-                       chunk_t tag_creator, unique_sw_id;
+                       char software_id[BUF_LEN], *swid_tag;
+                       chunk_t tag_creator, sw_id;
 
+                       /* Construct software ID from tag creator and unique software ID */
                        tag_creator  = tag_id->get_tag_creator(tag_id);
-                       unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
-                       snprintf(software_id, BUF_LEN, "%.*s_%.*s",
-                                        tag_creator.len, tag_creator.ptr,
-                                        unique_sw_id.len, unique_sw_id.ptr);
-
-                       /* Assemble the SWID generator command */
-                       snprintf(command, BUF_LEN, "%s swid --software-id %s%s%s",
-                                        generator, software_id, 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);
+                       sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
+                       snprintf(software_id, BUF_LEN, "%.*s__%.*s",
+                                        tag_creator.len, tag_creator.ptr, sw_id.len, sw_id.ptr);
 
-                       if (status != SUCCESS)
+                       swid_tag = swid_gen->generate_tag(swid_gen, software_id, NULL, NULL,
+                                                                                full, pretty);
+                       if (swid_tag)
                        {
-                               break;
+                               tag = swid_tag_create(chunk_from_str(swid_tag), chunk_empty);
+                               this->list->insert_last(this->list, tag);
+                               free(swid_tag);
                        }
                }
                enumerator->destroy(enumerator);
        }
+       swid_gen->destroy(swid_gen);
 
        return status;
 }
@@ -284,16 +191,16 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname,
                }
 
                /* parse the swidtag filename into its components */
-               separator = strchr(rel_name, '_');
+               separator = strstr(rel_name, "__");
                if (!separator)
                {
                        DBG1(DBG_IMC, "  %s", rel_name);
-                       DBG1(DBG_IMC, "  '_' separator not found");
+                       DBG1(DBG_IMC, "  '__' separator not found");
                        goto end;
                }
                tag_creator = chunk_create(rel_name, separator-rel_name);
 
-               unique_sw_id = chunk_create(separator+1, suffix-separator-1);
+               unique_sw_id = chunk_create(separator+2, suffix-separator-2);
                tag_file_path = chunk_from_str(abs_name);
 
                /* In case of a targeted request */
@@ -364,13 +271,13 @@ end:
 }
 
 METHOD(swid_inventory_t, collect, bool,
-       private_swid_inventory_t *this, char *directory, char *generator,
-       swid_inventory_t *targets, bool pretty, bool full)
+       private_swid_inventory_t *this, char *directory, swid_inventory_t *targets,
+       bool pretty, bool full)
 {
        /**
         * Tags are generated by a package manager
         */
-       generate_tags(this, generator, targets, pretty, full);
+       generate_tags(this, targets, pretty, full);
 
        /**
         * Collect swidtag files by iteratively entering all directories in
index 0402907..ba2518e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -37,13 +37,12 @@ struct swid_inventory_t {
         * Collect the SWID tags stored on the endpoint
         *
         * @param directory             SWID directory path
-        * @param generator             Path to SWID generator
         * @param targets               List of target tag IDs
         * @param pretty                Generate indented XML SWID tags
         * @param full                  Include file information in SWID tags
         * @return                              TRUE if successful
         */
-       bool (*collect)(swid_inventory_t *this, char *directory, char *generator,
+       bool (*collect)(swid_inventory_t *this, char *directory,
                                        swid_inventory_t *targets, bool pretty, bool full);
 
        /**
diff --git a/src/libimcv/swid_gen/swid_gen.c b/src/libimcv/swid_gen/swid_gen.c
new file mode 100644 (file)
index 0000000..206d41d
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2017 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "swid_gen.h"
+
+#include <bio/bio_writer.h>
+
+#define SWID_GENERATOR "/usr/local/bin/swid_generator"
+
+typedef struct private_swid_gen_t private_swid_gen_t;
+
+/**
+ * Private data of a swid_gen_t object.
+ *
+ */
+struct private_swid_gen_t {
+
+       /**
+        * Public swid_gen_t interface.
+        */
+       swid_gen_t public;
+
+       /**
+        * Path of the SWID generator command
+        */
+       char *generator;
+
+       /**
+        * Entity name of the tagCreator
+        */
+       char *entity;
+
+       /**
+        * Regid of the tagCreator
+        */
+       char *regid;
+
+};
+
+METHOD(swid_gen_t, generate_tag, char*,
+       private_swid_gen_t *this, char *sw_id, char *package, char *version,
+       bool full, bool pretty)
+{
+       char *tag = NULL;
+       size_t tag_buf_len = 8192;
+       char tag_buf[tag_buf_len], command[BUF_LEN];
+       bio_writer_t *writer;
+       chunk_t swid_tag;
+       FILE *file;
+
+       /* Compose the SWID generator command */
+       if (full || !package || !version)
+       { 
+               snprintf(command, BUF_LEN, "%s swid --entity-name \"%s\" "
+                                "--regid %s --software-id %s%s%s",
+                                this->generator, this->entity, this->regid, sw_id,
+                                full ? " --full" : "", pretty ? " --pretty" : "");
+       }
+       else
+       { 
+               snprintf(command, BUF_LEN, "%s swid --entity-name \"%s\" "
+                                "--regid %s --name %s --version-string %s%s",
+                                this->generator, this->entity, this->regid, package,
+                                version, pretty ? " --pretty" : "");
+       }
+
+       /* Open a pipe stream for reading the SWID generator output */
+       file = popen(command, "r");
+       if (file)
+       {
+               writer = bio_writer_create(tag_buf_len);
+               while (TRUE)
+               {
+                       if (!fgets(tag_buf, tag_buf_len, file))
+                       {
+                               break;
+                       }
+                       writer->write_data(writer, chunk_create(tag_buf, strlen(tag_buf)));
+               }
+               pclose(file);
+               swid_tag = writer->extract_buf(writer);
+               writer->destroy(writer);
+
+               if (swid_tag.len > 0)
+               {
+                       tag = swid_tag.ptr;
+                       tag[swid_tag.len - 1] = '\0';
+               }
+               else
+               {
+                       chunk_free(&swid_tag);
+               }
+       }
+       else
+       {
+               DBG1(DBG_IMC, "failed to run swid_generator command");
+       }
+
+       return tag;
+}
+
+typedef struct {
+       /** public enumerator interface */
+       enumerator_t public;
+       /** swid_generator output stream */
+       FILE *file;
+       /** generate software identifier only */
+       bool sw_id_only;
+} swid_gen_enumerator_t;
+
+METHOD(enumerator_t, enumerate, bool,
+       swid_gen_enumerator_t *this, va_list args)
+{
+       chunk_t *out;
+
+       VA_ARGS_VGET(args, out);
+
+       if (this->sw_id_only)
+       {
+               char line[BUF_LEN];
+               size_t len;
+
+               if (!fgets(line, sizeof(line), this->file))
+               {
+                       return FALSE;
+               }
+               len = strlen(line);
+
+               if (len == 0)
+               {
+                       return FALSE;
+               }
+
+               /* remove trailing newline if present */
+               if (line[len - 1] == '\n')
+               {
+                       len--;
+               }
+               DBG3(DBG_IMC, "  %.*s", len, line);
+               *out = chunk_clone(chunk_create(line, len));
+       }
+       else
+       {
+               bool last_newline = TRUE;
+               size_t len, line_len = 8192;
+               char line[line_len];
+               bio_writer_t *writer;
+               chunk_t swid_tag;
+
+               writer = bio_writer_create(line_len);
+               while (TRUE)
+               {
+                       if (!fgets(line, line_len, this->file))
+                       {
+                               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->extract_buf(writer);
+               writer->destroy(writer);
+
+               if (swid_tag.len <= 1)
+               {
+                       chunk_free(&swid_tag);
+                       return FALSE;
+               }
+
+               /* 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);
+               *out = swid_tag;
+       }
+
+       return TRUE;
+}
+
+METHOD(enumerator_t, enumerator_destroy, void,
+       swid_gen_enumerator_t *this)
+{
+       pclose(this->file);
+       free(this);
+}
+
+METHOD(swid_gen_t, create_tag_enumerator, enumerator_t*,
+       private_swid_gen_t *this, bool sw_id_only, bool full, bool pretty)
+{
+       swid_gen_enumerator_t *enumerator;
+       char command[BUF_LEN];
+       char doc_separator[] = "'\n\n'";
+       FILE *file;
+
+       /* Assemble the SWID generator command */
+       if (sw_id_only)
+       {
+               snprintf(command, BUF_LEN, "%s software-id --regid %s ",
+                                this->generator, this->regid);
+       }
+       else
+       {
+               snprintf(command, BUF_LEN, "%s swid --entity-name \"%s\" --regid %s "
+                                "--doc-separator %s%s%s", this->generator, this->entity,
+                                this->regid, 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 NULL;
+       }
+
+       INIT(enumerator,
+               .public = {
+                       .enumerate = enumerator_enumerate_default,
+                       .venumerate = _enumerate,
+                       .destroy = _enumerator_destroy,
+               },
+               .sw_id_only = sw_id_only,
+               .file = file,
+       );
+
+       return &enumerator->public;
+}
+
+METHOD(swid_gen_t, destroy, void,
+       private_swid_gen_t *this)
+{
+       free(this->generator);
+       free(this->entity);
+       free(this->regid);
+       free(this);
+}
+
+/**
+ * See header
+ */
+swid_gen_t *swid_gen_create(void)
+{
+       private_swid_gen_t *this;
+       char *entity, *regid, *generator;
+
+       entity = lib->settings->get_str(lib->settings,
+                               "libimcv.swid_gen.tag_creator.name", "strongSwan Project");
+       regid  = lib->settings->get_str(lib->settings,
+                               "libimcv.swid_gen.tag_creator.regid", "strongswan.org");
+       generator = lib->settings->get_str(lib->settings,
+                               "libimcv.swid_gen.command", SWID_GENERATOR);
+
+       INIT(this,
+               .public = {
+                       .generate_tag = _generate_tag,
+                       .create_tag_enumerator = _create_tag_enumerator,
+                       .destroy = _destroy,
+               },
+               .generator = strdup(generator),
+               .entity = strdup(entity),
+               .regid = strdup(regid),
+       );
+
+       return &this->public;
+}
diff --git a/src/libimcv/swid_gen/swid_gen.h b/src/libimcv/swid_gen/swid_gen.h
new file mode 100644 (file)
index 0000000..06ca0a3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 swid_gen swid_gen
+ * @{ @ingroup libimcv
+ */
+
+#ifndef SWID_GEN_H_
+#define SWID_GEN_H_
+
+#include <library.h>
+
+typedef struct swid_gen_t swid_gen_t;
+
+/**
+ * Class generating a either a full or a minimalistic ISO 19770-2:2015 SWID tag
+ */
+struct swid_gen_t {
+
+       /**
+        * Generate a SWID tag
+        *
+        * @param sw_id                 Software identifier
+        * @param package               Package name (can be NULL)
+        * @param version               Package version (can be NULL)
+        * @param full                  Generate full SWID tags with file information
+        * @param pretty                Generate SWID tags with pretty formating
+        * @return                              SWID tag
+        */
+       char* (*generate_tag)(swid_gen_t *this, char *sw_id, char *package,
+                                                 char *version, bool full, bool pretty);
+
+       /**
+        * Generate a SWID tag
+        *
+        * @param sw_id_only    Return software identifier only
+        * @param full                  Generate full SWID tags with file information
+        * @param pretty                Generate SWID tags with pretty formating
+        * @return                              Tag enumerator (sw_id, tag)
+        */
+       enumerator_t* (*create_tag_enumerator)(swid_gen_t *this, bool sw_id_only,
+                                                                                  bool full, bool pretty);
+
+       /**
+        * Destroys a swid_gen_t object.
+        */
+       void (*destroy)(swid_gen_t *this);
+
+};
+
+/**
+ * Creates a swid_gen_t object
+ */
+swid_gen_t* swid_gen_create(void);
+
+#endif /** SWID_GEN_H_ @}*/
index 0fd3d14..096093b 100644 (file)
@@ -15,8 +15,9 @@
 
 #include "swima_collector.h"
 
+#include <swid_gen/swid_gen.h>
+
 #include <collections/linked_list.h>
-#include <bio/bio_writer.h>
 #include <utils/debug.h>
 
 #include <stdio.h>
@@ -33,8 +34,6 @@
 #define SWID_DIRECTORY NULL
 #endif
 
-#define SWID_GENERATOR "/usr/local/bin/swid_generator"
-
 /**
  * Directories to be skipped by collector
  */
@@ -133,104 +132,6 @@ end:
        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)
 {
@@ -299,82 +200,118 @@ static status_t retrieve_events(private_swima_collector_t *this,
        return SUCCESS;
 }
 
-static status_t generate_tags(private_swima_collector_t *this, char *generator,
-                                                       swima_inventory_t *targets, bool pretty, bool full)
+static status_t generate_tags(private_swima_collector_t *this,
+                                                         swima_inventory_t *targets, bool pretty, bool full)
 {
-       FILE *file;
-       char command[BUF_LEN];
-       char doc_separator[] = "'\n\n'";
-
+       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)
        {
-               /* 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"   : "");
-               }
+               chunk_t out, sw_id, swid_tag = chunk_empty;
 
-               /* 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;
-               }
+               DBG2(DBG_IMC, "SWID tag%s generation by package manager",
+                                          this->sw_id_only ? " ID" : "");
 
-               if (this->sw_id_only)
+               enumerator = swid_gen->create_tag_enumerator(swid_gen, this->sw_id_only,
+                                                                                                        full, pretty);
+               if (enumerator)
                {
-                       DBG2(DBG_IMC, "SWID tag ID generation by package manager");
-                       status = read_swid_tag_ids(this, file);
+                       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
                {
-                       DBG2(DBG_IMC, "SWID tag generation by package manager");
-                       status = read_swid_tags(this, file);
+                       status = NOT_SUPPORTED;
                }
-               pclose(file);
        }
        else if (!this->sw_id_only)
        {
-               swima_record_t *target;
-               enumerator_t *enumerator;
-               chunk_t sw_id;
+               DBG2(DBG_IMC, "targeted SWID tag generation");
 
                enumerator = targets->create_enumerator(targets);
                while (enumerator->enumerate(enumerator, &target))
                {
-                       sw_id = target->get_sw_id(target, NULL);
+                       swima_record_t *sw_record;
+                       char *tag = NULL, *name, *package, *version;
+                       u_int installed;
+                       chunk_t sw_id;
+                       enumerator_t *e;
 
-                       /* 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" : "");
+                       sw_id = target->get_sw_id(target, NULL);
+                       name = strndup(sw_id.ptr, sw_id.len);
 
-                       /* Open a pipe stream for reading the SWID generator output */
-                       file = popen(command, "r");
-                       if (!file)
+                       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
                        {
-                               DBG1(DBG_IMC, "failed to run swid_generator command");
-                               return NOT_SUPPORTED;
+                               tag = swid_gen->generate_tag(swid_gen, name, NULL, NULL,
+                                                                                        full, pretty);
                        }
-                       status = read_swid_tags(this, file);
-                       pclose(file);
+                       free(name);
 
-                       if (status != SUCCESS)
+                       if (tag)
                        {
-                               break;
+                               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;
 }
@@ -480,6 +417,7 @@ static bool collect_tags(private_swima_collector_t *this, char *pathname,
                        {
                                if (chunk_equals(target->get_sw_id(target, NULL), sw_id))
                                {
+                                       DBG2(DBG_IMC, "  %.*s", sw_id.len, sw_id.ptr);
                                        match = TRUE;
                                        break;
                                }
@@ -518,16 +456,13 @@ end:
 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;
+       char *directory;
        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);
@@ -550,13 +485,14 @@ METHOD(swima_collector_t, collect_inventory, swima_inventory_t*,
        }
        else
        {
-               status = generate_tags(this, generator, targets, pretty, full);
+               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;
index da713cd..8560ba0 100644 (file)
@@ -99,9 +99,18 @@ The following parameters can be configured in strongswan.conf:
        uri = https://admin-user:ietf99hackathon@tnc.strongswan.org/api/
        timeout = 120
     }
-    tag_creator {
-       name = strongSwan Project
-       regid = strongswan.org
+ }
+.P
+The parameters of the swid_generator used with the \-\-generate command can
+be changed in the libimcv section of strongswan.conf:
+.P
+ libimcv {
+    swid_gen {
+       command = /usr/local/bin/swid_generator
+       tag_creator {
+          name = strongSwan Project
+          regid = strongswan.org
+       }
     }
  }
 .
index 0bdd598..e08f948 100644 (file)
 #include "sw_collector_dpkg.h"
 #
 #include <library.h>
-#include <bio/bio_writer.h>
 #include <utils/debug.h>
 #include <utils/lexparser.h>
 
 #include <imv/imv_os_info.h>
-
-#define SWID_GENERATOR "/usr/local/bin/swid_generator"
+#include <swid_gen/swid_gen.h>
 
 /**
  * global debug output variables
@@ -470,105 +468,21 @@ static int unregistered_identifiers(sw_collector_db_t *db,
 }
 
 /**
- * Generate a either a full or a minimalistic ISO 19770-2:2015 SWID tag
- */
-static char* generate_tag(char *name, char *package, char *version,
-                                                 char* entity, char *regid, char *product,
-                                                 bool full_tag, char *generator)
-{
-       char *tag = NULL;
-
-       if (full_tag)
-       {
-               size_t tag_buf_len = 8192;
-               char tag_buf[tag_buf_len], command[BUF_LEN];
-               bio_writer_t *writer;
-               chunk_t tag_chunk;
-               FILE *file;
-
-               /* Compose the SWID generator command */
-               snprintf(command, BUF_LEN, "%s swid --full --regid %s --entity-name "
-                                "\"%s\" --package %s", generator, regid, entity, package);
-\
-               /* Open a pipe stream for reading the SWID generator output */
-               file = popen(command, "r");
-               if (file)
-               {
-                       writer = bio_writer_create(tag_buf_len);
-                       while (TRUE)
-                       {
-                               if (!fgets(tag_buf, tag_buf_len, file))
-                               {
-                                       break;
-                               }
-                               writer->write_data(writer,
-                                                                  chunk_create(tag_buf, strlen(tag_buf)));
-                       }
-                       pclose(file);
-                       tag_chunk = writer->extract_buf(writer);
-                       writer->destroy(writer);
-                       if (tag_chunk.len > 1)
-                       {
-                               tag = tag_chunk.ptr;
-                               tag[tag_chunk.len - 1] = '\0';
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_IMC, "failed to run swid_generator command");
-               }
-       }
-
-       /* Generate minimalistic SWID tag */
-       if (!tag)
-       {
-               char *tag_id;
-
-               tag_id = strstr(name, "__");
-               if (!tag_id)
-               {
-                       return NULL;
-               }
-               tag_id += 2;
-
-               if (asprintf(&tag, "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
-                       "<SoftwareIdentity name=\"%s\" tagId=\"%s\" version=\"%s\" "
-                       "versionScheme=\"alphanumeric\" "
-                       "xmlns=\"http://standards.iso.org/iso/19770/-2/2015/schema.xsd\">"
-                       "<Entity name=\"%s\" regid=\"%s\" role=\"tagCreator\"/>"
-                       "<Meta product=\"%s\"/>"
-                       "</SoftwareIdentity>",
-                        package, tag_id, version, entity, regid, product) == -1)
-               {
-                       tag = NULL;
-               }
-       }
-
-       return tag;
-}
-
-/**
- * Generate a minimalistic ISO 19770-2:2015 SWID tag for
- * all removed SW identifiers that are not registered centrally
+ * Generate ISO 19770-2:2015 SWID tags for [installed|removed|all]
+ * SW identifiers that are not registered centrally
  */
 static int generate_tags(sw_collector_info_t *info, sw_collector_db_t *db,
                                                 bool full_tags, sw_collector_db_query_t type)
 {
+       swid_gen_t * swid_gen;
        sw_collector_rest_api_t *rest_api;
-       char *name, *package, *version, *entity, *regid, *product, *generator, *tag;
+       char *name, *package, *version, *tag;
        enumerator_t *enumerator;
        uint32_t sw_id;
        bool installed;
        int count = 0, installed_count = 0, status = EXIT_FAILURE;
 
-       entity = lib->settings->get_str(lib->settings, "%s.tag_creator.name",
-                                                                       "strongSwan Project", lib->ns);
-       regid  = lib->settings->get_str(lib->settings, "%s.tag_creator.regid",
-                                                                       "strongswan.org", lib->ns);
-       generator = lib->settings->get_str(lib->settings, "%s.swid_generator",
-                                                                       SWID_GENERATOR, lib->ns);
-       info->get_os(info, &product);
-
+       swid_gen = swid_gen_create();
        rest_api = sw_collector_rest_api_create(db);
        if (!rest_api)
        {
@@ -585,8 +499,8 @@ static int generate_tags(sw_collector_info_t *info, sw_collector_db_t *db,
                sw_id = db->get_sw_id(db, name, &package, &version, NULL, &installed);
                if (sw_id)
                {
-                       tag = generate_tag(name, package, version, entity, regid, product,
-                                                          full_tags && installed, generator);
+                       tag = swid_gen->generate_tag(swid_gen, name, package, version,
+                                                                                full_tags && installed, FALSE);
                        if (tag)
                        {
                                DBG2(DBG_IMC, "  creating %s", name);
@@ -623,6 +537,7 @@ static int generate_tags(sw_collector_info_t *info, sw_collector_db_t *db,
        }
 
 end:
+       swid_gen->destroy(swid_gen);
        DESTROY_IF(rest_api);
 
        return status;