diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2017-06-26 18:07:53 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2017-07-08 23:19:51 +0200 |
commit | 74aa1626d22b86f3245f35d8566cbd18992ef424 (patch) | |
tree | 4ed9d5a3004e36e87c56357c50a3b6203571b681 | |
parent | 8ba6bf511e5955460f2179945848ba0b3bffe241 (diff) | |
download | strongswan-74aa1626d22b86f3245f35d8566cbd18992ef424.tar.bz2 strongswan-74aa1626d22b86f3245f35d8566cbd18992ef424.tar.xz |
sw-collector: Query central collector database
9 files changed, 601 insertions, 42 deletions
diff --git a/conf/options/sw-collector.opt b/conf/options/sw-collector.opt index ccd29771e..cf4ce362a 100644 --- a/conf/options/sw-collector.opt +++ b/conf/options/sw-collector.opt @@ -13,5 +13,17 @@ sw-collector.history = sw-collector.first_time = 0000-00-00T00:00:00Z Time in UTC when the Linux OS was installed. +sw-collector.rest_api.uri = + HTTP URI of the central collector's REST API. + +sw-collector.rest_api.timeout = 120 + Timeout of REST API HTTP POST transaction. + +sw-collector.tag_creator.name = strongSwan Project + Name of the tagCreator entity. + +sw-collector.tag_creator.regid = strongswan.org + regid of the tagCreator entity. + sw-collector.load = Plugins to load in sw-collector tool. diff --git a/src/libimcv/plugins/imc_swima/Makefile.am b/src/libimcv/plugins/imc_swima/Makefile.am index 67ea25e58..cde20980f 100644 --- a/src/libimcv/plugins/imc_swima/Makefile.am +++ b/src/libimcv/plugins/imc_swima/Makefile.am @@ -23,7 +23,7 @@ AM_CPPFLAGS = \ -DPLUGINS=\""random openssl sqlite curl"\" AM_CFLAGS = \ - $(PLUGIN_CFLAGS) + $(PLUGIN_CFLAGS) $(json_CFLAGS) imcv_LTLIBRARIES = imc-swima.la @@ -37,11 +37,14 @@ ipsec_PROGRAMS = sw-collector sw_collector_SOURCES = \ sw_collector/sw-collector.c \ sw_collector/sw_collector_db.h sw_collector/sw_collector_db.c \ - sw_collector/sw_collector_history.h sw_collector/sw_collector_history.c + sw_collector/sw_collector_history.h sw_collector/sw_collector_history.c \ + sw_collector/sw_collector_rest_api.h sw_collector/sw_collector_rest_api.c sw_collector_LDADD = \ - $(top_builddir)/src/libstrongswan/libstrongswan.la \ - $(top_builddir)/src/libimcv/libimcv.la + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(json_LIBS) + sw-collector.o : $(top_builddir)/config.status templatesdir = $(pkgdatadir)/templates/database/sw-collector diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw-collector.c b/src/libimcv/plugins/imc_swima/sw_collector/sw-collector.c index 24cf4fbe0..bb72349c7 100644 --- a/src/libimcv/plugins/imc_swima/sw_collector/sw-collector.c +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw-collector.c @@ -25,6 +25,7 @@ #include "sw_collector_db.h" #include "sw_collector_history.h" +#include "sw_collector_rest_api.h" #include <library.h> #include <utils/debug.h> @@ -41,7 +42,9 @@ typedef enum collector_op_t collector_op_t; enum collector_op_t { COLLECTOR_OP_EXTRACT, - COLLECTOR_OP_LIST + COLLECTOR_OP_LIST, + COLLECTOR_OP_UNREGISTERED, + COLLECTOR_OP_GENERATE }; /** @@ -108,6 +111,7 @@ static void usage(void) Usage:\n\ sw-collector --help\n\ sw-collector [--debug <level>] [--quiet] --list\n\ + sw-collector [--debug <level>] [--quiet] --unregistered|--generate\n\ sw-collector [--debug <level>] [--quiet] [--count <event count>]\n"); } @@ -129,12 +133,14 @@ static collector_op_t do_args(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "count", required_argument, NULL, 'c' }, { "debug", required_argument, NULL, 'd' }, + { "generate", no_argument, NULL, 'g' }, { "list", no_argument, NULL, 'l' }, { "quiet", no_argument, NULL, 'q' }, + { "unregistered", no_argument, NULL, 'u' }, { 0,0,0,0 } }; - c = getopt_long(argc, argv, "hc:d:lq", long_opts, NULL); + c = getopt_long(argc, argv, "hc:d:lqu", long_opts, NULL); switch (c) { case EOF: @@ -149,12 +155,18 @@ static collector_op_t do_args(int argc, char *argv[]) case 'd': debug_level = atoi(optarg); continue; + case 'g': + op = COLLECTOR_OP_GENERATE; + continue; case 'l': op = COLLECTOR_OP_LIST; continue; case 'q': stderr_quiet = TRUE; continue; + case 'u': + op = COLLECTOR_OP_UNREGISTERED; + continue; default: usage(); exit(EXIT_FAILURE); @@ -177,8 +189,8 @@ static int extract_history(sw_collector_db_t *db) bool skip = TRUE; /* open history file for reading */ - history_path= lib->settings->get_str(lib->settings, "sw-collector.history", - NULL); + history_path= lib->settings->get_str(lib->settings, "%s.history", NULL, + lib->ns); if (!history_path) { fprintf(stderr, "sw-collector.history path not set.\n"); @@ -308,7 +320,7 @@ end: } /** - * List all software identifiers stored in the collector database + * List all endpoint software identifiers stored in local collector database */ static int list_identifiers(sw_collector_db_t *db) { @@ -316,7 +328,7 @@ static int list_identifiers(sw_collector_db_t *db) char *name, *package, *version; uint32_t count = 0, installed_count = 0, installed; - e = db->create_sw_enumerator(db, FALSE); + e = db->create_sw_enumerator(db, SW_QUERY_ALL); if (!e) { return EXIT_FAILURE; @@ -337,6 +349,156 @@ static int list_identifiers(sw_collector_db_t *db) return EXIT_SUCCESS; } +static bool query_registry(sw_collector_rest_api_t *rest_api, bool installed) +{ + sw_collector_db_query_t type; + enumerator_t *enumerator; + char *sw_id; + int count = 0; + + type = installed ? SW_QUERY_INSTALLED : SW_QUERY_DELETED; + enumerator = rest_api->create_sw_enumerator(rest_api, type); + if (!enumerator) + { + return FALSE; + } + while (enumerator->enumerate(enumerator, &sw_id)) + { + printf("%s,%s\n", sw_id, installed ? "1" : "0"); + count++; + } + enumerator->destroy(enumerator); + DBG1(DBG_IMC, "%d %s software identifiers not registered", count, + installed ? "installed" : "deleted"); + return TRUE; +} + + +/** + * List all endpoint software identifiers stored in local collector database + * that are not registered yet in central collelector database + */ +static int unregistered_identifiers(sw_collector_db_t *db) +{ + sw_collector_rest_api_t *rest_api; + int status = EXIT_SUCCESS; + + rest_api = sw_collector_rest_api_create(db); + if (!rest_api) + { + return EXIT_FAILURE; + } + + /* List installed software identifiers not registered centrally */ + if (!query_registry(rest_api, TRUE)) + { + status = EXIT_FAILURE; + } + + /* List deleted software identifiers not registered centrally */ + if (!query_registry(rest_api, FALSE)) + { + status = EXIT_FAILURE; + } + rest_api->destroy(rest_api); + + return status; +} + +/** + * Generate a minimalistic ISO 19770-2:2015 SWID tag + */ +static char* generate_tag(char *name, char *package, char *version, + char* entity, char *regid, char *product) +{ + char *tag_id, *tag; + int res; + + tag_id = strstr(name, "__"); + if (!tag_id) + { + return NULL; + } + tag_id += 2; + + res = asprintf(&tag, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<SoftwareIdentity name=\"%s\" tagId=\"%s\" version=\"%s\" " + "versionScheme=\"alphanumeric\" " + "xmlns=\"http://standards.iso.org/iso/19770/-2/2015/schema.xsd\">" + "<Entity name=\"%s\" regid=\"%s\" role=\"tagCreator\"/>" + "<Meta product=\"%s\"/>" + "</SoftwareIdentity>", + package, tag_id, version, entity, regid, product); + + return (res == -1) ? NULL : tag; +} + +static int generate_tags(sw_collector_db_t *db) +{ + sw_collector_history_t *os_info; + sw_collector_rest_api_t *rest_api; + char *pos, *name, *package, *version, *entity, *regid, *product, *tag; + enumerator_t *enumerator; + uint32_t sw_id; + int status = EXIT_FAILURE; + + entity = lib->settings->get_str(lib->settings, "%s.tag_creator.name", + "strongSwan Project", lib->ns); + regid = lib->settings->get_str(lib->settings, "%s.tag_creator.regid", + "strongswan.org", lib->ns); + + os_info = sw_collector_history_create(db, 0); + if (!os_info) + { + return EXIT_FAILURE; + } + os_info->get_os(os_info, &product); + + rest_api = sw_collector_rest_api_create(db); + if (!rest_api) + { + goto end; + } + + enumerator = rest_api->create_sw_enumerator(rest_api, SW_QUERY_DELETED); + if (!enumerator) + { + goto end; + } + while (enumerator->enumerate(enumerator, &name)) + { + sw_id = db->get_sw_id(db, name, &package, &version, NULL, NULL); + if (sw_id) + { + /* Remove architecture from package name */ + pos = strchr(package, ':'); + if (pos) + { + *pos = '\0'; + } + tag = generate_tag(name, package, version, entity, regid, product); + if (tag) + { + printf("%s\n", tag); + free(tag); + count++; + } + free(package); + free(version); + } + } + enumerator->destroy(enumerator); + status = EXIT_SUCCESS; + DBG1(DBG_IMC, "%d tags for deleted unregistered software identifiers", + count); + +end: + os_info->destroy(os_info); + DESTROY_IF(rest_api); + + return status; +} + int main(int argc, char *argv[]) { sw_collector_db_t *db = NULL; @@ -362,13 +524,13 @@ int main(int argc, char *argv[]) /* load sw-collector plugins */ if (!lib->plugins->load(lib->plugins, - lib->settings->get_str(lib->settings, "sw-collector.load", PLUGINS))) + lib->settings->get_str(lib->settings, "%s.load", PLUGINS, lib->ns))) { exit(SS_RC_INITIALIZATION_FAILED); } /* connect to sw-collector database */ - uri = lib->settings->get_str(lib->settings, "sw-collector.database", NULL); + uri = lib->settings->get_str(lib->settings, "%s.database", NULL, lib->ns); if (!uri) { fprintf(stderr, "sw-collector.database URI not set.\n"); @@ -389,6 +551,11 @@ int main(int argc, char *argv[]) case COLLECTOR_OP_LIST: status = list_identifiers(db); break; + case COLLECTOR_OP_UNREGISTERED: + status = unregistered_identifiers(db); + break; + case COLLECTOR_OP_GENERATE: + status = generate_tags(db); default: break; } diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.c b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.c index e3c8b008e..62a650787 100644 --- a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.c +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.c @@ -108,8 +108,8 @@ METHOD(sw_collector_db_t, add_sw_event, bool, return TRUE; } -METHOD(sw_collector_db_t, get_sw_id, uint32_t, - private_sw_collector_db_t *this, char *package, char *version, char *name, +METHOD(sw_collector_db_t, set_sw_id, uint32_t, + private_sw_collector_db_t *this, char *name, char *package, char *version, uint8_t source, bool installed, bool check) { uint32_t sw_id = 0, status; @@ -179,22 +179,66 @@ METHOD(sw_collector_db_t, get_sw_id, uint32_t, return sw_id; } +METHOD(sw_collector_db_t, get_sw_id, uint32_t, + private_sw_collector_db_t *this, char *name, char **package, char **version, + uint8_t *source, bool *installed) +{ + char *sw_package, *sw_version; + uint32_t sw_id = 0, sw_source, sw_installed; + enumerator_t *e; + + /* Does software identifier already exist in database? */ + e = this->db->query(this->db, + "SELECT id, package, version, source, installed " + "FROM sw_identifiers WHERE name = ?", + DB_TEXT, name, DB_UINT, DB_TEXT, DB_TEXT, DB_UINT, DB_UINT); + if (!e) + { + DBG1(DBG_IMC, "database query for sw_identifier failed"); + return 0; + } + if (e->enumerate(e, &sw_id, &sw_package, &sw_version, &sw_source, + &sw_installed)) + { + if (package) + { + *package = strdup(sw_package); + } + if (version) + { + *version = strdup(sw_version); + } + if (source) + { + *source = sw_source; + } + if (installed) + { + *installed = sw_installed; + } + } + e->destroy(e); + + return sw_id; +} + METHOD(sw_collector_db_t, get_sw_id_count, uint32_t, - private_sw_collector_db_t *this, bool installed_only) + private_sw_collector_db_t *this, sw_collector_db_query_t type) { - uint32_t count; + uint32_t count, installed; enumerator_t *e; - if (installed_only) + if (type == SW_QUERY_ALL) { e = this->db->query(this->db, - "SELECT COUNT(installed) FROM sw_identifiers WHERE installed = 1 ", - DB_UINT); + "SELECT COUNT(installed) FROM sw_identifiers", DB_UINT); } else { + installed = (type == SW_QUERY_INSTALLED); e = this->db->query(this->db, - "SELECT COUNT(installed) FROM sw_identifiers", DB_UINT); + "SELECT COUNT(installed) FROM sw_identifiers WHERE installed = ?", + DB_UINT, installed, DB_UINT); } if (!e) @@ -212,22 +256,24 @@ METHOD(sw_collector_db_t, get_sw_id_count, uint32_t, } METHOD(sw_collector_db_t, create_sw_enumerator, enumerator_t*, - private_sw_collector_db_t *this, bool installed_only) + private_sw_collector_db_t *this, sw_collector_db_query_t type) { enumerator_t *e; + uint32_t installed; - if (installed_only) + if (type == SW_QUERY_ALL) { e = this->db->query(this->db, "SELECT name, package, version, installed FROM sw_identifiers " - "WHERE installed = 1 ORDER BY name ASC", - DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT); + "ORDER BY name ASC", DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT); } else { + installed = (type == SW_QUERY_INSTALLED); e = this->db->query(this->db, "SELECT name, package, version, installed FROM sw_identifiers " - "ORDER BY name ASC", DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT); + "WHERE installed = ? ORDER BY name ASC", + DB_UINT, installed, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT); } if (!e) { @@ -259,6 +305,7 @@ sw_collector_db_t *sw_collector_db_create(char *uri) .add_event = _add_event, .get_last_event = _get_last_event, .add_sw_event = _add_sw_event, + .set_sw_id = _set_sw_id, .get_sw_id = _get_sw_id, .get_sw_id_count = _get_sw_id_count, .create_sw_enumerator = _create_sw_enumerator, @@ -296,6 +343,9 @@ sw_collector_db_t *sw_collector_db_create(char *uri) } rng->destroy(rng); + /* strongTNC workaround - limit epoch to 31 bit unsigned integer */ + this->epoch &= 0x7fffffff; + /* Create first event when the OS was installed */ first_time = lib->settings->get_str(lib->settings, "sw-collector.first_time", "0000-00-00T00:00:00Z"); diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.h b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.h index de3138d8d..c4e82a990 100644 --- a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.h +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_db.h @@ -24,6 +24,16 @@ #include <library.h> typedef struct sw_collector_db_t sw_collector_db_t; +typedef enum sw_collector_db_query_t sw_collector_db_query_t; + +/** + * Type of software identifier queries + */ +enum sw_collector_db_query_t { + SW_QUERY_ALL, + SW_QUERY_INSTALLED, + SW_QUERY_DELETED +}; /** * Software collector database object @@ -31,7 +41,7 @@ typedef struct sw_collector_db_t sw_collector_db_t; struct sw_collector_db_t { /** - * Add event to database + * bAdd event to database * * @param timestamp Timestamp in 20 octet RFC 3339 format * @return Primary key pointing to event ID or 0 if failed @@ -61,35 +71,50 @@ struct sw_collector_db_t { uint8_t action); /** - * Get software_identifier, creating one if it doesn't exist yet + * Set software_identifier, checking if the identifier already exists * + * @param name Software identifier * @param package Software package * @param version Version of software package - * @param name Software identifier * @param source Source ID of the software collector * @param installed Installation status to be set, TRUE if installed * @param check Check if SW ID is already installed * @return Primary key pointing to SW ID or 0 if failed */ - uint32_t (*get_sw_id)(sw_collector_db_t *this, char *package, char *version, - char *name, uint8_t source, bool installed, bool check); + uint32_t (*set_sw_id)(sw_collector_db_t *this, char *name, char *package, + char *version, uint8_t source, bool installed, + bool check); + + /** + * Get software_identifier record + * + * @param name Software identifier + * @param package Software package + * @param version Version of software package + * @param source Source ID of the software collector + * @param installed Installation status + * @return Primary key pointing to SW ID or 0 if failed + */ + uint32_t (*get_sw_id)(sw_collector_db_t *this, char *name, char **package, + char **version, uint8_t *source, bool *installed); /** * Get number of installed or deleted software identifiers * - * @param installed_only Count installed SW IDs if TRUE - * @return Count + * @param type Query type (ALL, INSTALLED, DELETED) + * @return Count */ - uint32_t (*get_sw_id_count)(sw_collector_db_t *this, bool installed_only); + uint32_t (*get_sw_id_count)(sw_collector_db_t *this, + sw_collector_db_query_t type); /** * Enumerate over all collected [installed] software identities * - * @param installed_only Return only installed software identities - * @return Enumerator + * @param type Query type (ALL, INSTALLED, DELETED) + * @return Enumerator */ enumerator_t* (*create_sw_enumerator)(sw_collector_db_t *this, - bool installed_only); + sw_collector_db_query_t type); /** * Destroy sw_collector_db_t object diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.c b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.c index 4cca63729..9371285d4 100644 --- a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.c +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.c @@ -45,6 +45,11 @@ struct private_sw_collector_history_t { char *os; /** + * Product string 'name version arch' + */ + char *product; + + /** * OS info about endpoint */ imc_os_info_t *os_info; @@ -61,6 +66,16 @@ struct private_sw_collector_history_t { }; +METHOD(sw_collector_history_t, get_os, char*, + private_sw_collector_history_t *this, char **product) +{ + if (product) + { + *product = this->product; + } + return this->os; +} + /** * Define auxiliary package_t list item object */ @@ -277,7 +292,14 @@ METHOD(sw_collector_history_t, extract_packages, bool, goto end; } - sw_id = this->db->get_sw_id(this->db, p->package, p->version, p->sw_id, + /* packages without version information cannot be handled */ + if (strlen(p->version) == 0) + { + free_package(p); + continue; + } + + sw_id = this->db->set_sw_id(this->db, p->sw_id, p->package, p->version, this->source, op != SW_OP_REMOVE, FALSE); if (!sw_id) { @@ -291,8 +313,9 @@ METHOD(sw_collector_history_t, extract_packages, bool, if (op == SW_OP_UPGRADE) { - sw_id = this->db->get_sw_id(this->db, p->package, p->old_version, - p->old_sw_id, this->source, FALSE, FALSE); + sw_id = this->db->set_sw_id(this->db, p->old_sw_id, p->package, + p->old_version, this->source, FALSE, + FALSE); if (!sw_id) { goto end; @@ -376,7 +399,7 @@ METHOD(sw_collector_history_t, merge_installed_packages, bool, name = create_sw_id(this->tag_creator, this->os, package, version); DBG3(DBG_IMC, " %s merged", name); - sw_id = this->db->get_sw_id(this->db, package, version, name, + sw_id = this->db->set_sw_id(this->db, name, package, version, this->source, TRUE, TRUE); free(name); if (!sw_id) @@ -387,7 +410,7 @@ METHOD(sw_collector_history_t, merge_installed_packages, bool, } success = TRUE; DBG1(DBG_IMC, " merged %u installed packages, %u registed in database", - count, this->db->get_sw_id_count(this->db, TRUE)); + count, this->db->get_sw_id_count(this->db, SW_QUERY_INSTALLED)); end: pclose(file); @@ -399,6 +422,7 @@ METHOD(sw_collector_history_t, destroy, void, { this->os_info->destroy(this->os_info); free(this->os); + free(this->product); free(this); } @@ -414,6 +438,7 @@ sw_collector_history_t *sw_collector_history_create(sw_collector_db_t *db, INIT(this, .public = { + .get_os = _get_os, .extract_timestamp = _extract_timestamp, .extract_packages = _extract_packages, .merge_installed_packages = _merge_installed_packages, @@ -423,7 +448,7 @@ sw_collector_history_t *sw_collector_history_create(sw_collector_db_t *db, .source = source, .os_info = imc_os_info_create(), .tag_creator = lib->settings->get_str(lib->settings, - "sw-collector.tag_creator", "strongswan.org"), + "%s.tag_creator.regid", "strongswan.org", lib->ns), ); os_type = this->os_info->get_type(this->os_info); @@ -445,6 +470,8 @@ sw_collector_history_t *sw_collector_history_create(sw_collector_db_t *db, destroy(this); return NULL; } + + /* construct OS string */ if (asprintf(&this->os, "%.*s_%.*s-%.*s", os_name.len, os_name.ptr, os_version.len, os_version.ptr, os_arch.len, os_arch.ptr) == -1) @@ -454,5 +481,15 @@ sw_collector_history_t *sw_collector_history_create(sw_collector_db_t *db, return NULL; } + /* construct product string */ + if (asprintf(&this->product, "%.*s %.*s %.*s", os_name.len, os_name.ptr, + os_version.len, os_version.ptr, + os_arch.len, os_arch.ptr) == -1) + { + DBG1(DBG_IMC, "constructon of product string failed"); + destroy(this); + return NULL; + } + return &this->public; } diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.h b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.h index d6efcc5f9..d1a3b2130 100644 --- a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.h +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_history.h @@ -45,6 +45,14 @@ enum sw_collector_history_op_t { struct sw_collector_history_t { /** + * Get OS and product strings + * + * @param product Product string formed from OS info + * @return OS string formed from OS info + */ + char* (*get_os)(sw_collector_history_t *this, char **product); + + /** * Extract timestamp from event in installation history * * @param args Arguments to be processed diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.c b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.c new file mode 100644 index 000000000..15108a01c --- /dev/null +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2017 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "sw_collector_rest_api.h" + +#include <rest/rest.h> +#include <utils/debug.h> + +typedef struct private_sw_collector_rest_api_t private_sw_collector_rest_api_t; + +/** + * Private data of an sw_collector_rest_api_t object. + */ +struct private_sw_collector_rest_api_t { + + /** + * Public members of sw_collector_rest_api_state_t + */ + sw_collector_rest_api_t public; + + /** + * Software collector database + */ + sw_collector_db_t *db; + + /** + * REST API of central collector database + */ + rest_t *rest_api; + +}; + +/** + * Put all locally retrieved software identifiers into a json object + */ +static json_object* create_rest_request(private_sw_collector_rest_api_t *this, + sw_collector_db_query_t type) +{ + json_object *jrequest, *jarray, *jstring; + char *name, *package, *version; + uint32_t i; + enumerator_t *e; + + jrequest = json_object_new_object(); + jarray = json_object_new_array(); + json_object_object_add(jrequest, "data", jarray); + + e = this->db->create_sw_enumerator(this->db, type); + if (!e) + { + return NULL; + } + while (e->enumerate(e, &name, &package, &version, &i)) + { + jstring = json_object_new_string(name); + json_object_array_add(jarray, jstring); + } + e->destroy(e); + + return jrequest; +} + +typedef struct { + /** public enumerator interface */ + enumerator_t public; + /** enumerated json array */ + json_object *jarray; + /** current index +1, initialized at 0 */ + int idx; +} json_array_enumerator_t; + +METHOD(enumerator_t, enumerate, bool, + json_array_enumerator_t *this, va_list args) +{ + json_object *jvalue; + char **out; + + VA_ARGS_VGET(args, out); + + if (this->idx >= json_object_array_length(this->jarray)) + { + return FALSE; + } + + jvalue = json_object_array_get_idx(this->jarray, this->idx++); + if (json_object_get_type(jvalue) != json_type_string) + { + DBG1(DBG_IMC, "json_string element expected in json_array"); + return FALSE; + } + *out = (char*)json_object_get_string(jvalue); + + return TRUE; +} + +METHOD(enumerator_t, enumerator_destroy, void, + json_array_enumerator_t *this) +{ + json_object_put(this->jarray); + free(this); +} + +METHOD(sw_collector_rest_api_t, create_sw_enumerator, enumerator_t*, + private_sw_collector_rest_api_t *this, sw_collector_db_query_t type) +{ + json_array_enumerator_t *enumerator; + json_object *jrequest, *jresponse; + char cmd[BUF_LEN]; + status_t status; + + jrequest = create_rest_request(this, type); + if (!jrequest) + { + return NULL; + } + snprintf(cmd, BUF_LEN, "sessions/0/swid-measurement/"); + + status = this->rest_api->post(this->rest_api, cmd, jrequest, &jresponse); + json_object_put(jrequest); + + switch (status) + { + case SUCCESS: + case NOT_FOUND: + jresponse = json_object_new_array(); + break; + case NEED_MORE: + if (json_object_get_type(jresponse) != json_type_array) + { + DBG1(DBG_IMC, "REST response was not a json_array"); + json_object_put(jresponse); + return NULL; + } + break; + case FAILED: + default: + return NULL; + } + + INIT(enumerator, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate, + .destroy = _enumerator_destroy, + }, + .jarray = jresponse, + ); + + return &enumerator->public; +} + +METHOD(sw_collector_rest_api_t, destroy, void, + private_sw_collector_rest_api_t *this) +{ + this->rest_api->destroy(this->rest_api); + free(this); +} + +/** + * Described in header. + */ +sw_collector_rest_api_t *sw_collector_rest_api_create(sw_collector_db_t *db) +{ + private_sw_collector_rest_api_t *this; + int timeout; + char *uri; + + uri = lib->settings->get_str(lib->settings, "%s.rest_api.uri", NULL, + lib->ns); + timeout = lib->settings->get_int(lib->settings, "%s.rest_api.timeout", 120, + lib->ns); + if (!uri) + { + DBG1(DBG_IMC, "REST URI to central collector database not set"); + return NULL; + } + + INIT(this, + .public = { + .create_sw_enumerator = _create_sw_enumerator, + .destroy = _destroy, + }, + .db = db, + .rest_api = rest_create(uri, timeout), + ); + + return &this->public; +} diff --git a/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.h b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.h new file mode 100644 index 000000000..e44ab6d06 --- /dev/null +++ b/src/libimcv/plugins/imc_swima/sw_collector/sw_collector_rest_api.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sw_collector_rest_api_t sw_collector_rest_api + * @{ @ingroup imc_swima + */ + +#ifndef SW_COLLECTOR_REST_API_H_ +#define SW_COLLECTOR_REST_API_H_ + +#include "sw_collector_db.h" + +typedef struct sw_collector_rest_api_t sw_collector_rest_api_t; + +/** + * Software collector database object + */ +struct sw_collector_rest_api_t { + + /** + * List of locally stored software identifiers that are not registered + * in a central collector database + * + * @param type Query type (ALL, INSTALLED, DELETED) + * @return Enumerator + */ + enumerator_t* (*create_sw_enumerator)(sw_collector_rest_api_t *this, + sw_collector_db_query_t type); + + /** + * Destroy sw_collector_rest_api_t object + */ + void (*destroy)(sw_collector_rest_api_t *this); + +}; + +/** + * Create an sw_collector_rest_api_t instance + * + * @param db Software collector database to be used + */ +sw_collector_rest_api_t* sw_collector_rest_api_create(sw_collector_db_t *db); + +#endif /** SW_COLLECTOR_REST_API_H_ @}*/ |