diff --git a/conf/options/imcv.opt b/conf/options/imcv.opt index 33ab74bd5..177781ff7 100644 --- a/conf/options/imcv.opt +++ b/conf/options/imcv.opt @@ -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. diff --git a/conf/options/sw-collector.opt b/conf/options/sw-collector.opt index 3cd714f51..52baaba73 100644 --- a/conf/options/sw-collector.opt +++ b/conf/options/sw-collector.opt @@ -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. diff --git a/conf/plugins/imc-swid.opt b/conf/plugins/imc-swid.opt index 74490c179..55e0e880e 100644 --- a/conf/plugins/imc-swid.opt +++ b/conf/plugins/imc-swid.opt @@ -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. diff --git a/conf/plugins/imc-swima.opt b/conf/plugins/imc-swima.opt index 73643f4ba..5dc3411e8 100644 --- a/conf/plugins/imc-swima.opt +++ b/conf/plugins/imc-swima.opt @@ -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. diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index dda0c2cd8..457a2f5a7 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -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 \ diff --git a/src/libimcv/plugins/imc_swid/imc_swid.c b/src/libimcv/plugins/imc_swid/imc_swid.c index 0dcb9afb6..1468a59cc 100644 --- a/src/libimcv/plugins/imc_swid/imc_swid.c +++ b/src/libimcv/plugins/imc_swid/imc_swid.c @@ -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 #include -#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, diff --git a/src/libimcv/plugins/imv_swid/imv_swid_agent.c b/src/libimcv/plugins/imv_swid/imv_swid_agent.c index 09a387fd3..2884a169c 100644 --- a/src/libimcv/plugins/imv_swid/imv_swid_agent.c +++ b/src/libimcv/plugins/imv_swid/imv_swid_agent.c @@ -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; diff --git a/src/libimcv/plugins/imv_swid/imv_swid_state.c b/src/libimcv/plugins/imv_swid/imv_swid_state.c index fb9493a83..2b270b880 100644 --- a/src/libimcv/plugins/imv_swid/imv_swid_state.c +++ b/src/libimcv/plugins/imv_swid/imv_swid_state.c @@ -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 */ diff --git a/src/libimcv/swid/swid_inventory.c b/src/libimcv/swid/swid_inventory.c index 7b05e8393..4adbb39b4 100644 --- a/src/libimcv/swid/swid_inventory.c +++ b/src/libimcv/swid/swid_inventory.c @@ -16,9 +16,10 @@ #include "swid_inventory.h" #include "swid_tag.h" #include "swid_tag_id.h" +#include "swid_gen/swid_gen.h" #include -#include +#include #include #include @@ -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) -{ - 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, +static status_t generate_tags(private_swid_inventory_t *this, swid_inventory_t *targets, bool pretty, bool full) { - FILE *file; - char command[BUF_LEN]; - char doc_separator[] = "'\n\n'"; - + swid_gen_t *swid_gen; + swid_tag_t *tag; + swid_tag_id_t *tag_id; + 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) + DBG2(DBG_IMC, "SWID tag%s generation by package manager", + this->full_tags ? "" : " ID"); + + enumerator = swid_gen->create_tag_enumerator(swid_gen, !this->full_tags, + full, pretty); + if (enumerator) { - snprintf(command, BUF_LEN, "%s swid --doc-separator %s%s%s", - generator, doc_separator, pretty ? " --pretty" : "", - full ? " --full" : ""); + while (enumerator->enumerate(enumerator, &out)) + { + if (this->full_tags) + { + chunk_t swid_tag = out; + + 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 { - snprintf(command, BUF_LEN, "%s software-id", generator); + status = NOT_SUPPORTED; } - - /* Open a pipe stream for reading the SWID generator output */ - file = popen(command, "r"); - if (!file) - { - DBG1(DBG_IMC, "failed to run swid_generator command"); - return NOT_SUPPORTED; - } - - if (this->full_tags) - { - DBG2(DBG_IMC, "SWID tag generation by package manager"); - status = read_swid_tags(this, file); - } - else - { - DBG2(DBG_IMC, "SWID tag ID generation by package manager"); - status = read_swid_tag_ids(this, file); - } - 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); + 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); - /* 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) + swid_tag = swid_gen->generate_tag(swid_gen, software_id, NULL, NULL, + full, pretty); + if (swid_tag) { - DBG1(DBG_IMC, "failed to run swid_generator command"); - return NOT_SUPPORTED; - } - status = read_swid_tags(this, file); - pclose(file); - - if (status != SUCCESS) - { - 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 diff --git a/src/libimcv/swid/swid_inventory.h b/src/libimcv/swid/swid_inventory.h index 04029070e..ba2518e26 100644 --- a/src/libimcv/swid/swid_inventory.h +++ b/src/libimcv/swid/swid_inventory.h @@ -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 index 000000000..206d41d11 --- /dev/null +++ b/src/libimcv/swid_gen/swid_gen.c @@ -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 . + * + * 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 + +#include "swid_gen.h" + +#include + +#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 index 000000000..06ca0a341 --- /dev/null +++ b/src/libimcv/swid_gen/swid_gen.h @@ -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 . + * + * 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 + +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_ @}*/ diff --git a/src/libimcv/swima/swima_collector.c b/src/libimcv/swima/swima_collector.c index 0fd3d14b3..096093b01 100644 --- a/src/libimcv/swima/swima_collector.c +++ b/src/libimcv/swima/swima_collector.c @@ -15,8 +15,9 @@ #include "swima_collector.h" +#include + #include -#include #include #include @@ -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) + 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) { - snprintf(command, BUF_LEN, "%s software-id", generator); + 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 { - snprintf(command, BUF_LEN, "%s swid --doc-separator %s%s%s", - generator, doc_separator, pretty ? " --pretty" : "", - full ? " --full" : ""); + status = NOT_SUPPORTED; } - - /* Open a pipe stream for reading the SWID generator output */ - file = popen(command, "r"); - if (!file) - { - DBG1(DBG_IMC, "failed to run swid_generator command"); - return NOT_SUPPORTED; - } - - if (this->sw_id_only) - { - DBG2(DBG_IMC, "SWID tag ID generation by package manager"); - status = read_swid_tag_ids(this, file); - } - else - { - DBG2(DBG_IMC, "SWID tag generation by package manager"); - status = read_swid_tags(this, file); - } - pclose(file); } else if (!this->sw_id_only) { - swima_record_t *target; - enumerator_t *enumerator; - chunk_t sw_id; + 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); - /* Assemble the SWID generator command */ - snprintf(command, BUF_LEN, "%s swid --software-id %.*s%s%s", - generator, sw_id.len, sw_id.ptr, - pretty ? " --pretty" : "", full ? " --full" : ""); - - /* Open a pipe stream for reading the SWID generator output */ - file = popen(command, "r"); - if (!file) + if (this->db) { - DBG1(DBG_IMC, "failed to run swid_generator command"); - return NOT_SUPPORTED; + 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); } - status = read_swid_tags(this, file); - pclose(file); - - if (status != SUCCESS) + else { - break; + 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; } @@ -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; diff --git a/src/sw-collector/sw-collector.8.in b/src/sw-collector/sw-collector.8.in index da713cd36..8560ba095 100644 --- a/src/sw-collector/sw-collector.8.in +++ b/src/sw-collector/sw-collector.8.in @@ -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 + } } } . diff --git a/src/sw-collector/sw-collector.c b/src/sw-collector/sw-collector.c index 0bdd59813..e08f94868 100644 --- a/src/sw-collector/sw-collector.c +++ b/src/sw-collector/sw-collector.c @@ -30,13 +30,11 @@ #include "sw_collector_dpkg.h" # #include -#include #include #include #include - -#define SWID_GENERATOR "/usr/local/bin/swid_generator" +#include /** * 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, "" - "" - "" - "" - "", - 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;