diff --git a/.github/workflows/ci-c.yml b/.github/workflows/ci-c.yml index 511f2974b..ca216f94a 100644 --- a/.github/workflows/ci-c.yml +++ b/.github/workflows/ci-c.yml @@ -2,9 +2,9 @@ name: Build and test C on: push: - branches: [ master, gvm-libs-20.08, gvm-libs-21.04 ] + branches: [ master, gvm-libs-20.08, gvm-libs-21.04, middleware ] pull_request: - branches: [ master, gvm-libs-20.08, gvm-libs-21.04 ] + branches: [ master, gvm-libs-20.08, gvm-libs-21.04, middleware ] jobs: diff --git a/.github/workflows/codeql-analysis-c.yml b/.github/workflows/codeql-analysis-c.yml index 442542ce3..3aa1d35d8 100644 --- a/.github/workflows/codeql-analysis-c.yml +++ b/.github/workflows/codeql-analysis-c.yml @@ -2,9 +2,9 @@ name: "CodeQL" on: push: - branches: [ master, gvm-libs-20.08, gvm-libs-21.04 ] + branches: [ master, gvm-libs-20.08, gvm-libs-21.04, middleware ] pull_request: - branches: [ master, gvm-libs-20.08, gvm-libs-21.04 ] + branches: [ master, gvm-libs-20.08, gvm-libs-21.04, middleware ] paths-ignore: - '**/*.md' - '**/*.txt' diff --git a/CHANGELOG.md b/CHANGELOG.md index 02f72b920..e83925c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Possibility to use lcrypt with `$6$` (sha512) for authentication [484](https://github.com/greenbone/gvm-libs/pull/484) - Add function to perform an alive test and get the amount of alive hosts. [495](https://github.com/greenbone/gvm-libs/pull/495) - Add functions for sentry integration. [#502](https://github.com/greenbone/gvm-libs/pull/502) [#506](https://github.com/greenbone/gvm-libs/pull/506) +- Add basic support for mqtt. + Original + [#505](https://github.com/greenbone/gvm-libs/pull/505) + [#511](https://github.com/greenbone/gvm-libs/pull/511). + Reintroduction after Rebase + [#538](https://github.com/greenbone/gvm-libs/pull/538) + ### Changed ### Fixed diff --git a/INSTALL.md b/INSTALL.md index 9d0db60e4..57753e400 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -71,6 +71,8 @@ Install prerequisites for optional features on Debian GNU/Linux 'Buster' 10: libldap2-dev \ libradcli-dev +Prerequisites for MQTT support: +* libpaho-mqtt-dev >= 1.3.8. This package is currently not available in debian buster stable. Could be installed from source, backports or unstable branch. Compiling gvm-libs ------------------ diff --git a/base/hosts.c b/base/hosts.c index dd00efddb..b252b6b93 100644 --- a/base/hosts.c +++ b/base/hosts.c @@ -958,7 +958,7 @@ gvm_hosts_add (gvm_hosts_t *hosts, gvm_host_t *host) hosts->hosts = g_realloc_n (hosts->hosts, hosts->max_size, sizeof (*hosts->hosts)); memset (hosts->hosts + hosts->count, '\0', - (hosts->max_size - hosts->count) * sizeof (gvm_host_t*)); + (hosts->max_size - hosts->count) * sizeof (gvm_host_t *)); } hosts->hosts[hosts->count] = host; hosts->count++; diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index d4b9d6ee4..3c460d93e 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -50,6 +50,17 @@ pkg_check_modules (REDIS REQUIRED hiredis>=0.10.1) # for fast XML we need libxml2 pkg_check_modules (LIBXML2 REQUIRED libxml-2.0>=2.0) +# for mqtt +# Optional for now because lib is currently not in debian buster stable. +find_library(LIBPAHO paho-mqtt3c) +message (STATUS "Looking for paho-mqtt3c ... ${LIBPAHO}") +if (NOT LIBPAHO) + message (STATUS "libpaho-mqtt3c is required for MQTTv5 support.") +else (LIBPAHO) + set (LIBPAHO_LDFLAGS "paho-mqtt3c") + add_definitions (-DHAVE_MQTT=1) +endif (NOT LIBPAHO) + #for gpgmeutils we need libgpgme set (GPGME_MIN_VERSION "1.7.0") message (STATUS "Looking for gpgme...") @@ -156,11 +167,11 @@ include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE ${LIBXML2_INCLUDE_DIRS}) set (FILES passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c - nvticache.c radiusutils.c serverutils.c sshutils.c uuidutils.c + nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c xmlutils.c) set (HEADERS passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h - ldaputils.h nvticache.h radiusutils.h serverutils.h sshutils.h + ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h uuidutils.h xmlutils.h) if (BUILD_STATIC) @@ -178,7 +189,7 @@ if (BUILD_SHARED) set_target_properties (gvm_util_shared PROPERTIES VERSION "${CPACK_PACKAGE_VERSION}") set_target_properties (gvm_util_shared PROPERTIES PUBLIC_HEADER "${HEADERS}") - target_link_libraries (gvm_util_shared LINK_PRIVATE ${GLIB_LDFLAGS} + target_link_libraries (gvm_util_shared LINK_PRIVATE ${LIBPAHO_LDFLAGS} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} diff --git a/util/mqtt.c b/util/mqtt.c new file mode 100644 index 000000000..fb4ffe9d7 --- /dev/null +++ b/util/mqtt.c @@ -0,0 +1,178 @@ +/* Copyright (C) 2021 Greenbone Networks GmbH + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "mqtt.h" + +#include "uuidutils.h" /* gvm_uuid_make */ + +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "lib mqtt" + +#define QOS 1 +#define TIMEOUT 10000L + +/** + * @brief Check for MQTT support + * + * @return 1 if gvm-libs has been built with mqtt, 0 otherwise. + */ +int +gvm_has_mqtt_support () +{ +#ifdef HAVE_MQTT + return 1; +#endif /* HAVE_MQTT */ + return 0; +} + +#ifdef HAVE_MQTT +/** + * Create a new mqtt client. + * + * @param server_uri URI of server. + * @param id Client id. + * + * @return mqtt client + */ +static MQTTClient +mqtt_create (const char *server_uri, char *id) +{ + MQTTClient client; + MQTTClient_createOptions create_opts = MQTTClient_createOptions_initializer; + create_opts.MQTTVersion = MQTTVERSION_5; + + int rc = MQTTClient_createWithOptions ( + &client, server_uri, id, MQTTCLIENT_PERSISTENCE_NONE, NULL, &create_opts); + + if (rc != MQTTCLIENT_SUCCESS) + { + MQTTClient_destroy (&client); + return NULL; + } + return client; +} +#endif /* HAVE_MQTT */ + +/** + * @brief connect to a mqtt broker. + * + * @param server_uri Address of the broker. + * + * @return Mqtt handle, NULL on error. + */ +mqtt_t * +mqtt_connect (const char *server_uri) +{ +#ifdef HAVE_MQTT + char *uuid; + int rc; + MQTTClient client; + mqtt_t *mqtt = NULL; + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer5; + MQTTProperties connect_properties = MQTTProperties_initializer; + MQTTResponse resp; + + uuid = gvm_uuid_make (); + client = mqtt_create (server_uri, uuid); + if (!client) + return NULL; + + conn_opts.keepAliveInterval = 0; + conn_opts.cleanstart = 1; + conn_opts.MQTTVersion = MQTTVERSION_5; + + resp = MQTTClient_connect5 (client, &conn_opts, &connect_properties, NULL); + rc = resp.reasonCode; + MQTTProperties_free (&connect_properties); + if (rc != MQTTCLIENT_SUCCESS) + { + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "%s: mqtt connection error to %s: %s", __func__, server_uri, + MQTTClient_strerror (rc)); + MQTTResponse_free (resp); + return NULL; + } + + mqtt = g_malloc0 (sizeof (mqtt)); + mqtt->client = client; + mqtt->addr = g_strdup (server_uri); + mqtt->client_id = uuid; + + return mqtt; +#else + (void) server_uri; + return NULL; +#endif /* HAVE_MQTT */ +} + +/** + * @brief Publish message on topic. + * + * @param mqtt MQTT handle. + * @param topic Topic to publish on. + * @param msg Message to publish on queue. + * + * @return 0 on success, negative errorcode on failure. + */ +int +mqtt_publish (mqtt_t *mqtt, const char *topic, const char *msg) +{ +#ifdef HAVE_MQTT + MQTTClient client; + MQTTClient_message pubmsg = MQTTClient_message_initializer; + MQTTClient_deliveryToken token; + MQTTResponse resp; + int rc; + + client = mqtt->client; + if (!client) + return -1; + + pubmsg.payload = (char *) msg; + pubmsg.payloadlen = (int) strlen (msg); + pubmsg.qos = QOS; + pubmsg.retained = 0; + + resp = MQTTClient_publishMessage5 (client, topic, &pubmsg, &token); + rc = resp.reasonCode; + if (rc != MQTTCLIENT_SUCCESS) + { + g_warning ("Failed to connect: %s", MQTTClient_strerror (rc)); + MQTTResponse_free (resp); + return -1; + } + + if ((rc = MQTTClient_waitForCompletion (client, token, TIMEOUT)) + != MQTTCLIENT_SUCCESS) + { + g_debug ("Message '%s' with delivery token %d could not be " + "published on topic %s", + msg, token, topic); + } + + return rc; +#else + (void) mqtt; + (void) topic; + (void) msg; + return -1; +#endif /* HAVE_MQTT */ +} diff --git a/util/mqtt.h b/util/mqtt.h new file mode 100644 index 000000000..dba28fa60 --- /dev/null +++ b/util/mqtt.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2021 Greenbone Networks GmbH + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * 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. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _GVM_MQTT_H +#define _GVM_MQTT_H + +#ifdef HAVE_MQTT +#include +#endif /* HAVE_MQTT*/ + +typedef struct +{ + void *client; + char *client_id; + char *addr; +} mqtt_t; + +int +gvm_has_mqtt_support (void); + +mqtt_t * +mqtt_connect (const char *); + +int +mqtt_publish (mqtt_t *, const char *, const char *); + +#endif /* _GVM_MQTT_H */