From f5fd5cd210a56d9f54988fede35c0fc71c2caa9c Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Sat, 6 Nov 2021 16:58:33 +0300 Subject: [PATCH 01/70] Fix hardcoded pthreads paths on Windows Use FindThreads module instead if available. Signed-off-by: Konstantin Podsvirov --- CMakeLists.txt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07eff849..2877213f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,12 +67,18 @@ option(WITH_THREADING "Include client library threading support?" ON) if (WITH_THREADING) add_definitions("-DWITH_THREADING") if (WIN32) - if (CMAKE_CL_64) - set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x64\\pthreadVC2.lib) - else (CMAKE_CL_64) - set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x86\\pthreadVC2.lib) - endif (CMAKE_CL_64) - set (PTHREAD_INCLUDE_DIR C:\\pthreads\\Pre-built.2\\include) + if (CMAKE_VERSION VERSION_LESS "3.1") + if (CMAKE_CL_64) + set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x64\\pthreadVC2.lib) + else (CMAKE_CL_64) + set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x86\\pthreadVC2.lib) + endif (CMAKE_CL_64) + set (PTHREAD_INCLUDE_DIR C:\\pthreads\\Pre-built.2\\include) + else() + find_package(Threads REQUIRED) + set (PTHREAD_LIBRARIES Threads::Threads) + set (PTHREAD_INCLUDE_DIR "") + endif() elseif (ANDROID) set (PTHREAD_LIBRARIES "") set (PTHREAD_INCLUDE_DIR "") From 366ec5c66e7c5543f25023cdad5de0d5bcbad1e1 Mon Sep 17 00:00:00 2001 From: Lusco Date: Thu, 16 Dec 2021 14:14:24 +1000 Subject: [PATCH 02/70] Update conf.c The default bridge configuration uses the backoff restart configuration, however this is not cleared if only a constant timeout is desired, causing it to always use the backoff configuration with a 30 second cap. To trigger this error, use a bridge configuration with a constant timeout (e.g restart_timeout 5). Note that the timeout value is not honoured. Clear the backoff configuration when applying restart_timeout. Signed-off-by: Trevor Luscombe --- src/conf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/conf.c b/src/conf.c index 22b85097..a3fbc7c4 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1897,6 +1897,8 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload, return MOSQ_ERR_INVAL; } cur_bridge->restart_timeout = atoi(token); + cur_bridge->backoff_base = 0; + cur_bridge->backoff_cap = 0; if(cur_bridge->restart_timeout < 1){ log__printf(NULL, MOSQ_LOG_NOTICE, "restart_timeout interval too low, using 1 second."); cur_bridge->restart_timeout = 1; From bff71fd99f555f2da1e1ae5e6416bfaf14e490c9 Mon Sep 17 00:00:00 2001 From: Xavier Dooms Date: Tue, 21 Dec 2021 23:51:34 +0100 Subject: [PATCH 03/70] support plugin tick callbacks with per_listener_settings enabled add tests for the plugin tick Signed-off-by: Xavier Dooms --- src/plugin.c | 10 ++++- test/broker/09-plugin-tick.py | 52 ++++++++++++++++++++++ test/broker/c/Makefile | 1 + test/broker/c/auth_plugin_v5_handle_tick.c | 38 ++++++++++++++++ test/broker/test.py | 1 + 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100755 test/broker/09-plugin-tick.py create mode 100644 test/broker/c/auth_plugin_v5_handle_tick.c diff --git a/src/plugin.c b/src/plugin.c index e0dd371a..a40c5242 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -180,10 +180,18 @@ void plugin__handle_tick(void) struct mosquitto_evt_tick event_data; struct mosquitto__callback *cb_base; struct mosquitto__security_options *opts; + int i; /* FIXME - set now_s and now_ns to avoid need for multiple time lookups */ if(db.config->per_listener_settings){ - /* FIXME - iterate over all listeners */ + for(i=0; i < db.config->listener_count; i++){ + opts = &db.config->listeners[i].security_options; + memset(&event_data, 0, sizeof(event_data)); + + DL_FOREACH(opts->plugin_callbacks.tick, cb_base){ + cb_base->cb(MOSQ_EVT_TICK, &event_data, cb_base->userdata); + } + } }else{ opts = &db.config->security_options; memset(&event_data, 0, sizeof(event_data)); diff --git a/test/broker/09-plugin-tick.py b/test/broker/09-plugin-tick.py new file mode 100755 index 00000000..f6af1dbd --- /dev/null +++ b/test/broker/09-plugin-tick.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +# Test whether a plugin can subscribe to the tick event + +from mosq_test_helper import * + +def write_config(filename, port, per_listener_settings="false"): + with open(filename, 'w') as f: + f.write("per_listener_settings %s\n" % (per_listener_settings)) + f.write("listener %d\n" % (port)) + f.write("plugin c/auth_plugin_v5_handle_tick.so\n") + f.write("allow_anonymous true\n") + +def do_test(per_listener_settings): + proto_ver = 5 + port = mosq_test.get_port() + conf_file = os.path.basename(__file__).replace('.py', '.conf') + write_config(conf_file, port, per_listener_settings) + + rc = 1 + keepalive = 10 + connect_packet = mosq_test.gen_connect("plugin-tick-test", keepalive=keepalive, username="readwrite", clean_session=False, proto_ver=proto_ver) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver) + + tick_packet = mosq_test.gen_publish("topic/tick", qos=0, payload="test-message", proto_ver=proto_ver) + + broker = mosq_test.start_broker(filename=os.path.basename(__file__), use_conf=True, port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=10, port=port) + + mosq_test.expect_packet(sock, "tick message", tick_packet) + mosq_test.expect_packet(sock, "tick message", tick_packet) + mosq_test.expect_packet(sock, "tick message", tick_packet) + + mosq_test.do_ping(sock) + + rc = 0 + sock.close() + except mosq_test.TestError: + pass + finally: + os.remove(conf_file) + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + exit(rc) + +do_test("false") +do_test("true") diff --git a/test/broker/c/Makefile b/test/broker/c/Makefile index 51fb2b79..e897e34d 100644 --- a/test/broker/c/Makefile +++ b/test/broker/c/Makefile @@ -18,6 +18,7 @@ PLUGIN_SRC = \ auth_plugin_v4.c \ auth_plugin_v5.c \ auth_plugin_v5_handle_message.c \ + auth_plugin_v5_handle_tick.c \ plugin_control.c PLUGINS = ${PLUGIN_SRC:.c=.so} diff --git a/test/broker/c/auth_plugin_v5_handle_tick.c b/test/broker/c/auth_plugin_v5_handle_tick.c new file mode 100644 index 00000000..d6435bb0 --- /dev/null +++ b/test/broker/c/auth_plugin_v5_handle_tick.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include + +static int handle_tick(int event, void *event_data, void *user_data); + +static mosquitto_plugin_id_t *plg_id; + + +int mosquitto_plugin_version(int supported_version_count, const int *supported_versions) +{ + return 5; +} + +int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *auth_opts, int auth_opt_count) +{ + plg_id = identifier; + + mosquitto_callback_register(plg_id, MOSQ_EVT_TICK, handle_tick, NULL, NULL); + + return MOSQ_ERR_SUCCESS; +} + +int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *auth_opts, int auth_opt_count) +{ + mosquitto_callback_unregister(plg_id, MOSQ_EVT_TICK, handle_tick, NULL); + + return MOSQ_ERR_SUCCESS; +} + +int handle_tick(int event, void *event_data, void *user_data) +{ + mosquitto_broker_publish_copy("plugin-tick-test", "topic/tick", strlen("test-message"), "test-message", 0, false, NULL); + return MOSQ_ERR_SUCCESS; +} diff --git a/test/broker/test.py b/test/broker/test.py index 2fbb39e4..26361c56 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -153,6 +153,7 @@ tests = [ (1, './09-plugin-auth-v2-unpwd-fail.py'), (1, './09-plugin-auth-v2-unpwd-success.py'), (1, './09-plugin-publish.py'), + (1, './09-plugin-tick.py'), (1, './09-pwfile-parse-invalid.py'), (2, './10-listener-mount-point.py'), From 26f747e0ac003b131857c0e7ea3a9849ce9f1286 Mon Sep 17 00:00:00 2001 From: Abilio Marques Date: Tue, 11 Jan 2022 19:24:34 +0100 Subject: [PATCH 04/70] fix confusing log message on connack error Signed-off-by: Abilio Marques --- src/handle_connack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handle_connack.c b/src/handle_connack.c index f4251fe9..e6418662 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -163,7 +163,7 @@ int handle__connack(struct mosquitto *context) log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable"); return MOSQ_ERR_CONN_LOST; case CONNACK_REFUSED_BAD_USERNAME_PASSWORD: - log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: broker unavailable"); + log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: bad user name or password"); return MOSQ_ERR_CONN_LOST; case CONNACK_REFUSED_NOT_AUTHORIZED: log__printf(NULL, MOSQ_LOG_ERR, "Connection Refused: not authorised"); From 5f57de21cdeb179b0b4876671ce308afccd46ac6 Mon Sep 17 00:00:00 2001 From: Abilio Marques Date: Fri, 11 Feb 2022 21:41:26 +0100 Subject: [PATCH 05/70] Fix memory leak when modifying topics using the plugin API Signed-off-by: Abilio Marques --- src/plugin.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugin.c b/src/plugin.c index e0dd371a..92973c11 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -162,7 +162,11 @@ int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store } } - stored->topic = event_data.topic; + if(stored->topic != event_data.topic){ + mosquitto__free(stored->topic); + stored->topic = event_data.topic; + } + if(stored->payload != event_data.payload){ mosquitto__free(stored->payload); stored->payload = event_data.payload; From b7fb9114286dd1da1d31500a10a49c4393e3a767 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Mon, 7 Feb 2022 10:29:02 +0100 Subject: [PATCH 06/70] tests: replace use of ssl.wrap_socket that throws warnings in Python 3.10 The function ssl.wrap_socket() is deprecated starting Python 3.7 because it does not support hostname matching (which is considered insecure). In Python 3.10, the function now throws warnings at runtime, which makes Ubuntu / Debian autopkgtest fail. The function ssl.SSLContext.wrap_socket comes in as the replacement and has support for SNI and hostname matching. Replaced all uses of ssl.wrap_socket() by equivalent using ssl.SSLContext.wrap_socket(). Signed-off-by: Olivier Gayot --- test/broker/08-ssl-bridge.py | 4 +++- test/broker/08-ssl-connect-cert-auth-crl.py | 4 +++- test/broker/08-ssl-connect-cert-auth-expired.py | 4 +++- test/broker/08-ssl-connect-cert-auth-revoked.py | 4 +++- test/broker/08-ssl-connect-cert-auth-without.py | 3 ++- test/broker/08-ssl-connect-cert-auth.py | 4 +++- test/broker/08-ssl-connect-identity.py | 4 +++- test/broker/08-ssl-connect-no-auth-wrong-ca.py | 3 ++- test/broker/08-ssl-connect-no-auth.py | 3 ++- test/broker/08-ssl-connect-no-identity.py | 3 ++- test/broker/08-ssl-hup-disconnect.py | 4 +++- test/lib/08-ssl-connect-cert-auth-enc.py | 7 ++++--- test/lib/08-ssl-connect-cert-auth.py | 7 ++++--- test/lib/08-ssl-connect-no-auth.py | 4 +++- test/lib/08-ssl-fake-cacert.py | 7 ++++--- 15 files changed, 44 insertions(+), 21 deletions(-) diff --git a/test/broker/08-ssl-bridge.py b/test/broker/08-ssl-bridge.py index c48e7de0..4cbe52e1 100755 --- a/test/broker/08-ssl-bridge.py +++ b/test/broker/08-ssl-bridge.py @@ -34,7 +34,9 @@ publish_packet = mosq_test.gen_publish("bridge/ssl/test", qos=0, payload="messag sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", keyfile="../ssl/server.key", certfile="../ssl/server.crt", server_side=True) +context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile="../ssl/all-ca.crt") +context.load_cert_chain(certfile="../ssl/server.crt", keyfile="../ssl/server.key") +ssock = context.wrap_socket(sock, server_side=True) ssock.settimeout(20) ssock.bind(('', port1)) ssock.listen(5) diff --git a/test/broker/08-ssl-connect-cert-auth-crl.py b/test/broker/08-ssl-connect-cert-auth-crl.py index 6c348a35..0cb448ef 100755 --- a/test/broker/08-ssl-connect-cert-auth-crl.py +++ b/test/broker/08-ssl-connect-cert-auth-crl.py @@ -31,7 +31,9 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", certfile="../ssl/client.crt", keyfile="../ssl/client.key", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + context.load_cert_chain(certfile="../ssl/client.crt", keyfile="../ssl/client.key") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-cert-auth-expired.py b/test/broker/08-ssl-connect-cert-auth-expired.py index c7be02a4..41e66364 100755 --- a/test/broker/08-ssl-connect-cert-auth-expired.py +++ b/test/broker/08-ssl-connect-cert-auth-expired.py @@ -31,7 +31,9 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", certfile="../ssl/client-expired.crt", keyfile="../ssl/client-expired.key", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + context.load_cert_chain(certfile="../ssl/client-expired.crt", keyfile="../ssl/client-expired.key") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) try: ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-cert-auth-revoked.py b/test/broker/08-ssl-connect-cert-auth-revoked.py index 76788bc7..92734543 100755 --- a/test/broker/08-ssl-connect-cert-auth-revoked.py +++ b/test/broker/08-ssl-connect-cert-auth-revoked.py @@ -30,7 +30,9 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", certfile="../ssl/client-revoked.crt", keyfile="../ssl/client-revoked.key", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + context.load_cert_chain(certfile="../ssl/client-revoked.crt", keyfile="../ssl/client-revoked.key") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) try: ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-cert-auth-without.py b/test/broker/08-ssl-connect-cert-auth-without.py index 932dee29..3e6bf6aa 100755 --- a/test/broker/08-ssl-connect-cert-auth-without.py +++ b/test/broker/08-ssl-connect-cert-auth-without.py @@ -28,7 +28,8 @@ connect_packet = mosq_test.gen_connect("connect-cert-test", keepalive=keepalive) broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, use_conf=True) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", cert_reqs=ssl.CERT_REQUIRED) +context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) +ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) try: ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-cert-auth.py b/test/broker/08-ssl-connect-cert-auth.py index bf7c67bb..26651c3a 100755 --- a/test/broker/08-ssl-connect-cert-auth.py +++ b/test/broker/08-ssl-connect-cert-auth.py @@ -32,7 +32,9 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", certfile="../ssl/client.crt", keyfile="../ssl/client.key", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + context.load_cert_chain(certfile="../ssl/client.crt", keyfile="../ssl/client.key") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-identity.py b/test/broker/08-ssl-connect-identity.py index f1bc53d3..ba2cbb22 100755 --- a/test/broker/08-ssl-connect-identity.py +++ b/test/broker/08-ssl-connect-identity.py @@ -33,7 +33,9 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", certfile="../ssl/client.crt", keyfile="../ssl/client.key", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + context.load_cert_chain(certfile="../ssl/client.crt", keyfile="../ssl/client.key") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-no-auth-wrong-ca.py b/test/broker/08-ssl-connect-no-auth-wrong-ca.py index 30e3e313..7a18ae61 100755 --- a/test/broker/08-ssl-connect-no-auth-wrong-ca.py +++ b/test/broker/08-ssl-connect-no-auth-wrong-ca.py @@ -29,7 +29,8 @@ connack_packet = mosq_test.gen_connack(rc=0) broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, use_conf=True) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-alt-ca.crt", cert_reqs=ssl.CERT_REQUIRED) +context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-alt-ca.crt") +ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) try: ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-no-auth.py b/test/broker/08-ssl-connect-no-auth.py index 8990afeb..7b70b325 100755 --- a/test/broker/08-ssl-connect-no-auth.py +++ b/test/broker/08-ssl-connect-no-auth.py @@ -32,7 +32,8 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-connect-no-identity.py b/test/broker/08-ssl-connect-no-identity.py index 8bbff40c..a5527d5c 100755 --- a/test/broker/08-ssl-connect-no-identity.py +++ b/test/broker/08-ssl-connect-no-identity.py @@ -32,7 +32,8 @@ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port2, try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) ssock.connect(("localhost", port1)) diff --git a/test/broker/08-ssl-hup-disconnect.py b/test/broker/08-ssl-hup-disconnect.py index b9bacd43..648556b0 100755 --- a/test/broker/08-ssl-hup-disconnect.py +++ b/test/broker/08-ssl-hup-disconnect.py @@ -43,7 +43,9 @@ def do_test(option): try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ssock = ssl.wrap_socket(sock, ca_certs="../ssl/test-root-ca.crt", certfile="../ssl/client.crt", keyfile="../ssl/client.key", cert_reqs=ssl.CERT_REQUIRED) + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile="../ssl/test-root-ca.crt") + context.load_cert_chain(certfile="../ssl/client.crt", keyfile="../ssl/client.key") + ssock = context.wrap_socket(sock, server_hostname="localhost") ssock.settimeout(20) ssock.connect(("localhost", port)) mosq_test.do_send_receive(ssock, connect_packet, connack_packet, "connack") diff --git a/test/lib/08-ssl-connect-cert-auth-enc.py b/test/lib/08-ssl-connect-cert-auth-enc.py index fad6b8b5..ad51e120 100755 --- a/test/lib/08-ssl-connect-cert-auth-enc.py +++ b/test/lib/08-ssl-connect-cert-auth-enc.py @@ -26,9 +26,10 @@ disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", - keyfile="../ssl/server.key", certfile="../ssl/server.crt", - server_side=True, cert_reqs=ssl.CERT_REQUIRED) +context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile="../ssl/all-ca.crt") +context.load_cert_chain(certfile="../ssl/server.crt", keyfile="../ssl/server.key") +context.verify_mode = ssl.CERT_REQUIRED +ssock = context.wrap_socket(sock, server_side=True) ssock.settimeout(10) ssock.bind(('', port)) ssock.listen(5) diff --git a/test/lib/08-ssl-connect-cert-auth.py b/test/lib/08-ssl-connect-cert-auth.py index dba818c1..f96942ec 100755 --- a/test/lib/08-ssl-connect-cert-auth.py +++ b/test/lib/08-ssl-connect-cert-auth.py @@ -26,9 +26,10 @@ disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", - keyfile="../ssl/server.key", certfile="../ssl/server.crt", - server_side=True, cert_reqs=ssl.CERT_REQUIRED) +context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile="../ssl/all-ca.crt") +context.load_cert_chain(certfile="../ssl/server.crt", keyfile="../ssl/server.key") +context.verify_mode = ssl.CERT_REQUIRED +ssock = context.wrap_socket(sock, server_side=True) ssock.settimeout(10) ssock.bind(('', port)) ssock.listen(5) diff --git a/test/lib/08-ssl-connect-no-auth.py b/test/lib/08-ssl-connect-no-auth.py index d994a5b4..17a68d1a 100755 --- a/test/lib/08-ssl-connect-no-auth.py +++ b/test/lib/08-ssl-connect-no-auth.py @@ -25,7 +25,9 @@ disconnect_packet = mosq_test.gen_disconnect() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", keyfile="../ssl/server.key", certfile="../ssl/server.crt", server_side=True) +context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile="../ssl/all-ca.crt") +context.load_cert_chain(certfile="../ssl/server.crt", keyfile="../ssl/server.key") +ssock = context.wrap_socket(sock, server_side=True) ssock.settimeout(10) ssock.bind(('', port)) ssock.listen(5) diff --git a/test/lib/08-ssl-fake-cacert.py b/test/lib/08-ssl-fake-cacert.py index a1306677..dc0eb5ca 100755 --- a/test/lib/08-ssl-fake-cacert.py +++ b/test/lib/08-ssl-fake-cacert.py @@ -10,9 +10,10 @@ if sys.version < '2.7': sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) -ssock = ssl.wrap_socket(sock, ca_certs="../ssl/all-ca.crt", - keyfile="../ssl/server.key", certfile="../ssl/server.crt", - server_side=True, cert_reqs=ssl.CERT_REQUIRED) +context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile="../ssl/all-ca.crt") +context.load_cert_chain(certfile="../ssl/server.crt", keyfile="../ssl/server.key") +context.verify_mode = ssl.CERT_REQUIRED +ssock = context.wrap_socket(sock, server_side=True) ssock.settimeout(10) ssock.bind(('', port)) ssock.listen(5) From 497cbe0c6c5eff7af6236c81d37c70e1431ebdc2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 24 Feb 2022 10:16:18 +0000 Subject: [PATCH 07/70] Update changelog --- ChangeLog.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index d202f4d0..221a79ba 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,11 @@ +2.0.15 - 2022-xx-xx +=================== + +Broker: +- Fix memory leak when a plugin modifies the topic of a message in + MOSQ_EVT_MESSAGE. + + 2.0.14 - 2021-11-17 =================== From 96931643a4da9a552a3796bd601df1c5cee88180 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 24 Feb 2022 12:01:26 +0000 Subject: [PATCH 08/70] Use strings.h for strcasecmp, except on Windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2420. Thanks to Frédéric Fauberteau. --- apps/mosquitto_ctrl/dynsec.c | 4 ++++ apps/mosquitto_ctrl/dynsec_role.c | 4 ++++ apps/mosquitto_ctrl/example.c | 4 ++++ apps/mosquitto_ctrl/mosquitto_ctrl.c | 4 ++++ lib/strings_mosq.c | 4 ++++ plugins/dynamic-security/plugin.c | 4 ++++ plugins/dynamic-security/roles.c | 4 ++++ src/net.c | 25 +++++++++++++------------ 8 files changed, 41 insertions(+), 12 deletions(-) diff --git a/apps/mosquitto_ctrl/dynsec.c b/apps/mosquitto_ctrl/dynsec.c index 3a5f4f1c..c74147b6 100644 --- a/apps/mosquitto_ctrl/dynsec.c +++ b/apps/mosquitto_ctrl/dynsec.c @@ -22,6 +22,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "mosquitto_ctrl.h" #include "mosquitto.h" #include "password_mosq.h" diff --git a/apps/mosquitto_ctrl/dynsec_role.c b/apps/mosquitto_ctrl/dynsec_role.c index 14eebcaa..6f103f7c 100644 --- a/apps/mosquitto_ctrl/dynsec_role.c +++ b/apps/mosquitto_ctrl/dynsec_role.c @@ -22,6 +22,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "mosquitto.h" #include "mosquitto_ctrl.h" #include "password_mosq.h" diff --git a/apps/mosquitto_ctrl/example.c b/apps/mosquitto_ctrl/example.c index 01b8d580..b4d0a732 100644 --- a/apps/mosquitto_ctrl/example.c +++ b/apps/mosquitto_ctrl/example.c @@ -22,6 +22,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "mosquitto_ctrl.h" void ctrl_help(void) diff --git a/apps/mosquitto_ctrl/mosquitto_ctrl.c b/apps/mosquitto_ctrl/mosquitto_ctrl.c index 837470d2..45a41d86 100644 --- a/apps/mosquitto_ctrl/mosquitto_ctrl.c +++ b/apps/mosquitto_ctrl/mosquitto_ctrl.c @@ -24,6 +24,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "lib_load.h" #include "mosquitto.h" #include "mosquitto_ctrl.h" diff --git a/lib/strings_mosq.c b/lib/strings_mosq.c index 292a1a74..419294a6 100644 --- a/lib/strings_mosq.c +++ b/lib/strings_mosq.c @@ -21,6 +21,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "mosquitto.h" #include "mqtt_protocol.h" diff --git a/plugins/dynamic-security/plugin.c b/plugins/dynamic-security/plugin.c index 27c3904d..ae9f2e7d 100644 --- a/plugins/dynamic-security/plugin.c +++ b/plugins/dynamic-security/plugin.c @@ -25,6 +25,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "json_help.h" #include "mosquitto.h" #include "mosquitto_broker.h" diff --git a/plugins/dynamic-security/roles.c b/plugins/dynamic-security/roles.c index 4d5accfc..6a393bc0 100644 --- a/plugins/dynamic-security/roles.c +++ b/plugins/dynamic-security/roles.c @@ -24,6 +24,10 @@ Contributors: #include #include +#ifndef WIN32 +# include +#endif + #include "dynamic_security.h" #include "json_help.h" #include "mosquitto.h" diff --git a/src/net.c b/src/net.c index ad9d53da..71bf54c8 100644 --- a/src/net.c +++ b/src/net.c @@ -19,15 +19,16 @@ Contributors: #include "config.h" #ifndef WIN32 -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include +# include #else -#include -#include +# include +# include #endif #include @@ -36,7 +37,7 @@ Contributors: #include #include #ifdef WITH_WRAP -#include +# include #endif #ifdef HAVE_NETINET_IN_H @@ -49,7 +50,7 @@ Contributors: #endif #ifdef __QNX__ -#include +# include #endif #include "mosquitto_broker_internal.h" @@ -59,8 +60,8 @@ Contributors: #include "util_mosq.h" #ifdef WITH_TLS -#include "tls_mosq.h" -#include +# include "tls_mosq.h" +# include static int tls_ex_index_context = -1; static int tls_ex_index_listener = -1; #endif From 39f303064362cf04835d552be8c4bbdfd74291bd Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 24 Feb 2022 14:05:11 +0000 Subject: [PATCH 09/70] Fix client_generated flag not being copied on properties. Closes #2401. Thanks to Diorcet Yann. --- lib/property_mosq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 6249869c..71c49737 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -1208,6 +1208,7 @@ int mosquitto_property_copy_all(mosquitto_property **dest, const mosquitto_prope } plast = pnew; + pnew->client_generated = src->client_generated; pnew->identifier = src->identifier; switch(pnew->identifier){ case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: From 1e9d00a1a194a1666860d17dba2a998e1f28766a Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 24 Feb 2022 15:56:46 +0000 Subject: [PATCH 10/70] Update changelog --- ChangeLog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 221a79ba..e1149940 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,7 @@ Broker: - Fix memory leak when a plugin modifies the topic of a message in MOSQ_EVT_MESSAGE. +- Fix bridge `restart_timeout` not being honoured. 2.0.14 - 2021-11-17 From fc06da2daab2a6de41830c4dfcad0277524347b3 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 24 Feb 2022 17:01:42 +0000 Subject: [PATCH 11/70] Fix pthreads linkage. --- config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.mk b/config.mk index 3cb2cc5e..432d54f3 100644 --- a/config.mk +++ b/config.mk @@ -254,10 +254,10 @@ ifeq ($(WITH_TLS),yes) endif ifeq ($(WITH_THREADING),yes) - LIB_LIBADD:=$(LIB_LIBADD) -lpthread + LIB_LDFLAGS:=$(LIB_LDFLAGS) -pthread LIB_CPPFLAGS:=$(LIB_CPPFLAGS) -DWITH_THREADING CLIENT_CPPFLAGS:=$(CLIENT_CPPFLAGS) -DWITH_THREADING - STATIC_LIB_DEPS:=$(STATIC_LIB_DEPS) -lpthread + STATIC_LIB_DEPS:=$(STATIC_LIB_DEPS) -pthread endif ifeq ($(WITH_SOCKS),yes) From 74814cc68f86d748037046d60d0bdaf467d78d37 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 24 Feb 2022 19:01:08 +0000 Subject: [PATCH 12/70] Simplify cmake threads detection on Windows Requires cmake 3.1. --- CMakeLists.txt | 17 ++++------------- ChangeLog.txt | 4 ++++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9c94fec..bd5bad3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # To configure the build options either use the CMake gui, or run the command # line utility including the "-i" option. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.1) cmake_policy(SET CMP0042 NEW) project(mosquitto) @@ -67,18 +67,9 @@ option(WITH_THREADING "Include client library threading support?" ON) if (WITH_THREADING) add_definitions("-DWITH_THREADING") if (WIN32) - if (CMAKE_VERSION VERSION_LESS "3.1") - if (CMAKE_CL_64) - set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x64\\pthreadVC2.lib) - else (CMAKE_CL_64) - set (PTHREAD_LIBRARIES C:\\pthreads\\Pre-built.2\\lib\\x86\\pthreadVC2.lib) - endif (CMAKE_CL_64) - set (PTHREAD_INCLUDE_DIR C:\\pthreads\\Pre-built.2\\include) - else() - find_package(Threads REQUIRED) - set (PTHREAD_LIBRARIES Threads::Threads) - set (PTHREAD_INCLUDE_DIR "") - endif() + find_package(Threads REQUIRED) + set (PTHREAD_LIBRARIES Threads::Threads) + set (PTHREAD_INCLUDE_DIR "") elseif (ANDROID) set (PTHREAD_LIBRARIES "") set (PTHREAD_INCLUDE_DIR "") diff --git a/ChangeLog.txt b/ChangeLog.txt index e1149940..9bccedc7 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -6,6 +6,10 @@ Broker: MOSQ_EVT_MESSAGE. - Fix bridge `restart_timeout` not being honoured. +Client library: +- Fix threads library detection on Windows under cmake. Bumps the minimum + cmake version to 3.1, which is still ancient. + 2.0.14 - 2021-11-17 =================== From 1b7c6b5cbdfd27635c46fbfe584267f7f3d25677 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 8 Mar 2022 16:05:15 +0000 Subject: [PATCH 13/70] All docker images should use the same base. --- docker/1.5-openssl/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/1.5-openssl/Dockerfile b/docker/1.5-openssl/Dockerfile index c4e0a3f7..baa41aa2 100644 --- a/docker/1.5-openssl/Dockerfile +++ b/docker/1.5-openssl/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.12 +FROM alpine:3.14 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" From 8459a3c45653df7d6f08a83d269b944c40892857 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 8 Mar 2022 16:06:32 +0000 Subject: [PATCH 14/70] Fix whitespace errors --- docker/1.5/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 00cfd691..42d27f2e 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -65,7 +65,7 @@ RUN set -x && \ WITH_SHARED_LIBRARIES=yes \ WITH_SRV=no \ WITH_STRIP=yes \ - WITH_TLS_PSK=no \ + WITH_TLS_PSK=no \ WITH_WEBSOCKETS=yes \ prefix=/usr \ binary && \ @@ -82,8 +82,8 @@ RUN set -x && \ chown -R mosquitto:mosquitto /mosquitto && \ apk --no-cache add \ ca-certificates \ - libressl \ - libuuid && \ + libressl \ + libuuid && \ apk del build-deps && \ rm -rf /build From 8212bbe29b6fc0a49c30a15b22a36ff0ac7b9d32 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 8 Mar 2022 16:06:50 +0000 Subject: [PATCH 15/70] Remove defunct pgp keyservers from Dockerfiles. --- docker/1.5-openssl/Dockerfile | 3 +-- docker/1.5/Dockerfile | 3 +-- docker/1.6-openssl/Dockerfile | 3 +-- docker/1.6/Dockerfile | 3 +-- docker/2.0-openssl/Dockerfile | 3 +-- docker/2.0/Dockerfile | 3 +-- docker/generic/Dockerfile | 3 +-- 7 files changed, 7 insertions(+), 14 deletions(-) diff --git a/docker/1.5-openssl/Dockerfile b/docker/1.5-openssl/Dockerfile index baa41aa2..2d258cbd 100644 --- a/docker/1.5-openssl/Dockerfile +++ b/docker/1.5-openssl/Dockerfile @@ -40,9 +40,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + htps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 42d27f2e..45c3c162 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -42,9 +42,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + hkps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ diff --git a/docker/1.6-openssl/Dockerfile b/docker/1.6-openssl/Dockerfile index 13769d51..025d85f1 100644 --- a/docker/1.6-openssl/Dockerfile +++ b/docker/1.6-openssl/Dockerfile @@ -45,9 +45,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + hkps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ diff --git a/docker/1.6/Dockerfile b/docker/1.6/Dockerfile index 882da193..75b8cf42 100644 --- a/docker/1.6/Dockerfile +++ b/docker/1.6/Dockerfile @@ -45,9 +45,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + hkps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ diff --git a/docker/2.0-openssl/Dockerfile b/docker/2.0-openssl/Dockerfile index 44f09b2d..fc3366de 100644 --- a/docker/2.0-openssl/Dockerfile +++ b/docker/2.0-openssl/Dockerfile @@ -46,9 +46,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + hkps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ diff --git a/docker/2.0/Dockerfile b/docker/2.0/Dockerfile index 3df68360..bf54f81f 100644 --- a/docker/2.0/Dockerfile +++ b/docker/2.0/Dockerfile @@ -46,9 +46,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + hkps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ diff --git a/docker/generic/Dockerfile b/docker/generic/Dockerfile index a855bd7c..656f8a15 100644 --- a/docker/generic/Dockerfile +++ b/docker/generic/Dockerfile @@ -63,9 +63,8 @@ RUN set -x && \ export GNUPGHOME="$(mktemp -d)" && \ found=''; \ for server in \ - ha.pool.sks-keyservers.net \ + hkps://keys.openpgp.org \ hkp://keyserver.ubuntu.com:80 \ - hkp://p80.pool.sks-keyservers.net:80 \ pgp.mit.edu \ ; do \ echo "Fetching GPG key $GPG_KEYS from $server"; \ From 3c48b501e032592c99c93362329faf5e3c113e6a Mon Sep 17 00:00:00 2001 From: Abilio Marques Date: Sat, 12 Mar 2022 18:01:37 +0100 Subject: [PATCH 16/70] broker: fix memory leaks on plugin payload modification Signed-off-by: Abilio Marques --- src/plugin.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/plugin.c b/src/plugin.c index d7cac815..092353fb 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -157,23 +157,29 @@ int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store DL_FOREACH(opts->plugin_callbacks.message, cb_base){ rc = cb_base->cb(MOSQ_EVT_MESSAGE, &event_data, cb_base->userdata); + + if(stored->topic != event_data.topic){ + mosquitto__free(stored->topic); + stored->topic = event_data.topic; + } + + if(stored->payload != event_data.payload){ + mosquitto__free(stored->payload); + stored->payload = event_data.payload; + stored->payloadlen = event_data.payloadlen; + } + + if(stored->properties != event_data.properties){ + mosquitto_property_free_all(stored->properties); + stored->properties = event_data.properties; + } + if(rc != MOSQ_ERR_SUCCESS){ break; } } - if(stored->topic != event_data.topic){ - mosquitto__free(stored->topic); - stored->topic = event_data.topic; - } - - if(stored->payload != event_data.payload){ - mosquitto__free(stored->payload); - stored->payload = event_data.payload; - stored->payloadlen = event_data.payloadlen; - } stored->retain = event_data.retain; - stored->properties = event_data.properties; return rc; } From 610b63985adf7cd2010d2b319ee44c1530bd23dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20L=C3=A9caud=C3=A9?= Date: Mon, 14 Mar 2022 11:09:43 -0400 Subject: [PATCH 17/70] Fix typo (missing word) --- www/pages/documentation/dynamic-security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/pages/documentation/dynamic-security.md b/www/pages/documentation/dynamic-security.md index a84f8589..6570ace1 100644 --- a/www/pages/documentation/dynamic-security.md +++ b/www/pages/documentation/dynamic-security.md @@ -15,7 +15,7 @@ ## Introduction The Dynamic Security plugin is a Mosquitto plugin which provides role based -authentication and access control features that can updated whilst the broker +authentication and access control features that can be updated whilst the broker is running, using a special topic based API. It is supported since Mosquitto 2.0, and should be available in all From 8504f6b70bb7d6a1d05bb6acd348069343dfa203 Mon Sep 17 00:00:00 2001 From: Pierre Hallot Date: Tue, 5 Apr 2022 16:14:48 +0200 Subject: [PATCH 18/70] CMake: Use PROJECT_SOURCE_DIR to improve using mosquitto as subdirectory When mosquitto is included as subdirectory, `CMAKE_SOURCE_DIR` does not refer to the mosquitto top level CMake file, but to the whole project top level CMake. Use `PROJECT_SOURCE_DIR` instead to refer to the right CMake in both contextes. Signed-off-by: Pierre Hallot --- CMakeLists.txt | 2 +- man/CMakeLists.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd5bad3c..851c4243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ cmake_policy(SET CMP0042 NEW) project(mosquitto) set (VERSION 2.0.14) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/") +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/") add_definitions (-DCMAKE -DVERSION=\"${VERSION}\") diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt index 2c8b0955..13a18735 100644 --- a/man/CMakeLists.txt +++ b/man/CMakeLists.txt @@ -8,10 +8,10 @@ if(NOT WIN32) find_program(XSLTPROC xsltproc OPTIONAL) if(XSLTPROC) function(compile_manpage page) - add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/man/${page} - COMMAND xsltproc ${CMAKE_SOURCE_DIR}/man/${page}.xml -o ${CMAKE_SOURCE_DIR}/man/ - MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/man/${page}.xml) - add_custom_target(${page} ALL DEPENDS ${CMAKE_SOURCE_DIR}/man/${page}) + add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/man/${page} + COMMAND xsltproc ${PROJECT_SOURCE_DIR}/man/${page}.xml -o ${PROJECT_SOURCE_DIR}/man/ + MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/man/${page}.xml) + add_custom_target(${page} ALL DEPENDS ${PROJECT_SOURCE_DIR}/man/${page}) endfunction() compile_manpage("mosquitto_ctrl.1") From 40779875937730f77c1a08de163349b5b4c8ccb4 Mon Sep 17 00:00:00 2001 From: Christian Salvasohn Date: Wed, 13 Apr 2022 20:05:35 +0200 Subject: [PATCH 19/70] fix data race mosquitto_loop function next_msg_out must be protected with the msgtime_mutex as done everywhere else in the code else there is a data race e.g. if mosquitto_publish is called from another thread Signed-off-by: Christian Salvasohn --- lib/loop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/loop.c b/lib/loop.c index 3373c186..2c35ee19 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -114,9 +114,11 @@ int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) } now = mosquitto_time(); + pthread_mutex_lock(&mosq->msgtime_mutex); if(mosq->next_msg_out && now + timeout_ms/1000 > mosq->next_msg_out){ timeout_ms = (mosq->next_msg_out - now)*1000; } + pthread_mutex_unlock(&mosq->msgtime_mutex); if(timeout_ms < 0){ /* There has been a delay somewhere which means we should have already From a9a5ac2283feeb58a3cb1e78d3bda14bdf475d13 Mon Sep 17 00:00:00 2001 From: Tobias Assarsson Date: Wed, 20 Apr 2022 10:04:58 +0200 Subject: [PATCH 20/70] Don't reuse topic alias after reconnect. --- client/pub_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/pub_client.c b/client/pub_client.c index 848e2c2d..7822e27f 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -135,6 +135,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag connack_result = result; if(!result){ + first_publish = true; switch(cfg.pub_mode){ case MSGMODE_CMD: case MSGMODE_FILE: From 0745a8536ae2250e00dbef026b7700d9cb607a85 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 29 Apr 2022 22:20:15 +0100 Subject: [PATCH 21/70] Update changelog. Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. Closes #2494. --- ChangeLog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 9bccedc7..0dfdb6ab 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,9 @@ Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum cmake version to 3.1, which is still ancient. +Clients: +- Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. + Closes #2494. 2.0.14 - 2021-11-17 =================== From 651331ff7d16fef7bc37802a3686929f6884202a Mon Sep 17 00:00:00 2001 From: JsBergbau <37013344+JsBergbau@users.noreply.github.com> Date: Thu, 31 Mar 2022 01:41:57 +0200 Subject: [PATCH 22/70] Added queue_qos0_messages documentation for bridging See https://github.com/eclipse/mosquitto/pull/2500 --- man/mosquitto.conf.5.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 364b9785..1ede1156 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -954,7 +954,9 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S Set to true to queue messages with QoS 0 when a persistent client is - disconnected. These messages are included in the limit + disconnected. When bridges topics are configured with QoS level 1 or 2 incoming + QoS 0 messages for these topics are also queued. + These messages are included in the limit imposed by max_queued_messages. Defaults to false. Note that the MQTT v3.1.1 spec states that only QoS 1 From 127c5e7577541fc62d5df8f8e59734fccf09c23e Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 11 May 2022 15:55:05 +0100 Subject: [PATCH 23/70] Update changelog --- ChangeLog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0dfdb6ab..dd81c535 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,6 +5,8 @@ Broker: - Fix memory leak when a plugin modifies the topic of a message in MOSQ_EVT_MESSAGE. - Fix bridge `restart_timeout` not being honoured. +- Fix potential memory leaks if a plugin modifies the message in the + MOSQ_EVT_MESSAGE event. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum From e5bf040fb7a4f630eb7311550c08365c243cbea8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 13 May 2022 13:25:16 +0100 Subject: [PATCH 24/70] Weekly Coverity Scan run. --- .github/workflows/coverity-scan.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/coverity-scan.yml diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml new file mode 100644 index 00000000..27310bd7 --- /dev/null +++ b/.github/workflows/coverity-scan.yml @@ -0,0 +1,24 @@ +name: Coverity Scan fixes and develop branches on a weekly basis + +on: + workflow_dispatch: + schedule: + - cron: "7 3 * * 0" + +jobs: + coverity: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Dependencies + run: sudo apt-get install -y libcjson-dev libsqlite3-dev libssl-dev uthash-dev + + - uses: vapier/coverity-scan-action@v1 + with: + build_language: 'cxx' + project: "eclipse/mosquitto" + token: ${{ secrets.COVERITY_SCAN_TOKEN }} + email: ${{ secrets.COVERITY_SCAN_EMAIL }} + command: "make binary" + From b6b803991449d213b0314676c47d9d0f91b8306d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 17 May 2022 17:18:21 +0100 Subject: [PATCH 25/70] Fix use of `MOSQ_OPT_TLS_ENGINE` being unable to be used. This was due to the openssl ctx not being initialised until starting to connect. Closes #2537. Thanks to chessing-c4. --- ChangeLog.txt | 2 ++ include/mosquitto.h | 3 +++ lib/options.c | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index dd81c535..e1bb6e10 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -11,6 +11,8 @@ Broker: Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum cmake version to 3.1, which is still ancient. +- Fix use of `MOSQ_OPT_TLS_ENGINE` being unable to be used due to the openssl + ctx not being initialised until starting to connect. Closes #2537. Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. diff --git a/include/mosquitto.h b/include/mosquitto.h index e514d3f6..8fc43a95 100644 --- a/include/mosquitto.h +++ b/include/mosquitto.h @@ -1565,6 +1565,9 @@ libmosq_EXPORT int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t * MOSQ_OPT_TLS_ENGINE - Configure the client for TLS Engine support. * Pass a TLS Engine ID to be used when creating TLS * connections. Must be set before . + * Must be a valid engine, and note that the string will not be used + * until a connection attempt is made so this function will return + * success even if an invalid engine string is passed. * * MOSQ_OPT_TLS_KEYFORM - Configure the client to treat the keyfile * differently depending on its type. Must be set diff --git a/lib/options.c b/lib/options.c index 29f8225f..fa7386c2 100644 --- a/lib/options.c +++ b/lib/options.c @@ -284,14 +284,17 @@ int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, cons switch(option){ case MOSQ_OPT_TLS_ENGINE: #if defined(WITH_TLS) && !defined(OPENSSL_NO_ENGINE) - eng = ENGINE_by_id(value); - if(!eng){ - return MOSQ_ERR_INVAL; - } - ENGINE_free(eng); /* release the structural reference from ENGINE_by_id() */ - mosq->tls_engine = mosquitto__strdup(value); - if(!mosq->tls_engine){ - return MOSQ_ERR_NOMEM; + mosquitto__free(mosq->tls_engine); + if(value){ + eng = ENGINE_by_id(value); + if(!eng){ + return MOSQ_ERR_INVAL; + } + ENGINE_free(eng); /* release the structural reference from ENGINE_by_id() */ + mosq->tls_engine = mosquitto__strdup(value); + if(!mosq->tls_engine){ + return MOSQ_ERR_NOMEM; + } } return MOSQ_ERR_SUCCESS; #else From 09ac57845916901a42c69f8db1fa1a5512977699 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 17 May 2022 17:41:57 +0100 Subject: [PATCH 26/70] Fix unused flags in CONNECT command being forced to be 0 in MQTT v3.1 This check is not required until v3.1.1. Closes #2522. Thanks to garinocyr --- ChangeLog.txt | 2 ++ src/handle_connect.c | 6 +++--- test/broker/data/CONNECT.json | 8 ++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index e1bb6e10..d2383aec 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,8 @@ Broker: - Fix bridge `restart_timeout` not being honoured. - Fix potential memory leaks if a plugin modifies the message in the MOSQ_EVT_MESSAGE event. +- Fix unused flags in CONNECT command being forced to be 0, which is not + required for MQTT v3.1. Closes #2522. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/src/handle_connect.c b/src/handle_connect.c index 944b9f1e..dcc8ea5c 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -458,9 +458,6 @@ int handle__connect(struct mosquitto *context) rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } - if(context->in_packet.command != CMD_CONNECT){ - return MOSQ_ERR_MALFORMED_PACKET; - } /* Read protocol name as length then bytes rather than with read_string * because the length is fixed and we can check that. Removes the need @@ -528,6 +525,9 @@ int handle__connect(struct mosquitto *context) rc = MOSQ_ERR_PROTOCOL; goto handle_connect_error; } + if((protocol_version&0x7F) != PROTOCOL_VERSION_v31 && context->in_packet.command != CMD_CONNECT){ + return MOSQ_ERR_MALFORMED_PACKET; + } if(packet__read_byte(&context->in_packet, &connect_flags)){ rc = MOSQ_ERR_PROTOCOL; diff --git a/test/broker/data/CONNECT.json b/test/broker/data/CONNECT.json index 21fbcc50..6900e7ce 100644 --- a/test/broker/data/CONNECT.json +++ b/test/broker/data/CONNECT.json @@ -3,6 +3,14 @@ "comment": "CONNECT TESTS ARE INCOMPLETE", "group": "v3.1 CONNECT", "tests": [ + { "name": "10 ok ", "connect":false, "expect_disconnect":false, "msgs":[ + {"type":"send", "payload":"10 0F 0006 4D5149736470 03 01 000A 0001 70", "comment":"minimal valid CONNECT"}, + {"type":"recv", "payload":"20 02 00 00", "comment": "CONNACK"} + ]}, + { "name": "14 ok ", "connect":false, "expect_disconnect":false, "msgs":[ + {"type":"send", "payload":"14 0F 0006 4D5149736470 03 01 000A 0001 70", "comment":"CONNECT with QoS=1"}, + {"type":"recv", "payload":"20 02 00 00", "comment": "CONNACK"} + ]}, { "name": "10 proto ver 2", "connect":false, "msgs":[ {"type":"send", "payload":"10 0F 0006 4D5149736470 02 00 000A 0001 70", "comment":"CONNECT"}, {"type":"recv", "payload":"20 02 00 01", "comment": "CONNACK identifier rejected"} From 4ac8c0bcc34c8640e8c6a931e8e63ea4f250c6c7 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 17 May 2022 21:11:20 +0100 Subject: [PATCH 27/70] Add deny-protocol-version example plugin, for 2.0 only. --- plugins/Makefile | 1 + plugins/deny-protocol-version/CMakeLists.txt | 24 ++++ plugins/deny-protocol-version/Makefile | 29 +++++ .../mosquitto_deny_protocol_version.c | 110 ++++++++++++++++++ plugins/deny-protocol-version/test.conf | 4 + plugins/deny-protocol-version/test.sh | 4 + 6 files changed, 172 insertions(+) create mode 100644 plugins/deny-protocol-version/CMakeLists.txt create mode 100644 plugins/deny-protocol-version/Makefile create mode 100644 plugins/deny-protocol-version/mosquitto_deny_protocol_version.c create mode 100644 plugins/deny-protocol-version/test.conf create mode 100755 plugins/deny-protocol-version/test.sh diff --git a/plugins/Makefile b/plugins/Makefile index f039b2c4..51d5670c 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -1,5 +1,6 @@ DIRS= \ auth-by-ip \ + deny-protocol-version \ dynamic-security \ message-timestamp \ payload-modification diff --git a/plugins/deny-protocol-version/CMakeLists.txt b/plugins/deny-protocol-version/CMakeLists.txt new file mode 100644 index 00000000..d998df75 --- /dev/null +++ b/plugins/deny-protocol-version/CMakeLists.txt @@ -0,0 +1,24 @@ +set (PLUGIN_NAME mosquitto_deny_protocol_version) + +add_library(${PLUGIN_NAME} MODULE + ${PLUGIN_NAME}.c +) + +target_include_directories(${PLUGIN_NAME} PRIVATE + "${OPENSSL_INCLUDE_DIR}" + "${STDBOOL_H_PATH} ${STDINT_H_PATH}" + "${mosquitto_SOURCE_DIR}" + "${mosquitto_SOURCE_DIR}/include" +) + +set_target_properties(${PLUGIN_NAME} PROPERTIES + PREFIX "" + POSITION_INDEPENDENT_CODE 1 +) + +if(WIN32) + target_link_libraries(${PLUGIN_NAME} PRIVATE mosquitto) +endif() + +# Don't install, these are example plugins only. +#install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") diff --git a/plugins/deny-protocol-version/Makefile b/plugins/deny-protocol-version/Makefile new file mode 100644 index 00000000..42e6c806 --- /dev/null +++ b/plugins/deny-protocol-version/Makefile @@ -0,0 +1,29 @@ +R=../.. +include ${R}/config.mk + +.PHONY : all binary check clean reallyclean test install uninstall + +PLUGIN_NAME=mosquitto_deny_protocol_version +PLUGIN_CFLAGS+=-I${R}/include -I${R}/ + +all : binary + +binary : ${PLUGIN_NAME}.so + +${PLUGIN_NAME}.so : ${PLUGIN_NAME}.c + $(CROSS_COMPILE)$(CC) $(PLUGIN_CPPFLAGS) $(PLUGIN_CFLAGS) $(PLUGIN_LDFLAGS) -fPIC -shared $< -o $@ + +reallyclean : clean +clean: + -rm -f *.o ${PLUGIN_NAME}.so *.gcda *.gcno + +check: test +test: + +install: ${PLUGIN_NAME}.so + # Don't install, these are examples only. + #$(INSTALL) -d "${DESTDIR}$(libdir)" + #$(INSTALL) ${STRIP_OPTS} ${PLUGIN_NAME}.so "${DESTDIR}${libdir}/${PLUGIN_NAME}.so" + +uninstall : + -rm -f "${DESTDIR}${libdir}/${PLUGIN_NAME}.so" diff --git a/plugins/deny-protocol-version/mosquitto_deny_protocol_version.c b/plugins/deny-protocol-version/mosquitto_deny_protocol_version.c new file mode 100644 index 00000000..191cf710 --- /dev/null +++ b/plugins/deny-protocol-version/mosquitto_deny_protocol_version.c @@ -0,0 +1,110 @@ +/* +Copyright (c) 2022 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License 2.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + https://www.eclipse.org/legal/epl-2.0/ +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +SPDX-License-Identifier: EPL-2.0 OR EDL-1.0 + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +/* + * This is an example plugin showing how to deny access based on the version of + * the protocol spec a client connects with. It does no other authentication + * checks. + * + * It could be used with other authentication plugins by specifying it in the + * config file before another plugin, for example: + * + * plugin /usr/lib/mosquitto_deny_protocol_version.so + * plugin /usr/lib/mosquitto_dynamic_security.so + * + * or: + * + * plugin /usr/lib/mosquitto_deny_protocol_version.so + * password_file pwfile + * + * It will *not* work on its own. + * + * In Mosquitto 2.1, this can be achieved with the `accept_protocol_version` + * option instead. + * + * + * To compile: + * + * gcc -I -fPIC -shared mosquitto_deny_protocol_version.c -o mosquitto_deny_protocol_version.so + * + * Note that this only works on Mosquitto 2.0 or later. + */ +#include "config.h" + +#include +#include + +#include "mosquitto_broker.h" +#include "mosquitto_plugin.h" +#include "mosquitto.h" +#include "mqtt_protocol.h" + +static mosquitto_plugin_id_t *mosq_pid = NULL; + +int mosquitto_plugin_version(int supported_version_count, const int *supported_versions) +{ + int i; + + for(i=0; iclient); + + if(protocol_version == 5 || protocol_version == 4){ + /* Allow access to MQTT v5.0 and v3.1.1 - this passes on responsibility + * for the actual auth checks to the next plugin/password file in the + * config list. If no other plugins/password file is defined, then + * access will be denied. */ + return MOSQ_ERR_PLUGIN_DEFER; + }else{ + /* Deny access to all others */ + return MOSQ_ERR_AUTH; + } +} + +int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *opts, int opt_count) +{ + UNUSED(user_data); + UNUSED(opts); + UNUSED(opt_count); + + mosq_pid = identifier; + return mosquitto_callback_register(mosq_pid, MOSQ_EVT_BASIC_AUTH, basic_auth_callback, NULL, NULL); +} + +int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *opts, int opt_count) +{ + UNUSED(user_data); + UNUSED(opts); + UNUSED(opt_count); + + return mosquitto_callback_unregister(mosq_pid, MOSQ_EVT_MESSAGE, basic_auth_callback, NULL); +} diff --git a/plugins/deny-protocol-version/test.conf b/plugins/deny-protocol-version/test.conf new file mode 100644 index 00000000..01021314 --- /dev/null +++ b/plugins/deny-protocol-version/test.conf @@ -0,0 +1,4 @@ +listener 1883 + +plugin ./mosquitto_deny_protocol_version.so +password_file pwfile diff --git a/plugins/deny-protocol-version/test.sh b/plugins/deny-protocol-version/test.sh new file mode 100755 index 00000000..3005da50 --- /dev/null +++ b/plugins/deny-protocol-version/test.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +../../apps/mosquitto_passwd/mosquitto_passwd -c -b pwfile username password +../../src/mosquitto -c test.conf -v From 29c6480c47986b0b53f453b2933d7b5fef891811 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 19 May 2022 17:04:20 +0100 Subject: [PATCH 28/70] Improve documentation of `persistent_client_expiration` option. Closes #2404. Thanks to Rainer Plischke. --- ChangeLog.txt | 2 ++ man/mosquitto.conf.5.xml | 24 +++++++++++++++--------- mosquitto.conf | 14 ++++++++------ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index d2383aec..18bd565d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -9,6 +9,8 @@ Broker: MOSQ_EVT_MESSAGE event. - Fix unused flags in CONNECT command being forced to be 0, which is not required for MQTT v3.1. Closes #2522. +- Improve documentation of `persistent_client_expiration` option. + Closes #2404. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 1ede1156..4121a8d4 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -842,15 +842,21 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S duration - This option allows persistent clients (those with - clean session set to false) to be removed if they do - not reconnect within a certain time frame. This is a - non-standard option. As far as the MQTT spec is - concerned, persistent clients persist forever. - Badly designed clients may set clean session to false - whilst using a randomly generated client id. This leads - to persistent clients that will never reconnect. This - option allows these clients to be removed. + + This option allows the session of persistent clients (those with clean + session set to false) that are not currently connected to be removed if they + do not reconnect within a certain time frame. This is a non-standard option + in MQTT v3.1. MQTT v3.1.1 and v5.0 allow brokers to remove client sessions. + + + + Badly designed clients may set clean session to false whilst using a randomly + generated client id. This leads to persistent clients that connect once and + never reconnect. This option allows these clients to be removed. This option + allows persistent clients (those with clean session set to false) to be + removed if they do not reconnect within a certain time frame. + + The expiration period should be an integer followed by one of h d w m y for hour, day, week, month and year respectively. For example: diff --git a/mosquitto.conf b/mosquitto.conf index c46802e0..8da8a59e 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -141,14 +141,16 @@ # accepted. MQTT imposes a maximum payload size of 268435455 bytes. #message_size_limit 0 -# This option allows persistent clients (those with clean session set to false) -# to be removed if they do not reconnect within a certain time frame. -# -# This is a non-standard option in MQTT V3.1 but allowed in MQTT v3.1.1. +# This option allows the session of persistent clients (those with clean +# session set to false) that are not currently connected to be removed if they +# do not reconnect within a certain time frame. This is a non-standard option +# in MQTT v3.1. MQTT v3.1.1 and v5.0 allow brokers to remove client sessions. # # Badly designed clients may set clean session to false whilst using a randomly -# generated client id. This leads to persistent clients that will never -# reconnect. This option allows these clients to be removed. +# generated client id. This leads to persistent clients that connect once and +# never reconnect. This option allows these clients to be removed. This option +# allows persistent clients (those with clean session set to false) to be +# removed if they do not reconnect within a certain time frame. # # The expiration period should be an integer followed by one of h d w m y for # hour, day, week, month and year respectively. For example From 80b36919b158dd053877da32fc8ef065b6fbe846 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 23 May 2022 22:38:02 +0100 Subject: [PATCH 29/70] Fix incorrect pointer use. --- src/plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin.c b/src/plugin.c index 092353fb..56fad1de 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -170,7 +170,7 @@ int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store } if(stored->properties != event_data.properties){ - mosquitto_property_free_all(stored->properties); + mosquitto_property_free_all(&stored->properties); stored->properties = event_data.properties; } From c99502a2567bf9147b3d811cb17e38ad51f08660 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 23 May 2022 23:05:49 +0100 Subject: [PATCH 30/70] Add clients to session expiry check list when restarting and reloading from persistence. Closes #2546. Thanks to Joachim Schachermayer. --- ChangeLog.txt | 2 ++ src/mosquitto_broker_internal.h | 1 + src/persist_read.c | 2 +- src/session_expiry.c | 17 +++++++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 18bd565d..3b107be0 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -11,6 +11,8 @@ Broker: required for MQTT v3.1. Closes #2522. - Improve documentation of `persistent_client_expiration` option. Closes #2404. +- Add clients to session expiry check list when restarting and reloading from + persistence. Closes #2546. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 5d4f5de5..8f2ad0b2 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -818,6 +818,7 @@ void unpwd__free_item(struct mosquitto__unpwd **unpwd, struct mosquitto__unpwd * * Session expiry * ============================================================ */ int session_expiry__add(struct mosquitto *context); +int session_expiry__add_from_persistence(struct mosquitto *context, time_t expiry_time); void session_expiry__remove(struct mosquitto *context); void session_expiry__remove_all(void); void session_expiry__check(void); diff --git a/src/persist_read.c b/src/persist_read.c index 5e7be454..107e8602 100644 --- a/src/persist_read.c +++ b/src/persist_read.c @@ -208,7 +208,7 @@ static int persist__client_chunk_restore(FILE *db_fptr) } } } - /* FIXME - we should expire clients here if they have exceeded their time */ + session_expiry__add_from_persistence(context, chunk.F.session_expiry_time); }else{ rc = 1; } diff --git a/src/session_expiry.c b/src/session_expiry.c index 2ecceb74..470a12a6 100644 --- a/src/session_expiry.c +++ b/src/session_expiry.c @@ -82,6 +82,23 @@ int session_expiry__add(struct mosquitto *context) } +int session_expiry__add_from_persistence(struct mosquitto *context, time_t expiry_time) +{ + struct session_expiry_list *item; + + item = mosquitto__calloc(1, sizeof(struct session_expiry_list)); + if(!item) return MOSQ_ERR_NOMEM; + + item->context = context; + item->context->session_expiry_time = expiry_time; + context->expiry_list_item = item; + + DL_INSERT_INORDER(expiry_list, item, session_expiry__cmp); + + return MOSQ_ERR_SUCCESS; +} + + void session_expiry__remove(struct mosquitto *context) { if(context->expiry_list_item){ From 3e1cf8a80b9b7396dfe9c60ac8c538402e5f9c07 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 25 May 2022 16:16:48 +0100 Subject: [PATCH 31/70] Fix tests build. --- apps/db_dump/stubs.c | 7 +++++++ test/unit/persist_read_stubs.c | 7 +++++++ test/unit/persist_write_stubs.c | 7 +++++++ test/unit/subs_stubs.c | 7 +++++++ 4 files changed, 28 insertions(+) diff --git a/apps/db_dump/stubs.c b/apps/db_dump/stubs.c index f3773a6d..80ff9c69 100644 --- a/apps/db_dump/stubs.c +++ b/apps/db_dump/stubs.c @@ -139,3 +139,10 @@ void db__msg_add_to_queued_stats(struct mosquitto_msg_data *msg_data, struct mos UNUSED(msg_data); UNUSED(msg); } + +int session_expiry__add_from_persistence(struct mosquitto *context, time_t expiry_time) +{ + UNUSED(context); + UNUSED(expiry_time); + return 0; +} diff --git a/test/unit/persist_read_stubs.c b/test/unit/persist_read_stubs.c index 2d088ac7..ec559bef 100644 --- a/test/unit/persist_read_stubs.c +++ b/test/unit/persist_read_stubs.c @@ -205,3 +205,10 @@ void context__add_to_by_id(struct mosquitto *context) HASH_ADD_KEYPTR(hh_id, db.contexts_by_id, context->id, strlen(context->id), context); } } + +int session_expiry__add_from_persistence(struct mosquitto *context, time_t expiry_time) +{ + UNUSED(context); + UNUSED(expiry_time); + return 0; +} diff --git a/test/unit/persist_write_stubs.c b/test/unit/persist_write_stubs.c index 5cc4a597..69baffce 100644 --- a/test/unit/persist_write_stubs.c +++ b/test/unit/persist_write_stubs.c @@ -121,3 +121,10 @@ void context__add_to_by_id(struct mosquitto *context) HASH_ADD_KEYPTR(hh_id, db.contexts_by_id, context->id, strlen(context->id), context); } } + +int session_expiry__add_from_persistence(struct mosquitto *context, time_t expiry_time) +{ + UNUSED(context); + UNUSED(expiry_time); + return 0; +} diff --git a/test/unit/subs_stubs.c b/test/unit/subs_stubs.c index 0815e4a9..ca228170 100644 --- a/test/unit/subs_stubs.c +++ b/test/unit/subs_stubs.c @@ -219,3 +219,10 @@ void util__increment_send_quota(struct mosquitto *mosq) { mosq->msgs_out.inflight_quota++; } + +int session_expiry__add_from_persistence(struct mosquitto *context, time_t expiry_time) +{ + UNUSED(context); + UNUSED(expiry_time); + return 0; +} From ebfebf870836c46299133f548449f0e93ca3c27b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 25 May 2022 16:20:15 +0100 Subject: [PATCH 32/70] Fix bridges not sending failure notification messages. This is for messages to the local broker if the remote bridge connection fails. Closes #1488. Closes #2467. --- ChangeLog.txt | 2 ++ lib/util_mosq.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 3b107be0..f5029030 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -13,6 +13,8 @@ Broker: Closes #2404. - Add clients to session expiry check list when restarting and reloading from persistence. Closes #2546. +- Fix bridges not sending failure notification messages to the local broker if + the remote bridge connection fails. Closes #2467. Closes #1488. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/lib/util_mosq.c b/lib/util_mosq.c index fda69801..65fc5f7d 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -104,6 +104,12 @@ int mosquitto__check_keepalive(struct mosquitto *mosq) pthread_mutex_unlock(&mosq->msgtime_mutex); }else{ #ifdef WITH_BROKER +# ifdef WITH_BRIDGE + if(mosq->bridge){ + context__send_will(mosq); + } +# endif +#endif net__socket_close(mosq); #else net__socket_close(mosq); From 2e061afcc6591c627c11ec79e93dd30f09aac022 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 3 Jun 2022 20:49:59 +0100 Subject: [PATCH 33/70] Fix build --- lib/util_mosq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/util_mosq.c b/lib/util_mosq.c index 65fc5f7d..f4f868b9 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -109,7 +109,6 @@ int mosquitto__check_keepalive(struct mosquitto *mosq) context__send_will(mosq); } # endif -#endif net__socket_close(mosq); #else net__socket_close(mosq); From 9417facffac9d69cd7dcbc1bf0a1af1b9edd4621 Mon Sep 17 00:00:00 2001 From: Pargorn Puttapirat Date: Thu, 23 Jun 2022 00:26:00 +0700 Subject: [PATCH 34/70] Fix syntax errors in examples Problematics examples: addRoleACL and removeRoleACL --- www/pages/documentation/dynamic-security.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/pages/documentation/dynamic-security.md b/www/pages/documentation/dynamic-security.md index 6570ace1..82f9635d 100644 --- a/www/pages/documentation/dynamic-security.md +++ b/www/pages/documentation/dynamic-security.md @@ -660,7 +660,7 @@ Where `acltype` is one of `publishClientSend`, `publishClientReceive`, For example: ``` -mosquitto_ctrl dynsec addRoleACL clientPublishSend client/topic allow 5 +mosquitto_ctrl dynsec addRoleACL publishClientSend client/topic allow 5 ``` To remove an ACL from a role using the topic filter as the key: @@ -670,7 +670,7 @@ mosquitto_ctrl dynsec removeRoleACL dynsec removeRoleACL clientPublishSend client/topic +mosquitto_ctrl dynsec removeRoleACL publishClientSend client/topic ``` To get information on a role: From ca009907e5f76c67790a83609e5fb267f104ec3b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Jul 2022 16:28:07 +0100 Subject: [PATCH 35/70] Web page update including external docs. --- www/pages/documentation.md | 12 ++++++ www/pages/index.html | 85 ++++++++++++++++++++++++-------------- 2 files changed, 67 insertions(+), 30 deletions(-) diff --git a/www/pages/documentation.md b/www/pages/documentation.md index cc728dc8..a464b4a6 100644 --- a/www/pages/documentation.md +++ b/www/pages/documentation.md @@ -31,6 +31,15 @@ * [Using the snap package] - specific instructions on installing and configuring the Mosquitto snap package. * [Migrating from 1.x to 2.0] - details of changes needed to migrate to version 2.0. +# Third party + +These are some Mosquitto documentation hosted by third parties. + +* [Steve's internet guide] - a broad range of documentation and examples + covering Mosquitto and the Paho Python client, amongst others. +* [docs.cedalo.com] - includes documentation for both Mosquitto and Eclipse + Streamsheets + [mosquitto]:/man/mosquitto-8.html [mosquitto.conf]:/man/mosquitto-conf-5.html [mosquitto_passwd]:/man/mosquitto_passwd-1.html @@ -46,3 +55,6 @@ [Using the snap package]:/documentation/using-the-snap/ [Dynamic Security plugin]:/documentation/dynamic-security/ [Migrating from 1.x to 2.0]:/documentation/migrating-to-2-0/ + +[Steve's internet guide]: http://www.steves-internet-guide.com/ +[docs.cedalo.com]: https://docs.cedalo.com/ diff --git a/www/pages/index.html b/www/pages/index.html index 5842835c..6ddcb05b 100644 --- a/www/pages/index.html +++ b/www/pages/index.html @@ -27,8 +27,8 @@ and mosquitto_sub command line MQTT clients.

Mosquitto is part of the Eclipse - Foundation, is an iot.eclipse.org - project and is sponsored by cedalo.com.

+ Foundation, and is an iot.eclipse.org + project. The development is driven by Cedalo.


@@ -37,43 +37,68 @@
-

Download

+

Download and Security

Mosquitto is highly portable and available for a wide range of platforms. Go to the dedicated download page to find the source or binaries for your platform.

Read the Change Log to find out about recent releases.

-
-
-

Test

-

You can have your own instance of Mosquitto running in - minutes, but to make testing even easier, the Mosquitto Project - runs a test server at test.mosquitto.org where - you can test your clients in a variety of ways: plain MQTT, - MQTT over TLS, MQTT over TLS (with client certificate), - MQTT over WebSockets and MQTT over WebSockets with TLS.

-
- -
-

Community

- - -
- -
-

Security

-

Use the security page to find out +

Use the security page to find out how to report vulnerabilities or responses to past security issues.

+ +
+

Test

+

You can have your own instance of Mosquitto running in + minutes, but to make testing even easier, the Mosquitto Project + runs a test server at + test.mosquitto.org where + you can test your clients in a variety of ways: plain MQTT, + MQTT over TLS, MQTT over TLS (with + client certificate), + MQTT over WebSockets and MQTT over WebSockets with TLS.

+
+
+ +
+
+

Community

+ +
+ +
+

Support

+

Support is always available from the community channels on a + best effort basis. If you require commercial support, + Cedalo can offer support for hosted + or on-premise instances, consulting on the use of Mosquitto, + and custom development to your needs.

+
+
+ +
+
+

Related Projects

+

Paho provides MQTT + client library implementations in a wide variety of + languages.

+

Streamsheets is an + easy to use web based real time spreadsheet interface that can + be used to process incoming data from a variety of sources, + such as MQTT, OPC-UA, and REST. Developers and non-developers + can use Streamsheets to control processes and build dashboards, + for example. Mosquitto is a core component of Streamsheets.

+
+
+
From ee1487743a870451b048e79eeecff9934ae357ca Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 6 Jul 2022 16:34:43 +0100 Subject: [PATCH 36/70] Remove dead link --- www/themes/mosquitto/templates/base_footer.tmpl | 1 - 1 file changed, 1 deletion(-) diff --git a/www/themes/mosquitto/templates/base_footer.tmpl b/www/themes/mosquitto/templates/base_footer.tmpl index 62693ab8..8b87c166 100644 --- a/www/themes/mosquitto/templates/base_footer.tmpl +++ b/www/themes/mosquitto/templates/base_footer.tmpl @@ -9,7 +9,6 @@ @@ -70,7 +70,7 @@
  • Talk to other users on the Mosquitto mailing list or on Slack.
  • Get help from the forums.
  • -
  • Cite Mosquitto in your academic work.
  • +
  • Cite Mosquitto in your academic work.
  • @@ -78,7 +78,7 @@

    Support

    Support is always available from the community channels on a best effort basis. If you require commercial support, - Cedalo can offer support for hosted + Cedalo can offer support for hosted or on-premise instances, consulting on the use of Mosquitto, and custom development to your needs.

    From 71a90177d7b23870147010e14a48e219c0a0fb81 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 20 Jul 2022 16:56:51 +0100 Subject: [PATCH 38/70] Systemd: Add mosquitto group ownership Thanks to minfrin --- service/systemd/mosquitto.service.notify | 4 ++-- service/systemd/mosquitto.service.simple | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/service/systemd/mosquitto.service.notify b/service/systemd/mosquitto.service.notify index d88a8868..06772dda 100644 --- a/service/systemd/mosquitto.service.notify +++ b/service/systemd/mosquitto.service.notify @@ -11,9 +11,9 @@ ExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto -ExecStartPre=/bin/chown mosquitto /var/log/mosquitto +ExecStartPre=/bin/chown mosquitto:mosquitto /var/log/mosquitto ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto -ExecStartPre=/bin/chown mosquitto /run/mosquitto +ExecStartPre=/bin/chown mosquitto:mosquitto /run/mosquitto [Install] WantedBy=multi-user.target diff --git a/service/systemd/mosquitto.service.simple b/service/systemd/mosquitto.service.simple index 80efecd4..15ee0d62 100644 --- a/service/systemd/mosquitto.service.simple +++ b/service/systemd/mosquitto.service.simple @@ -9,9 +9,9 @@ ExecStart=/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto -ExecStartPre=/bin/chown mosquitto /var/log/mosquitto +ExecStartPre=/bin/chown mosquitto:mosquitto /var/log/mosquitto ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto -ExecStartPre=/bin/chown mosquitto /run/mosquitto +ExecStartPre=/bin/chown mosquitto:mosquitto /run/mosquitto [Install] WantedBy=multi-user.target From efef2abdce58e131c34fa5312e62fa136364b8d6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 1 Aug 2022 22:26:45 +0100 Subject: [PATCH 39/70] Separate coverity scan branches scans. --- ...ity-scan.yml => coverity-scan-develop.yml} | 6 +++-- .github/workflows/coverity-scan-fixes.yml | 26 +++++++++++++++++++ .github/workflows/covsync.yml | 21 --------------- 3 files changed, 30 insertions(+), 23 deletions(-) rename .github/workflows/{coverity-scan.yml => coverity-scan-develop.yml} (80%) create mode 100644 .github/workflows/coverity-scan-fixes.yml delete mode 100644 .github/workflows/covsync.yml diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan-develop.yml similarity index 80% rename from .github/workflows/coverity-scan.yml rename to .github/workflows/coverity-scan-develop.yml index 27310bd7..0ef60c83 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan-develop.yml @@ -1,4 +1,4 @@ -name: Coverity Scan fixes and develop branches on a weekly basis +name: Coverity Scan develop branch on a weekly basis on: workflow_dispatch: @@ -9,7 +9,9 @@ jobs: coverity: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + with: + ref: develop - name: Dependencies run: sudo apt-get install -y libcjson-dev libsqlite3-dev libssl-dev uthash-dev diff --git a/.github/workflows/coverity-scan-fixes.yml b/.github/workflows/coverity-scan-fixes.yml new file mode 100644 index 00000000..2f11d013 --- /dev/null +++ b/.github/workflows/coverity-scan-fixes.yml @@ -0,0 +1,26 @@ +name: Coverity Scan fixes branch on a weekly basis + +on: + workflow_dispatch: + schedule: + - cron: "7 3 * * 3" + +jobs: + coverity: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: fixes + + - name: Dependencies + run: sudo apt-get install -y libcjson-dev libsqlite3-dev libssl-dev uthash-dev + + - uses: vapier/coverity-scan-action@v1 + with: + build_language: 'cxx' + project: "eclipse/mosquitto" + token: ${{ secrets.COVERITY_SCAN_TOKEN }} + email: ${{ secrets.COVERITY_SCAN_EMAIL }} + command: "make binary" + diff --git a/.github/workflows/covsync.yml b/.github/workflows/covsync.yml deleted file mode 100644 index 233b009e..00000000 --- a/.github/workflows/covsync.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "Synchronise Coverity Scan branches on a weekly basis" - -on: - workflow_dispatch: - schedule: - - cron: "7 3 * * 0" - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - run: | - git checkout coverity-fixes - git reset --hard origin/fixes - git push origin coverity-fixes - git checkout coverity-develop - git reset --hard origin/develop - git push origin coverity-develop From a146c218ad585aac8b67142f0f75c029bfc58b11 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 6 Aug 2022 22:49:08 +0100 Subject: [PATCH 40/70] Fix unlimited message quota not being properly checked. This is for incoming messages. Closes #2593. Thanks to dongguoqing2015. --- ChangeLog.txt | 2 ++ src/database.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index f5029030..6a55e4ee 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -53,6 +53,8 @@ Broker: - Fix broker sending duplicate CONNACK on failed MQTT v5 reauthentication. Closes #2339. - Fix mosquitto_plugin.h not including mosquitto_broker.h. Closes #2350. +- Fix unlimited message quota not being properly checked for incoming + messages. Closes #2593. Client library: - Initialise sockpairR/W to invalid in `mosquitto_reinitialise()` to avoid diff --git a/src/database.c b/src/database.c index df9778ba..061e1ed7 100644 --- a/src/database.c +++ b/src/database.c @@ -1188,7 +1188,7 @@ int db__message_write_queued_in(struct mosquitto *context) } DL_FOREACH_SAFE(context->msgs_in.queued, tail, tmp){ - if(context->msgs_out.inflight_maximum != 0 && context->msgs_in.inflight_quota == 0){ + if(context->msgs_in.inflight_maximum != 0 && context->msgs_in.inflight_quota == 0){ break; } From 8c0600c40c169601b68af8cf8769eda2cbefb599 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 6 Aug 2022 23:16:55 +0100 Subject: [PATCH 41/70] Fixed build for openssl compiled with OPENSSL_NO_ENGINE. Closes #2589. Thanks to Dirk Feytons. --- ChangeLog.txt | 1 + src/net.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 6a55e4ee..c5618b5d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -55,6 +55,7 @@ Broker: - Fix mosquitto_plugin.h not including mosquitto_broker.h. Closes #2350. - Fix unlimited message quota not being properly checked for incoming messages. Closes #2593. +- Fixed build for openssl compiled with OPENSSL_NO_ENGINE. Closes #2589. Client library: - Initialise sockpairR/W to invalid in `mosquitto_reinitialise()` to avoid diff --git a/src/net.c b/src/net.c index 71bf54c8..80d2c8d6 100644 --- a/src/net.c +++ b/src/net.c @@ -570,7 +570,7 @@ int net__tls_load_verify(struct mosquitto__listener *listener) #ifdef WITH_TLS int rc; -#if OPENSSL_VERSION_NUMBER < 0x30000000L +# if OPENSSL_VERSION_NUMBER < 0x30000000L if(listener->cafile || listener->capath){ rc = SSL_CTX_load_verify_locations(listener->ssl_ctx, listener->cafile, listener->capath); if(rc == 0){ @@ -583,7 +583,7 @@ int net__tls_load_verify(struct mosquitto__listener *listener) } } } -#else +# else if(listener->cafile){ rc = SSL_CTX_load_verify_file(listener->ssl_ctx, listener->cafile); if(rc == 0){ @@ -600,11 +600,13 @@ int net__tls_load_verify(struct mosquitto__listener *listener) return MOSQ_ERR_TLS; } } -#endif +# endif +# if !defined(OPENSSL_NO_ENGINE) if(net__load_engine(listener)){ return MOSQ_ERR_TLS; } +# endif #endif return net__load_certificates(listener); } From 0c9d9f21633c5dbb482893a9d6bdf40111829925 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sun, 7 Aug 2022 23:04:46 +0100 Subject: [PATCH 42/70] Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes #2564. Thanks to nmeum. --- ChangeLog.txt | 1 + lib/mosquitto.c | 4 ---- lib/net_mosq.c | 6 +----- lib/net_mosq.h | 5 +++++ 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index c5618b5d..70557603 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -21,6 +21,7 @@ Client library: cmake version to 3.1, which is still ancient. - Fix use of `MOSQ_OPT_TLS_ENGINE` being unable to be used due to the openssl ctx not being initialised until starting to connect. Closes #2537. +- Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes #2564. Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 0d68d313..72762ed6 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -109,10 +109,6 @@ struct mosquitto *mosquitto_new(const char *id, bool clean_start, void *userdata return NULL; } -#ifndef WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - mosq = (struct mosquitto *)mosquitto__calloc(1, sizeof(struct mosquitto)); if(mosq){ mosq->sock = INVALID_SOCKET; diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 22f5a313..d4eb89ef 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -1041,11 +1041,7 @@ ssize_t net__write(struct mosquitto *mosq, const void *buf, size_t count) /* Call normal write/send */ #endif -#ifndef WIN32 - return write(mosq->sock, buf, count); -#else - return send(mosq->sock, buf, count, 0); -#endif + return send(mosq->sock, buf, count, MSG_NOSIGNAL); #ifdef WITH_TLS } diff --git a/lib/net_mosq.h b/lib/net_mosq.h index 37a21461..ded98760 100644 --- a/lib/net_mosq.h +++ b/lib/net_mosq.h @@ -19,6 +19,7 @@ Contributors: #define NET_MOSQ_H #ifndef WIN32 +# include # include #else # include @@ -51,6 +52,10 @@ typedef SSIZE_T ssize_t; #define INVALID_SOCKET -1 #endif +#ifndef MSG_NOSIGNAL +# define MSG_NOSIGNAL 0 +#endif + /* Macros for accessing the MSB and LSB of a uint16_t */ #define MOSQ_MSB(A) (uint8_t)((A & 0xFF00) >> 8) #define MOSQ_LSB(A) (uint8_t)(A & 0x00FF) From ba6bbd59590df3131d27e7f29cc46dcc05328b32 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 8 Aug 2022 00:01:56 +0100 Subject: [PATCH 43/70] Add documentation of struct mosquitto_message to header. Closes #2561. --- ChangeLog.txt | 1 + include/mosquitto.h | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 70557603..082c233a 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -22,6 +22,7 @@ Client library: - Fix use of `MOSQ_OPT_TLS_ENGINE` being unable to be used due to the openssl ctx not being initialised until starting to connect. Closes #2537. - Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes #2564. +- Add documentation of struct mosquitto_message to header. Closes #2561. Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. diff --git a/include/mosquitto.h b/include/mosquitto.h index 8fc43a95..a169ab7f 100644 --- a/include/mosquitto.h +++ b/include/mosquitto.h @@ -83,7 +83,8 @@ extern "C" { #define MOSQ_LOG_INTERNAL 0x80000000U #define MOSQ_LOG_ALL 0xFFFFFFFFU -/* Error values */ +/* Enum: mosq_err_t + * Integer values returned from many libmosquitto functions. */ enum mosq_err_t { MOSQ_ERR_AUTH_CONTINUE = -4, MOSQ_ERR_NO_SUBSCRIBERS = -3, @@ -123,7 +124,12 @@ enum mosq_err_t { MOSQ_ERR_ALREADY_EXISTS = 31, }; -/* Option values */ +/* Enum: mosq_opt_t + * + * Client options. + * + * See , , and . + */ enum mosq_opt_t { MOSQ_OPT_PROTOCOL_VERSION = 1, MOSQ_OPT_SSL_CTX = 2, @@ -148,6 +154,24 @@ enum mosq_opt_t { #define MQTT_PROTOCOL_V311 4 #define MQTT_PROTOCOL_V5 5 +/* Struct: mosquitto_message + * + * Contains details of a PUBLISH message. + * + * int mid - the message/packet ID of the PUBLISH message, assuming this is a + * QoS 1 or 2 message. Will be set to 0 for QoS 0 messages. + * + * char *topic - the topic the message was delivered on. + * + * void *payload - the message payload. This will be payloadlen bytes long, and + * may be NULL if a zero length payload was sent. + * + * int payloadlen - the length of the payload, in bytes. + * + * int qos - the quality of service of the message, 0, 1, or 2. + * + * bool retain - set to true for stale retained messages. + */ struct mosquitto_message{ int mid; char *topic; From a913de2d28e361c6396dc49e50a9987919324b33 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 8 Aug 2022 00:29:37 +0100 Subject: [PATCH 44/70] Fix some PUBLISH messages not being counted in $SYS stats. Closes #2448. Thanks to Antoine. --- ChangeLog.txt | 1 + lib/packet_mosq.c | 2 +- src/websockets.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 082c233a..4b1f133c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -15,6 +15,7 @@ Broker: persistence. Closes #2546. - Fix bridges not sending failure notification messages to the local broker if the remote bridge connection fails. Closes #2467. Closes #1488. +- Fix some PUBLISH messages not being counted in $SYS stats. Closes #2448. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index f65769f6..f3f3dcc5 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -546,7 +546,7 @@ int packet__read(struct mosquitto *mosq) mosq->in_packet.pos = 0; #ifdef WITH_BROKER G_MSGS_RECEIVED_INC(1); - if(((mosq->in_packet.command)&0xF5) == CMD_PUBLISH){ + if(((mosq->in_packet.command)&0xF0) == CMD_PUBLISH){ G_PUB_MSGS_RECEIVED_INC(1); } #endif diff --git a/src/websockets.c b/src/websockets.c index 74e36d31..c6990e70 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -261,7 +261,7 @@ static int callback_mqtt( #ifdef WITH_SYS_TREE g_msgs_sent++; - if(((packet->command)&0xF6) == CMD_PUBLISH){ + if(((packet->command)&0xF0) == CMD_PUBLISH){ g_pub_msgs_sent++; } #endif @@ -356,7 +356,7 @@ static int callback_mqtt( #ifdef WITH_SYS_TREE G_MSGS_RECEIVED_INC(1); - if(((mosq->in_packet.command)&0xF5) == CMD_PUBLISH){ + if(((mosq->in_packet.command)&0xF0) == CMD_PUBLISH){ G_PUB_MSGS_RECEIVED_INC(1); } #endif From e979a46c048a8c60c53614548c4a98dfd4992cf4 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 5 Aug 2022 22:14:37 +0100 Subject: [PATCH 45/70] Backport SSL connect fixes. Closes #2594. Closes #2595. --- ChangeLog.txt | 1 + lib/loop.c | 30 +++--------------------------- lib/mosquitto.c | 2 -- lib/mosquitto_internal.h | 1 - lib/net_mosq.c | 26 +------------------------- lib/packet_mosq.c | 4 ---- 6 files changed, 5 insertions(+), 59 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 4b1f133c..9a1abd42 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -22,6 +22,7 @@ Client library: cmake version to 3.1, which is still ancient. - Fix use of `MOSQ_OPT_TLS_ENGINE` being unable to be used due to the openssl ctx not being initialised until starting to connect. Closes #2537. +- Fix incorrect use of SSL_connect. Closes #2594. - Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes #2564. - Add documentation of struct mosquitto_message to header. Closes #2561. diff --git a/lib/loop.c b/lib/loop.c index 2c35ee19..eb12854e 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -72,12 +72,6 @@ int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) if(mosq->ssl){ if(mosq->want_write){ FD_SET(mosq->sock, &writefds); - }else if(mosq->want_connect){ - /* Remove possible FD_SET from above, we don't want to check - * for writing if we are still connecting, unless want_write is - * definitely set. The presence of outgoing packets does not - * matter yet. */ - FD_CLR(mosq->sock, &writefds); } } #endif @@ -169,17 +163,9 @@ int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) FD_SET(mosq->sock, &writefds); } if(mosq->sock != INVALID_SOCKET && FD_ISSET(mosq->sock, &writefds)){ -#ifdef WITH_TLS - if(mosq->want_connect){ - rc = net__socket_connect_tls(mosq); - if(rc) return rc; - }else -#endif - { - rc = mosquitto_loop_write(mosq, max_packets); - if(rc || mosq->sock == INVALID_SOCKET){ - return rc; - } + rc = mosquitto_loop_write(mosq, max_packets); + if(rc || mosq->sock == INVALID_SOCKET){ + return rc; } } } @@ -373,16 +359,6 @@ int mosquitto_loop_read(struct mosquitto *mosq, int max_packets) int i; if(max_packets < 1) return MOSQ_ERR_INVAL; -#ifdef WITH_TLS - if(mosq->want_connect){ - rc = net__socket_connect_tls(mosq); - if (MOSQ_ERR_TLS == rc){ - rc = mosquitto__loop_rc_handle(mosq, rc); - } - return rc; - } -#endif - pthread_mutex_lock(&mosq->msgs_out.mutex); max_packets = mosq->msgs_out.queue_len; pthread_mutex_unlock(&mosq->msgs_out.mutex); diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 72762ed6..9f23adfd 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -334,8 +334,6 @@ bool mosquitto_want_write(struct mosquitto *mosq) if(mosq->ssl){ if (mosq->want_write) { result = true; - }else if(mosq->want_connect){ - result = false; } } #endif diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 8d066388..87718ea9 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -272,7 +272,6 @@ struct mosquitto { enum mosquitto__keyform tls_keyform; #endif bool want_write; - bool want_connect; #if defined(WITH_THREADING) && !defined(WITH_BROKER) pthread_mutex_t callback_mutex; pthread_mutex_t log_callback_mutex; diff --git a/lib/net_mosq.c b/lib/net_mosq.c index d4eb89ef..28654b14 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -569,31 +569,7 @@ int net__socket_connect_tls(struct mosquitto *mosq) return MOSQ_ERR_OCSP; } } - - ret = SSL_connect(mosq->ssl); - if(ret != 1) { - err = SSL_get_error(mosq->ssl, ret); - if (err == SSL_ERROR_SYSCALL) { - mosq->want_connect = true; - return MOSQ_ERR_SUCCESS; - } - if(err == SSL_ERROR_WANT_READ){ - mosq->want_connect = true; - /* We always try to read anyway */ - }else if(err == SSL_ERROR_WANT_WRITE){ - mosq->want_write = true; - mosq->want_connect = true; - }else{ - net__print_ssl_error(mosq); - - COMPAT_CLOSE(mosq->sock); - mosq->sock = INVALID_SOCKET; - net__print_ssl_error(mosq); - return MOSQ_ERR_TLS; - } - }else{ - mosq->want_connect = false; - } + SSL_set_connect_state(mosq->ssl); return MOSQ_ERR_SUCCESS; } #endif diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index f3f3dcc5..80f47168 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -236,11 +236,7 @@ int packet__write(struct mosquitto *mosq) #endif state = mosquitto__get_state(mosq); -#if defined(WITH_TLS) && !defined(WITH_BROKER) - if(state == mosq_cs_connect_pending || mosq->want_connect){ -#else if(state == mosq_cs_connect_pending){ -#endif pthread_mutex_unlock(&mosq->current_out_packet_mutex); return MOSQ_ERR_SUCCESS; } From 08610f7c99c599deaf0b209ec30b89aca240c9d2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 5 Aug 2022 22:57:27 +0100 Subject: [PATCH 46/70] Further fix for #2546. --- src/persist_write.c | 5 +++++ src/session_expiry.c | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/persist_write.c b/src/persist_write.c index ccfbc29c..0df016ec 100644 --- a/src/persist_write.c +++ b/src/persist_write.c @@ -169,6 +169,11 @@ static int persist__client_save(FILE *db_fptr) HASH_ITER(hh_id, db.contexts_by_id, context, ctxt_tmp){ if(context && context->clean_start == false){ chunk.F.session_expiry_time = context->session_expiry_time; + if(context->session_expiry_interval != 0 && context->session_expiry_interval != UINT32_MAX && context->session_expiry_time == 0){ + chunk.F.session_expiry_time = context->session_expiry_interval + db.now_real_s; + }else{ + chunk.F.session_expiry_time = context->session_expiry_time; + } chunk.F.session_expiry_interval = context->session_expiry_interval; chunk.F.last_mid = context->last_mid; chunk.F.id_len = (uint16_t)strlen(context->id); diff --git a/src/session_expiry.c b/src/session_expiry.c index 470a12a6..98913d8a 100644 --- a/src/session_expiry.c +++ b/src/session_expiry.c @@ -86,6 +86,14 @@ int session_expiry__add_from_persistence(struct mosquitto *context, time_t expir { struct session_expiry_list *item; + if(db.config->persistent_client_expiration == 0){ + if(context->session_expiry_interval == UINT32_MAX){ + /* There isn't a global expiry set, and the client has asked to + * never expire, so we don't add it to the list. */ + return MOSQ_ERR_SUCCESS; + } + } + item = mosquitto__calloc(1, sizeof(struct session_expiry_list)); if(!item) return MOSQ_ERR_NOMEM; From 351911bd8f0bfe93f37b92e56f8447fed86f4e8b Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Aug 2022 14:09:47 +0100 Subject: [PATCH 47/70] Fix incorrect return code being sent in DISCONNECT. This is for when a client session is taken over. Closes #2607. Thanks to der-b --- ChangeLog.txt | 2 ++ src/handle_connect.c | 4 ++++ test/broker/01-connect-take-over.py | 34 +++++++++++++++++++++++++++++ test/broker/Makefile | 1 + test/broker/test.py | 1 + 5 files changed, 42 insertions(+) create mode 100755 test/broker/01-connect-take-over.py diff --git a/ChangeLog.txt b/ChangeLog.txt index 9a1abd42..975fb8a1 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -16,6 +16,8 @@ Broker: - Fix bridges not sending failure notification messages to the local broker if the remote bridge connection fails. Closes #2467. Closes #1488. - Fix some PUBLISH messages not being counted in $SYS stats. Closes #2448. +- Fix incorrect return code being sent in DISCONNECT when a client session is + taken over. Closes #2607. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/src/handle_connect.c b/src/handle_connect.c index dcc8ea5c..790c88a2 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -205,6 +205,10 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1 found_context->clean_start = true; found_context->session_expiry_interval = 0; mosquitto__set_state(found_context, mosq_cs_duplicate); + + if(found_context->protocol == mosq_p_mqtt5){ + send__disconnect(found_context, MQTT_RC_SESSION_TAKEN_OVER, NULL); + } do_disconnect(found_context, MOSQ_ERR_SUCCESS); } diff --git a/test/broker/01-connect-take-over.py b/test/broker/01-connect-take-over.py new file mode 100755 index 00000000..a275ad7e --- /dev/null +++ b/test/broker/01-connect-take-over.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +# MQTT v5 session takeover test + +from mosq_test_helper import * + +port = mosq_test.get_port() +broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + +try: + rc = 1 + connect_packet = mosq_test.gen_connect("take-over", proto_ver=5) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5) + disconnect_packet = mosq_test.gen_disconnect(reason_code=mqtt5_rc.MQTT_RC_SESSION_TAKEN_OVER, proto_ver=5) + + sock1 = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + sock2 = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.expect_packet(sock1, "disconnect", disconnect_packet) + mosq_test.do_ping(sock2) + + sock2.close() + sock1.close() + rc = 0 +except mosq_test.TestError: + pass +except Exception as e: + print(e) +finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + exit(rc) diff --git a/test/broker/Makefile b/test/broker/Makefile index 5883645c..63b9ae8f 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -28,6 +28,7 @@ msg_sequence_test: ./01-connect-disconnect-v5.py ./01-connect-max-connections.py ./01-connect-max-keepalive.py + ./01-connect-take-over.py ./01-connect-uname-no-password-denied.py ./01-connect-uname-or-anon.py ./01-connect-uname-password-denied-no-will.py diff --git a/test/broker/test.py b/test/broker/test.py index 26361c56..e034a83d 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -10,6 +10,7 @@ tests = [ (1, './01-connect-disconnect-v5.py'), (1, './01-connect-max-connections.py'), (1, './01-connect-max-keepalive.py'), + (1, './01-connect-take-over.py'), (1, './01-connect-uname-no-password-denied.py'), (1, './01-connect-uname-or-anon.py'), (1, './01-connect-uname-password-denied-no-will.py'), From 6468bb4f9b1ca75e7c546c9da2a9897e8fce4872 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Aug 2022 14:31:34 +0100 Subject: [PATCH 48/70] Fix documentation omission around mosquitto_reinitialise. Closes #2489. Thanks to rroguski --- ChangeLog.txt | 1 + include/mosquitto.h | 7 ++++--- lib/mosquitto.c | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 975fb8a1..f84d38c9 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -27,6 +27,7 @@ Client library: - Fix incorrect use of SSL_connect. Closes #2594. - Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes #2564. - Add documentation of struct mosquitto_message to header. Closes #2561. +- Fix documentation omission around mosquitto_reinitialise. Closes #2489. Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. diff --git a/include/mosquitto.h b/include/mosquitto.h index a169ab7f..1c860ac8 100644 --- a/include/mosquitto.h +++ b/include/mosquitto.h @@ -346,9 +346,10 @@ libmosq_EXPORT void mosquitto_destroy(struct mosquitto *mosq); * callbacks that are specified. * * Returns: - * MOSQ_ERR_SUCCESS - on success. - * MOSQ_ERR_INVAL - if the input parameters were invalid. - * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_SUCCESS - on success. + * MOSQ_ERR_INVAL - if the input parameters were invalid. + * MOSQ_ERR_NOMEM - if an out of memory condition occurred. + * MOSQ_ERR_MALFORMED_UTF8 - if the client id is not valid UTF-8. * * See Also: * , diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 9f23adfd..27a44c15 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -163,6 +163,9 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st return MOSQ_ERR_MALFORMED_UTF8; } mosq->id = mosquitto__strdup(id); + if(!mosq->id){ + return MOSQ_ERR_NOMEM; + } } mosq->in_packet.payload = NULL; packet__cleanup(&mosq->in_packet); From f9fa19ce6a8f79d4d73c039a7e6aea5db05e6d83 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Aug 2022 15:11:52 +0100 Subject: [PATCH 49/70] - Fix `-o` not working in `mosquitto_ctrl`, and typo in related documentation. Closes #2471. Thanks to Vitaljok and rillbert --- ChangeLog.txt | 5 +++++ apps/mosquitto_ctrl/options.c | 9 +++++---- www/pages/documentation/dynamic-security.md | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index f84d38c9..6e2376e0 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -33,6 +33,11 @@ Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. Closes #2494. +Apps: +- Fix `-o` not working in `mosquitto_ctrl`, and typo in related documentation. + Closes #2471. + + 2.0.14 - 2021-11-17 =================== diff --git a/apps/mosquitto_ctrl/options.c b/apps/mosquitto_ctrl/options.c index 5c36e5db..592d9e8c 100644 --- a/apps/mosquitto_ctrl/options.c +++ b/apps/mosquitto_ctrl/options.c @@ -89,13 +89,14 @@ int ctrl_config_parse(struct mosq_config *cfg, int *argc, char **argv[]) init_config(cfg); - rc = client_config_load(cfg); - if(rc) return rc; - /* Deal with real argc/argv */ rc = client_config_line_proc(cfg, argc, argv); if(rc) return rc; + /* Load options from config file - this must be after `-o` has been processed */ + rc = client_config_load(cfg); + if(rc) return rc; + #ifdef WITH_TLS if((cfg->certfile && !cfg->keyfile) || (cfg->keyfile && !cfg->certfile)){ fprintf(stderr, "Error: Both certfile and keyfile must be provided if one of them is set.\n"); @@ -531,7 +532,7 @@ int client_config_load(struct mosq_config *cfg) fclose(fptr); return 1; } - while(fgets(line, 1024, fptr)){ + while(fgets(line, sizeof(line), fptr)){ if(line[0] == '#') continue; /* Comments */ while(line[strlen(line)-1] == 10 || line[strlen(line)-1] == 13){ diff --git a/www/pages/documentation/dynamic-security.md b/www/pages/documentation/dynamic-security.md index a84f8589..b3550ac1 100644 --- a/www/pages/documentation/dynamic-security.md +++ b/www/pages/documentation/dynamic-security.md @@ -389,9 +389,9 @@ admin username and any other options once and not have to add them to the command line every time. mosquitto_ctrl will try to load a configuration file from a default location. -For Windows this is at `%USER_PROFILE%\mosquitto_ctrl.conf`. For other systems, -it will try `$XDG_CONFIG_HOME/mosquitto_ctrl.conf` or -`$HOME/.config/mosquitto_ctrl.conf`. +For Windows this is at `%USER_PROFILE%\mosquitto_ctrl`. For other systems, +it will try `$XDG_CONFIG_HOME/mosquitto_ctrl` or +`$HOME/.config/mosquitto_ctrl`. You may override this behaviour by manually specifying an options file with `-o `. From 02b92b97ef35aae503559d589cec797800a5be61 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Wed, 10 Aug 2022 17:18:33 +0100 Subject: [PATCH 50/70] Fix use of MOSQ_OPT_SSL_CTX when used with MOSQ_OPT_SSL_CTX_DEFAULTS Closes #2463. Thanks to Tim Nordell. --- ChangeLog.txt | 2 + lib/net_mosq.c | 2 +- test/lib/Makefile | 2 + ...connect-cert-auth-custom-ssl-ctx-default.c | 59 +++++++++++++++++ .../08-ssl-connect-cert-auth-custom-ssl-ctx.c | 63 +++++++++++++++++++ test/lib/c/Makefile | 9 +++ test/lib/test.py | 2 + 7 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c create mode 100644 test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c diff --git a/ChangeLog.txt b/ChangeLog.txt index 6e2376e0..81bf20c8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -28,6 +28,8 @@ Client library: - Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes #2564. - Add documentation of struct mosquitto_message to header. Closes #2561. - Fix documentation omission around mosquitto_reinitialise. Closes #2489. +- Fix use of MOSQ_OPT_SSL_CTX when used in conjunction with + MOSQ_OPT_SSL_CTX_DEFAULTS. Closes #2463. Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 28654b14..80d9195b 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -661,8 +661,8 @@ static int net__init_ssl_ctx(struct mosquitto *mosq) * has not been set, or if both of MOSQ_OPT_SSL_CTX and * MOSQ_OPT_SSL_CTX_WITH_DEFAULTS are set. */ if(mosq->tls_cafile || mosq->tls_capath || mosq->tls_psk || mosq->tls_use_os_certs){ + net__init_tls(); if(!mosq->ssl_ctx){ - net__init_tls(); #if OPENSSL_VERSION_NUMBER < 0x10100000L mosq->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); diff --git a/test/lib/Makefile b/test/lib/Makefile index 65d49ca2..6ade78d0 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -65,6 +65,8 @@ ifeq ($(WITH_TLS),yes) ./08-ssl-bad-cacert.py $@/08-ssl-bad-cacert.test ./08-ssl-connect-cert-auth-enc.py $@/08-ssl-connect-cert-auth-enc.test ./08-ssl-connect-cert-auth.py $@/08-ssl-connect-cert-auth.test + ./08-ssl-connect-cert-auth.py $@/08-ssl-connect-cert-auth-custom-ssl-ctx.test + ./08-ssl-connect-cert-auth.py $@/08-ssl-connect-cert-auth-custom-ssl-ctx-default.test ./08-ssl-connect-no-auth.py $@/08-ssl-connect-no-auth.test endif ./09-util-topic-tokenise.py $@/09-util-topic-tokenise.test diff --git a/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c new file mode 100644 index 00000000..2a0d5baf --- /dev/null +++ b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_disconnect(mosq); + } +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = rc; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + SSL_CTX *ssl_ctx; + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ + | OPENSSL_INIT_ADD_ALL_DIGESTS \ + | OPENSSL_INIT_LOAD_CONFIG, NULL); + ssl_ctx = SSL_CTX_new(TLS_client_method()); + + mosq = mosquitto_new("08-ssl-connect-crt-auth", true, NULL); + if(mosq == NULL){ + return 1; + } + + mosquitto_int_option(mosq, MOSQ_OPT_SSL_CTX_WITH_DEFAULTS, 1); + mosquitto_void_option(mosq, MOSQ_OPT_SSL_CTX, ssl_ctx); + + mosquitto_tls_set(mosq, "../ssl/test-root-ca.crt", "../ssl/certs", "../ssl/client.crt", "../ssl/client.key", NULL); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, -1, 1); + } + mosquitto_destroy(mosq); + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c new file mode 100644 index 00000000..5d9866ef --- /dev/null +++ b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include + +static int run = -1; + +void on_connect(struct mosquitto *mosq, void *obj, int rc) +{ + if(rc){ + exit(1); + }else{ + mosquitto_disconnect(mosq); + } +} + +void on_disconnect(struct mosquitto *mosq, void *obj, int rc) +{ + run = rc; +} + +int main(int argc, char *argv[]) +{ + int rc; + struct mosquitto *mosq; + SSL_CTX *ssl_ctx; + int port = atoi(argv[1]); + + mosquitto_lib_init(); + + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ + | OPENSSL_INIT_ADD_ALL_DIGESTS \ + | OPENSSL_INIT_LOAD_CONFIG, NULL); + ssl_ctx = SSL_CTX_new(TLS_client_method()); + + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + SSL_CTX_use_certificate_chain_file(ssl_ctx, "../ssl/client.crt"); + SSL_CTX_use_PrivateKey_file(ssl_ctx, "../ssl/client.key", SSL_FILETYPE_PEM); + SSL_CTX_load_verify_locations(ssl_ctx, "../ssl/test-root-ca.crt", "../ssl/certs"); + + mosq = mosquitto_new("08-ssl-connect-crt-auth", true, NULL); + if(mosq == NULL){ + return 1; + } + mosquitto_tls_set(mosq, "../ssl/test-root-ca.crt", "../ssl/certs", "../ssl/client.crt", "../ssl/client.key", NULL); + mosquitto_connect_callback_set(mosq, on_connect); + mosquitto_disconnect_callback_set(mosq, on_disconnect); + + mosquitto_int_option(mosq, MOSQ_OPT_SSL_CTX_WITH_DEFAULTS, 0); + mosquitto_void_option(mosq, MOSQ_OPT_SSL_CTX, ssl_ctx); + + rc = mosquitto_connect(mosq, "localhost", port, 60); + + while(run == -1){ + mosquitto_loop(mosq, -1, 1); + } + mosquitto_destroy(mosq); + + mosquitto_lib_cleanup(); + return run; +} diff --git a/test/lib/c/Makefile b/test/lib/c/Makefile index 6c09e806..40cb7d15 100644 --- a/test/lib/c/Makefile +++ b/test/lib/c/Makefile @@ -1,3 +1,5 @@ +include ../../../config.mk + .PHONY: all clean reallyclean CFLAGS=-I../../../include -Werror @@ -55,6 +57,13 @@ SRC = \ 11-prop-send-payload-format.c \ 11-prop-send-content-type.c +ifeq ($(WITH_TLS),yes) +SRC += \ + 08-ssl-connect-cert-auth-custom-ssl-ctx.c \ + 08-ssl-connect-cert-auth-custom-ssl-ctx-default.c +LIBS += -lssl -lcrypto +endif + TESTS = ${SRC:.c=.test} all : ${TESTS} diff --git a/test/lib/test.py b/test/lib/test.py index eb56e718..6f06c3f7 100755 --- a/test/lib/test.py +++ b/test/lib/test.py @@ -48,6 +48,8 @@ tests = [ (1, ['./08-ssl-bad-cacert.py', 'c/08-ssl-bad-cacert.test']), (1, ['./08-ssl-connect-cert-auth-enc.py', 'c/08-ssl-connect-cert-auth-enc.test']), (1, ['./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth.test']), + (1, ['./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth-custom-ssl-ctx.test']), + (1, ['./08-ssl-connect-cert-auth.py', 'c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.test']), (1, ['./08-ssl-connect-no-auth.py', 'c/08-ssl-connect-no-auth.test']), (1, ['./09-util-topic-tokenise.py', 'c/09-util-topic-tokenise.test']), From c4664f08aca4dd9ade15d5006a4bef53f9f3a6a9 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 11 Aug 2022 11:51:53 +0100 Subject: [PATCH 51/70] Clarify use_username_as_clientid is not global --- man/mosquitto.conf.5.xml | 1 + mosquitto.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 4121a8d4..35e016c8 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1263,6 +1263,7 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S disconnected as not authorised when this option is set to true. Do not use in conjunction with .
    + This does not apply globally, but on a per-listener basis. See also . Not reloaded on reload signal. diff --git a/mosquitto.conf b/mosquitto.conf index 8da8a59e..10b0406e 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -290,6 +290,7 @@ # authorised when this option is set to true. # Do not use in conjunction with clientid_prefixes. # See also use_identity_as_username. +# This does not apply globally, but on a per-listener basis. #use_username_as_clientid # Change the websockets headers size. This is a global option, it is not From 268a2bae4799f6aadad7d8fb0314e9048ace0007 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 11 Aug 2022 15:20:13 +0100 Subject: [PATCH 52/70] Update lock-threads workflow --- .github/lock.yml | 35 ----------------------------------- .github/workflows/lock.yml | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 35 deletions(-) delete mode 100644 .github/lock.yml create mode 100644 .github/workflows/lock.yml diff --git a/.github/lock.yml b/.github/lock.yml deleted file mode 100644 index 916ac1f7..00000000 --- a/.github/lock.yml +++ /dev/null @@ -1,35 +0,0 @@ -# Configuration for Lock Threads - https://github.com/dessant/lock-threads - -# Number of days of inactivity before a closed issue or pull request is locked -daysUntilLock: 90 - -# Skip issues and pull requests created before a given timestamp. Timestamp must -# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable -skipCreatedBefore: false - -# Issues and pull requests with these labels will be ignored. Set to `[]` to disable -exemptLabels: [] - -# Label to add before locking, such as `outdated`. Set to `false` to disable -lockLabel: false - -# Comment to post before locking. Set to `false` to disable -lockComment: false - -# Assign `resolved` as the reason for locking. Set to `false` to disable -setLockReason: true - -# Limit to only `issues` or `pulls` -only: issues - -# Optionally, specify configuration settings just for `issues` or `pulls` -# issues: -# exemptLabels: -# - help-wanted -# lockLabel: outdated - -# pulls: -# daysUntilLock: 30 - -# Repository to extend settings from -# _extends: repo diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 00000000..8331df74 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,21 @@ +name: 'Lock Threads' + +on: + schedule: + - cron: '0 * * * *' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +concurrency: + group: lock + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v3 + with: + issue-inactive-days: '90' From 775bd2effde71c5f64334de94b40371bece8c155 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 12 Aug 2022 08:17:17 +0100 Subject: [PATCH 53/70] Fix confusing "out of memory" error. This happens when a client is kicked in the dynamic security plugin. Closes #2525. Thanks to sezanzeb. --- ChangeLog.txt | 2 ++ src/control.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 81bf20c8..e89fe76c 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -18,6 +18,8 @@ Broker: - Fix some PUBLISH messages not being counted in $SYS stats. Closes #2448. - Fix incorrect return code being sent in DISCONNECT when a client session is taken over. Closes #2607. +- Fix confusing "out of memory" error when a client is kicked in the dynamic + security plugin. Closes #2525. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/src/control.c b/src/control.c index 88c4e9da..8a70a967 100644 --- a/src/control.c +++ b/src/control.c @@ -65,9 +65,9 @@ int control__process(struct mosquitto *context, struct mosquitto_msg_store *stor } if(stored->qos == 1){ - if(send__puback(context, stored->source_mid, MQTT_RC_SUCCESS, properties)) rc = 1; + rc = send__puback(context, stored->source_mid, MQTT_RC_SUCCESS, properties); }else if(stored->qos == 2){ - if(send__pubrec(context, stored->source_mid, MQTT_RC_SUCCESS, properties)) rc = 1; + rc = send__pubrec(context, stored->source_mid, MQTT_RC_SUCCESS, properties); } mosquitto_property_free_all(&properties); From 80c7726d5cf26eba7bae38e79bd7260ca7196eee Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 12 Aug 2022 08:34:56 +0100 Subject: [PATCH 54/70] Fix confusing error message when dynamic security config file was a directory. Closes #2520. Thanks to sezanzeb --- ChangeLog.txt | 2 ++ plugins/dynamic-security/plugin.c | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index e89fe76c..a0614d89 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -20,6 +20,8 @@ Broker: taken over. Closes #2607. - Fix confusing "out of memory" error when a client is kicked in the dynamic security plugin. Closes #2525. +- Fix confusing error message when dynamic security config file was a + directory. Closes #2520. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/plugins/dynamic-security/plugin.c b/plugins/dynamic-security/plugin.c index ae9f2e7d..45c9229b 100644 --- a/plugins/dynamic-security/plugin.c +++ b/plugins/dynamic-security/plugin.c @@ -361,15 +361,21 @@ static int dynsec__config_load(void) fptr = fopen(config_file, "rb"); if(fptr == NULL){ mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not readable - check permissions.\n"); - return 1; + return MOSQ_ERR_ERRNO; } +#ifndef WIN32 + if(errno == ENOTDIR || errno == EISDIR){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: Config is not a file.\n"); + return MOSQ_ERR_ERRNO; + } +#endif fseek(fptr, 0, SEEK_END); flen_l = ftell(fptr); if(flen_l < 0){ mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: %s\n", strerror(errno)); fclose(fptr); - return 1; + return MOSQ_ERR_ERRNO; }else if(flen_l == 0){ fclose(fptr); return 0; @@ -380,13 +386,13 @@ static int dynsec__config_load(void) if(json_str == NULL){ mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); fclose(fptr); - return 1; + return MOSQ_ERR_NOMEM; } if(fread(json_str, 1, flen, fptr) != flen){ mosquitto_log_printf(MOSQ_LOG_WARNING, "Error loading Dynamic security plugin config: Unable to read file contents.\n"); mosquitto_free(json_str); fclose(fptr); - return 1; + return MOSQ_ERR_ERRNO; } fclose(fptr); @@ -394,7 +400,7 @@ static int dynsec__config_load(void) mosquitto_free(json_str); if(tree == NULL){ mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not valid JSON.\n"); - return 1; + return MOSQ_ERR_INVAL; } if(dynsec__general_config_load(tree) @@ -404,7 +410,7 @@ static int dynsec__config_load(void) ){ cJSON_Delete(tree); - return 1; + return MOSQ_ERR_NOMEM; } cJSON_Delete(tree); From 5d18962486bf4cee693cc474ecb704021e03ada3 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 12 Aug 2022 08:52:40 +0100 Subject: [PATCH 55/70] Improve custom SSL_CTX tests. Issue #2463. --- .../c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c | 8 ++++++++ test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c index 2a0d5baf..f92fcb9c 100644 --- a/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c +++ b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx-default.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,6 +8,11 @@ static int run = -1; +void handle_sigint(int signal) +{ + run = 0; +} + void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ @@ -49,9 +55,11 @@ int main(int argc, char *argv[]) rc = mosquitto_connect(mosq, "localhost", port, 60); + signal(SIGINT, handle_sigint); while(run == -1){ mosquitto_loop(mosq, -1, 1); } + SSL_CTX_free(ssl_ctx); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); diff --git a/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c index 5d9866ef..e0fe94ef 100644 --- a/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c +++ b/test/lib/c/08-ssl-connect-cert-auth-custom-ssl-ctx.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,6 +8,11 @@ static int run = -1; +void handle_sigint(int signal) +{ + run = 0; +} + void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc){ @@ -53,9 +59,11 @@ int main(int argc, char *argv[]) rc = mosquitto_connect(mosq, "localhost", port, 60); + signal(SIGINT, handle_sigint); while(run == -1){ mosquitto_loop(mosq, -1, 1); } + SSL_CTX_free(ssl_ctx); mosquitto_destroy(mosq); mosquitto_lib_cleanup(); From 1ed0c0436ab52b67f5c5ea92161dede66fc30af5 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 13 Aug 2022 21:39:25 +0100 Subject: [PATCH 56/70] Run lock only once per week --- .github/workflows/lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 8331df74..920a0259 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -2,7 +2,7 @@ name: 'Lock Threads' on: schedule: - - cron: '0 * * * *' + - cron: '0 0 * * 0' workflow_dispatch: permissions: From fa31b6f41d69394dce9424a04e4f95d5fb2cfdc2 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Sat, 13 Aug 2022 22:46:19 +0100 Subject: [PATCH 57/70] Fix bridge queued messages not being persisted. This happens when local_cleansession is set to false and cleansession is set to true. Closes #2604. Thank to Frank Dekervel. --- ChangeLog.txt | 2 ++ src/persist_write.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index a0614d89..5a165de1 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -22,6 +22,8 @@ Broker: security plugin. Closes #2525. - Fix confusing error message when dynamic security config file was a directory. Closes #2520. +- Fix bridge queued messages not being persisted when local_cleansession is + set to false and cleansession is set to true. Closes #2604. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/src/persist_write.c b/src/persist_write.c index 0df016ec..fb3632fe 100644 --- a/src/persist_write.c +++ b/src/persist_write.c @@ -167,7 +167,11 @@ static int persist__client_save(FILE *db_fptr) memset(&chunk, 0, sizeof(struct P_client)); HASH_ITER(hh_id, db.contexts_by_id, context, ctxt_tmp){ - if(context && context->clean_start == false){ + if(context && (context->clean_start == false +#ifdef WITH_BRIDGE + || (context->bridge && context->bridge->clean_start_local == false) +#endif + )){ chunk.F.session_expiry_time = context->session_expiry_time; if(context->session_expiry_interval != 0 && context->session_expiry_interval != UINT32_MAX && context->session_expiry_time == 0){ chunk.F.session_expiry_time = context->session_expiry_interval + db.now_real_s; From 49ebb585693aa3361b9ec235c1a2d28407a2091d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Mon, 15 Aug 2022 22:17:00 +0100 Subject: [PATCH 58/70] Fix failure to close thread in some situations. Closes #2545. Thanks to p-luke. --- ChangeLog.txt | 1 + lib/connect.c | 2 ++ lib/loop.c | 7 ++----- lib/mosquitto_internal.h | 1 + lib/util_mosq.c | 20 ++++++++++++++++++++ lib/util_mosq.h | 4 ++++ 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 5a165de1..79f2ee77 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -36,6 +36,7 @@ Client library: - Fix documentation omission around mosquitto_reinitialise. Closes #2489. - Fix use of MOSQ_OPT_SSL_CTX when used in conjunction with MOSQ_OPT_SSL_CTX_DEFAULTS. Closes #2463. +- Fix failure to close thread in some situations. Closes #2545. Clients: - Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. diff --git a/lib/connect.c b/lib/connect.c index ab61b66c..dfc57fa2 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -76,6 +76,7 @@ static int mosquitto__connect_init(struct mosquitto *mosq, const char *host, int mosq->msgs_in.inflight_quota = mosq->msgs_in.inflight_maximum; mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum; mosq->retain_available = 1; + mosquitto__set_request_disconnect(mosq, false); return MOSQ_ERR_SUCCESS; } @@ -255,6 +256,7 @@ int mosquitto_disconnect_v5(struct mosquitto *mosq, int reason_code, const mosqu } mosquitto__set_state(mosq, mosq_cs_disconnected); + mosquitto__set_request_disconnect(mosq, true); if(mosq->sock == INVALID_SOCKET){ return MOSQ_ERR_NO_CONN; }else{ diff --git a/lib/loop.c b/lib/loop.c index eb12854e..965294f0 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -242,7 +242,6 @@ int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets) int run = 1; int rc = MOSQ_ERR_SUCCESS; unsigned long reconnect_delay; - enum mosquitto_client_state state; if(!mosq) return MOSQ_ERR_INVAL; @@ -281,8 +280,7 @@ int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets) pthread_testcancel(); #endif rc = MOSQ_ERR_SUCCESS; - state = mosquitto__get_state(mosq); - if(state == mosq_cs_disconnecting || state == mosq_cs_disconnected){ + if(mosquitto__get_request_disconnect(mosq)){ run = 0; }else{ if(mosq->reconnect_delay_max > mosq->reconnect_delay){ @@ -304,8 +302,7 @@ int mosquitto_loop_forever(struct mosquitto *mosq, int timeout, int max_packets) rc = interruptible_sleep(mosq, (time_t)reconnect_delay); if(rc) return rc; - state = mosquitto__get_state(mosq); - if(state == mosq_cs_disconnecting || state == mosq_cs_disconnected){ + if(mosquitto__get_request_disconnect(mosq)){ run = 0; }else{ rc = mosquitto_reconnect(mosq); diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 87718ea9..ac71ffbf 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -339,6 +339,7 @@ struct mosquitto { unsigned int reconnect_delay; unsigned int reconnect_delay_max; bool reconnect_exponential_backoff; + bool request_disconnect; char threaded; struct mosquitto__packet *out_packet_last; mosquitto_property *connect_properties; diff --git a/lib/util_mosq.c b/lib/util_mosq.c index f4f868b9..22f8c4d5 100644 --- a/lib/util_mosq.c +++ b/lib/util_mosq.c @@ -302,3 +302,23 @@ enum mosquitto_client_state mosquitto__get_state(struct mosquitto *mosq) return state; } + +#ifndef WITH_BROKER +void mosquitto__set_request_disconnect(struct mosquitto *mosq, bool request_disconnect) +{ + pthread_mutex_lock(&mosq->state_mutex); + mosq->request_disconnect = request_disconnect; + pthread_mutex_unlock(&mosq->state_mutex); +} + +bool mosquitto__get_request_disconnect(struct mosquitto *mosq) +{ + bool request_disconnect; + + pthread_mutex_lock(&mosq->state_mutex); + request_disconnect = mosq->request_disconnect; + pthread_mutex_unlock(&mosq->state_mutex); + + return request_disconnect; +} +#endif diff --git a/lib/util_mosq.h b/lib/util_mosq.h index 7d993442..ecc0120c 100644 --- a/lib/util_mosq.h +++ b/lib/util_mosq.h @@ -32,6 +32,10 @@ uint16_t mosquitto__mid_generate(struct mosquitto *mosq); int mosquitto__set_state(struct mosquitto *mosq, enum mosquitto_client_state state); enum mosquitto_client_state mosquitto__get_state(struct mosquitto *mosq); +#ifndef WITH_BROKER +void mosquitto__set_request_disconnect(struct mosquitto *mosq, bool request_disconnect); +bool mosquitto__get_request_disconnect(struct mosquitto *mosq); +#endif #ifdef WITH_TLS int mosquitto__hex2bin_sha1(const char *hex, unsigned char **bin); From b22df5140e848244e70e6cc787da4da98fe57565 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 00:23:06 +0100 Subject: [PATCH 59/70] Clear errno before check. --- plugins/dynamic-security/plugin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/dynamic-security/plugin.c b/plugins/dynamic-security/plugin.c index 45c9229b..e6b5943f 100644 --- a/plugins/dynamic-security/plugin.c +++ b/plugins/dynamic-security/plugin.c @@ -358,6 +358,7 @@ static int dynsec__config_load(void) cJSON *tree; /* Load from file */ + errno = 0; fptr = fopen(config_file, "rb"); if(fptr == NULL){ mosquitto_log_printf(MOSQ_LOG_ERR, "Error loading Dynamic security plugin config: File is not readable - check permissions.\n"); From 436f0b934847c75a40d870a035304610511897b8 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 00:48:02 +0100 Subject: [PATCH 60/70] dynsec: Fix modifyClient and modifyGroup commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They will now not modify the client/group if a new group/client being added is not valid, or on other failures. Closes #2598. Thanks to Sebastian Szczepański. --- ChangeLog.txt | 3 + plugins/dynamic-security/clients.c | 136 ++++++++++++++++++++--------- plugins/dynamic-security/groups.c | 99 ++++++++++++++++----- 3 files changed, 172 insertions(+), 66 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 79f2ee77..f0a70026 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -24,6 +24,9 @@ Broker: directory. Closes #2520. - Fix bridge queued messages not being persisted when local_cleansession is set to false and cleansession is set to true. Closes #2604. +- Dynamic security: Fix modifyClient and modifyGroup commands to not modify + the client/group if a new group/client being added is not valid. + Closes #2598. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/plugins/dynamic-security/clients.c b/plugins/dynamic-security/clients.c index a22e5cfb..78d53729 100644 --- a/plugins/dynamic-security/clients.c +++ b/plugins/dynamic-security/clients.c @@ -720,10 +720,12 @@ static void client__remove_all_roles(struct dynsec__client *client) int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { char *username; - char *clientid; - char *password; - char *text_name, *text_description; + char *clientid = NULL; + char *password = NULL; + char *text_name = NULL, *text_description = NULL; + bool have_clientid = false, have_text_name = false, have_text_description = false, have_rolelist = false, have_password = false; struct dynsec__client *client; + struct dynsec__group *group; struct dynsec__rolelist *rolelist = NULL; char *str; int rc; @@ -746,81 +748,87 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context return MOSQ_ERR_INVAL; } - if(json_get_string(command, "clientid", &clientid, false) == MOSQ_ERR_SUCCESS){ - if(clientid && strlen(clientid) > 0){ - str = mosquitto_strdup(clientid); - if(str == NULL){ + if(json_get_string(command, "clientid", &str, false) == MOSQ_ERR_SUCCESS){ + have_clientid = true; + if(str && strlen(str) > 0){ + clientid = mosquitto_strdup(str); + if(clientid == NULL){ dynsec__command_reply(j_responses, context, "modifyClient", "Internal error", correlation_data); - return MOSQ_ERR_NOMEM; + rc = MOSQ_ERR_NOMEM; + goto error; } }else{ - str = NULL; + clientid = NULL; } - mosquitto_free(client->clientid); - client->clientid = str; } if(json_get_string(command, "password", &password, false) == MOSQ_ERR_SUCCESS){ if(strlen(password) > 0){ - /* If password == "", we just ignore it */ - rc = client__set_password(client, password); - if(rc != MOSQ_ERR_SUCCESS){ - dynsec__command_reply(j_responses, context, "modifyClient", "Internal error", correlation_data); - mosquitto_kick_client_by_username(username, false); - return MOSQ_ERR_NOMEM; - } + have_password = true; } } - if(json_get_string(command, "textname", &text_name, false) == MOSQ_ERR_SUCCESS){ - str = mosquitto_strdup(text_name); - if(str == NULL){ + if(json_get_string(command, "textname", &str, false) == MOSQ_ERR_SUCCESS){ + have_text_name = true; + text_name = mosquitto_strdup(str); + if(text_name == NULL){ dynsec__command_reply(j_responses, context, "modifyClient", "Internal error", correlation_data); - mosquitto_kick_client_by_username(username, false); - return MOSQ_ERR_NOMEM; + rc = MOSQ_ERR_NOMEM; + goto error; } - mosquitto_free(client->text_name); - client->text_name = str; } - if(json_get_string(command, "textdescription", &text_description, false) == MOSQ_ERR_SUCCESS){ - str = mosquitto_strdup(text_description); - if(str == NULL){ + if(json_get_string(command, "textdescription", &str, false) == MOSQ_ERR_SUCCESS){ + have_text_description = true; + text_description = mosquitto_strdup(str); + if(text_description == NULL){ dynsec__command_reply(j_responses, context, "modifyClient", "Internal error", correlation_data); - mosquitto_kick_client_by_username(username, false); - return MOSQ_ERR_NOMEM; + rc = MOSQ_ERR_NOMEM; + goto error; } - mosquitto_free(client->text_description); - client->text_description = str; } rc = dynsec_rolelist__load_from_json(command, &rolelist); if(rc == MOSQ_ERR_SUCCESS){ - client__remove_all_roles(client); - client__add_new_roles(client, rolelist); - dynsec_rolelist__cleanup(&rolelist); + have_rolelist = true; }else if(rc == ERR_LIST_NOT_FOUND){ /* There was no list in the JSON, so no modification */ }else if(rc == MOSQ_ERR_NOT_FOUND){ dynsec__command_reply(j_responses, context, "modifyClient", "Role not found", correlation_data); - dynsec_rolelist__cleanup(&rolelist); - mosquitto_kick_client_by_username(username, false); - return MOSQ_ERR_INVAL; + rc = MOSQ_ERR_INVAL; + goto error; }else{ if(rc == MOSQ_ERR_INVAL){ dynsec__command_reply(j_responses, context, "modifyClient", "'roles' not an array or missing/invalid rolename", correlation_data); }else{ dynsec__command_reply(j_responses, context, "modifyClient", "Internal error", correlation_data); } - dynsec_rolelist__cleanup(&rolelist); - mosquitto_kick_client_by_username(username, false); - return MOSQ_ERR_INVAL; + rc = MOSQ_ERR_INVAL; + goto error; } j_groups = cJSON_GetObjectItem(command, "groups"); if(j_groups && cJSON_IsArray(j_groups)){ - dynsec__remove_client_from_all_groups(username); + /* Iterate through list to check all groups are valid */ + cJSON_ArrayForEach(j_group, j_groups){ + if(cJSON_IsObject(j_group)){ + jtmp = cJSON_GetObjectItem(j_group, "groupname"); + if(jtmp && cJSON_IsString(jtmp)){ + group = dynsec_groups__find(jtmp->valuestring); + if(group == NULL){ + dynsec__command_reply(j_responses, context, "modifyClient", "'groups' contains an object with a 'groupname' that does not exist", correlation_data); + rc = MOSQ_ERR_INVAL; + goto error; + } + }else{ + dynsec__command_reply(j_responses, context, "modifyClient", "'groups' contains an object with an invalid 'groupname'", correlation_data); + rc = MOSQ_ERR_INVAL; + goto error; + } + } + } + dynsec__remove_client_from_all_groups(username); cJSON_ArrayForEach(j_group, j_groups){ if(cJSON_IsObject(j_group)){ jtmp = cJSON_GetObjectItem(j_group, "groupname"); @@ -832,6 +840,44 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context } } + if(have_password){ + /* FIXME - This is the one call that will result in modification on internal error - note that groups have already been modified */ + rc = client__set_password(client, password); + if(rc != MOSQ_ERR_SUCCESS){ + dynsec__command_reply(j_responses, context, "modifyClient", "Internal error", correlation_data); + mosquitto_kick_client_by_username(username, false); + /* If this fails we have the situation that the password is set as + * invalid, but the config isn't saved, so restarting the broker + * *now* will mean the client can log in again. This might be + * "good", but is inconsistent, so save the config to be + * consistent. */ + dynsec__config_save(); + rc = MOSQ_ERR_NOMEM; + goto error; + } + } + + if(have_clientid){ + mosquitto_free(client->clientid); + client->clientid = clientid; + } + + if(have_text_name){ + mosquitto_free(client->text_name); + client->text_name = text_name; + } + + if(have_text_description){ + mosquitto_free(client->text_description); + client->text_description = text_description; + } + + if(have_rolelist){ + client__remove_all_roles(client); + client__add_new_roles(client, rolelist); + dynsec_rolelist__cleanup(&rolelist); + } + dynsec__config_save(); dynsec__command_reply(j_responses, context, "modifyClient", NULL, correlation_data); @@ -843,6 +889,12 @@ int dynsec_clients__process_modify(cJSON *j_responses, struct mosquitto *context mosquitto_log_printf(MOSQ_LOG_INFO, "dynsec: %s/%s | modifyClient | username=%s", admin_clientid, admin_username, username); return MOSQ_ERR_SUCCESS; +error: + mosquitto_free(clientid); + mosquitto_free(text_name); + mosquitto_free(text_description); + dynsec_rolelist__cleanup(&rolelist); + return rc; } diff --git a/plugins/dynamic-security/groups.c b/plugins/dynamic-security/groups.c index c4bdda14..b2a2f485 100644 --- a/plugins/dynamic-security/groups.c +++ b/plugins/dynamic-security/groups.c @@ -911,10 +911,12 @@ int dynsec_groups__process_remove_role(cJSON *j_responses, struct mosquitto *con int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { - char *groupname; - char *text_name, *text_description; - struct dynsec__group *group; + char *groupname = NULL; + char *text_name = NULL, *text_description = NULL; + struct dynsec__client *client = NULL; + struct dynsec__group *group = NULL; struct dynsec__rolelist *rolelist = NULL; + bool have_text_name = false, have_text_description = false, have_rolelist = false; char *str; int rc; int priority; @@ -936,52 +938,73 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, return MOSQ_ERR_INVAL; } - if(json_get_string(command, "textname", &text_name, false) == MOSQ_ERR_SUCCESS){ - str = mosquitto_strdup(text_name); - if(str == NULL){ + if(json_get_string(command, "textname", &str, false) == MOSQ_ERR_SUCCESS){ + have_text_name = true; + text_name = mosquitto_strdup(str); + if(text_name == NULL){ dynsec__command_reply(j_responses, context, "modifyGroup", "Internal error", correlation_data); - return MOSQ_ERR_NOMEM; + rc = MOSQ_ERR_NOMEM; + goto error; } - mosquitto_free(group->text_name); - group->text_name = str; } - if(json_get_string(command, "textdescription", &text_description, false) == MOSQ_ERR_SUCCESS){ - str = mosquitto_strdup(text_description); - if(str == NULL){ + if(json_get_string(command, "textdescription", &str, false) == MOSQ_ERR_SUCCESS){ + have_text_description = true; + text_description = mosquitto_strdup(str); + if(text_description == NULL){ dynsec__command_reply(j_responses, context, "modifyGroup", "Internal error", correlation_data); - return MOSQ_ERR_NOMEM; + rc = MOSQ_ERR_NOMEM; + goto error; } - mosquitto_free(group->text_description); - group->text_description = str; } rc = dynsec_rolelist__load_from_json(command, &rolelist); if(rc == MOSQ_ERR_SUCCESS){ - dynsec_rolelist__cleanup(&group->rolelist); - group->rolelist = rolelist; + /* Apply changes below */ + have_rolelist = true; }else if(rc == ERR_LIST_NOT_FOUND){ /* There was no list in the JSON, so no modification */ + rolelist = NULL; }else if(rc == MOSQ_ERR_NOT_FOUND){ dynsec__command_reply(j_responses, context, "modifyGroup", "Role not found", correlation_data); - dynsec_rolelist__cleanup(&rolelist); - group__kick_all(group); - return MOSQ_ERR_INVAL; + rc = MOSQ_ERR_INVAL; + goto error; }else{ if(rc == MOSQ_ERR_INVAL){ dynsec__command_reply(j_responses, context, "modifyGroup", "'roles' not an array or missing/invalid rolename", correlation_data); }else{ dynsec__command_reply(j_responses, context, "modifyGroup", "Internal error", correlation_data); } - dynsec_rolelist__cleanup(&rolelist); - group__kick_all(group); - return MOSQ_ERR_INVAL; + rc = MOSQ_ERR_INVAL; + goto error; } j_clients = cJSON_GetObjectItem(command, "clients"); if(j_clients && cJSON_IsArray(j_clients)){ + /* Iterate over array to check clients are valid before proceeding */ + cJSON_ArrayForEach(j_client, j_clients){ + if(cJSON_IsObject(j_client)){ + jtmp = cJSON_GetObjectItem(j_client, "username"); + if(jtmp && cJSON_IsString(jtmp)){ + client = dynsec_clients__find(jtmp->valuestring); + if(client == NULL){ + dynsec__command_reply(j_responses, context, "modifyGroup", "'clients' contains an object with a 'username' that does not exist", correlation_data); + rc = MOSQ_ERR_INVAL; + goto error; + } + }else{ + dynsec__command_reply(j_responses, context, "modifyGroup", "'clients' contains an object with an invalid 'username'", correlation_data); + rc = MOSQ_ERR_INVAL; + goto error; + } + } + } + + /* Kick all clients in the *current* group */ + group__kick_all(group); dynsec__remove_all_clients_from_group(group); + /* Now we can add the new clients to the group */ cJSON_ArrayForEach(j_client, j_clients){ if(cJSON_IsObject(j_client)){ jtmp = cJSON_GetObjectItem(j_client, "username"); @@ -993,11 +1016,28 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, } } + /* Apply remaining changes to group, note that user changes are already applied */ + if(have_text_name){ + mosquitto_free(group->text_name); + group->text_name = text_name; + } + + if(have_text_description){ + mosquitto_free(group->text_description); + group->text_description = text_description; + } + + if(have_rolelist){ + dynsec_rolelist__cleanup(&group->rolelist); + group->rolelist = rolelist; + } + + /* And save */ dynsec__config_save(); dynsec__command_reply(j_responses, context, "modifyGroup", NULL, correlation_data); - /* Enforce any changes */ + /* Enforce any changes - kick any clients in the *new* group */ group__kick_all(group); admin_clientid = mosquitto_client_id(context); @@ -1006,6 +1046,17 @@ int dynsec_groups__process_modify(cJSON *j_responses, struct mosquitto *context, admin_clientid, admin_username, groupname); return MOSQ_ERR_SUCCESS; +error: + mosquitto_free(text_name); + mosquitto_free(text_description); + dynsec_rolelist__cleanup(&rolelist); + + admin_clientid = mosquitto_client_id(context); + admin_username = mosquitto_client_username(context); + mosquitto_log_printf(MOSQ_LOG_INFO, "dynsec: %s/%s | modifyGroup | groupname=%s", + admin_clientid, admin_username, groupname); + + return rc; } From df317ff71f8c1a904400ff092536c0c9c664d644 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 01:27:55 +0100 Subject: [PATCH 61/70] Dynamic security: Fix the plugin being able to be loaded twice. Currently only a single plugin can interact with a unique $CONTROL topic. Using multiple instances of the plugin would produce duplicate entries in the config file. Closes #2601. Closes #2470. --- ChangeLog.txt | 4 +++ plugins/dynamic-security/plugin.c | 42 ++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index f0a70026..d2e83a7f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -27,6 +27,10 @@ Broker: - Dynamic security: Fix modifyClient and modifyGroup commands to not modify the client/group if a new group/client being added is not valid. Closes #2598. +- Dynamic security: Fix the plugin being able to be loaded twice. Currently + only a single plugin can interact with a unique $CONTROL topic. Using + multiple instances of the plugin would produce duplicate entries in the + config file. Closes #2601. Closes #2470. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/plugins/dynamic-security/plugin.c b/plugins/dynamic-security/plugin.c index e6b5943f..3ff1054a 100644 --- a/plugins/dynamic-security/plugin.c +++ b/plugins/dynamic-security/plugin.c @@ -482,6 +482,7 @@ void dynsec__config_save(void) int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *options, int option_count) { int i; + int rc; UNUSED(user_data); @@ -502,11 +503,46 @@ int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, s plg_id = identifier; dynsec__config_load(); - mosquitto_callback_register(plg_id, MOSQ_EVT_CONTROL, dynsec_control_callback, "$CONTROL/dynamic-security/v1", NULL); - mosquitto_callback_register(plg_id, MOSQ_EVT_BASIC_AUTH, dynsec_auth__basic_auth_callback, NULL, NULL); - mosquitto_callback_register(plg_id, MOSQ_EVT_ACL_CHECK, dynsec__acl_check_callback, NULL, NULL); + + rc = mosquitto_callback_register(plg_id, MOSQ_EVT_CONTROL, dynsec_control_callback, "$CONTROL/dynamic-security/v1", NULL); + if(rc == MOSQ_ERR_ALREADY_EXISTS){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Dynamic security plugin can currently only be loaded once."); + mosquitto_log_printf(MOSQ_LOG_ERR, "Note that this was previously incorrectly allowed but could cause problems with duplicate entries in the config."); + goto error; + }else if(rc == MOSQ_ERR_NOMEM){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); + goto error; + }else if(rc != MOSQ_ERR_SUCCESS){ + goto error; + } + + rc = mosquitto_callback_register(plg_id, MOSQ_EVT_BASIC_AUTH, dynsec_auth__basic_auth_callback, NULL, NULL); + if(rc == MOSQ_ERR_ALREADY_EXISTS){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Dynamic security plugin can only be loaded once."); + goto error; + }else if(rc == MOSQ_ERR_NOMEM){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); + goto error; + }else if(rc != MOSQ_ERR_SUCCESS){ + goto error; + } + + rc = mosquitto_callback_register(plg_id, MOSQ_EVT_ACL_CHECK, dynsec__acl_check_callback, NULL, NULL); + if(rc == MOSQ_ERR_ALREADY_EXISTS){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Dynamic security plugin can only be loaded once."); + goto error; + }else if(rc == MOSQ_ERR_NOMEM){ + mosquitto_log_printf(MOSQ_LOG_ERR, "Error: Out of memory."); + goto error; + }else if(rc != MOSQ_ERR_SUCCESS){ + goto error; + } return MOSQ_ERR_SUCCESS; +error: + mosquitto_free(config_file); + config_file = NULL; + return rc; } int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *options, int option_count) From cd8890613261146baf0529ad5f0b603957749262 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 12:28:13 +0100 Subject: [PATCH 62/70] Clearer function name --- src/database.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/database.c b/src/database.c index 061e1ed7..21f9357d 100644 --- a/src/database.c +++ b/src/database.c @@ -339,7 +339,7 @@ void db__msg_store_compact(void) } -static void db__message_remove(struct mosquitto_msg_data *msg_data, struct mosquitto_client_msg *item) +static void db__message_remove_from_inflight(struct mosquitto_msg_data *msg_data, struct mosquitto_client_msg *item) { if(!msg_data || !item){ return; @@ -390,7 +390,7 @@ int db__message_delete_outgoing(struct mosquitto *context, uint16_t mid, enum mo return MOSQ_ERR_PROTOCOL; } msg_index--; - db__message_remove(&context->msgs_out, tail); + db__message_remove_from_inflight(&context->msgs_out, tail); break; } } @@ -894,7 +894,7 @@ static int db__message_reconnect_reset_incoming(struct mosquitto *context) if(msg->qos != 2){ /* Anything msgs_in, msg); + db__message_remove_from_inflight(&context->msgs_in, msg); }else{ /* Message state can be preserved here because it should match * whatever the client has got. */ @@ -950,7 +950,7 @@ int db__message_remove_incoming(struct mosquitto* context, uint16_t mid) if(tail->store->qos != 2){ return MOSQ_ERR_PROTOCOL; } - db__message_remove(&context->msgs_in, tail); + db__message_remove_from_inflight(&context->msgs_in, tail); return MOSQ_ERR_SUCCESS; } } @@ -986,12 +986,12 @@ int db__message_release_incoming(struct mosquitto *context, uint16_t mid) * keep resending it. That means we don't send it to other * clients. */ if(topic == NULL){ - db__message_remove(&context->msgs_in, tail); + db__message_remove_from_inflight(&context->msgs_in, tail); deleted = true; }else{ rc = sub__messages_queue(source_id, topic, 2, retain, &tail->store); if(rc == MOSQ_ERR_SUCCESS || rc == MOSQ_ERR_NO_SUBSCRIBERS){ - db__message_remove(&context->msgs_in, tail); + db__message_remove_from_inflight(&context->msgs_in, tail); deleted = true; }else{ return 1; @@ -1041,7 +1041,7 @@ static int db__message_write_inflight_out_single(struct mosquitto *context, stru if(msg->direction == mosq_md_out && msg->qos > 0){ util__increment_send_quota(context); } - db__message_remove(&context->msgs_out, msg); + db__message_remove_from_inflight(&context->msgs_out, msg); return MOSQ_ERR_SUCCESS; }else{ expiry_interval = (uint32_t)(msg->store->message_expiry_time - db.now_real_s); @@ -1061,7 +1061,7 @@ static int db__message_write_inflight_out_single(struct mosquitto *context, stru case mosq_ms_publish_qos0: rc = send__publish(context, mid, topic, payloadlen, payload, qos, retain, retries, cmsg_props, store_props, expiry_interval); if(rc == MOSQ_ERR_SUCCESS || rc == MOSQ_ERR_OVERSIZE_PACKET){ - db__message_remove(&context->msgs_out, msg); + db__message_remove_from_inflight(&context->msgs_out, msg); }else{ return rc; } @@ -1074,7 +1074,7 @@ static int db__message_write_inflight_out_single(struct mosquitto *context, stru msg->dup = 1; /* Any retry attempts are a duplicate. */ msg->state = mosq_ms_wait_for_puback; }else if(rc == MOSQ_ERR_OVERSIZE_PACKET){ - db__message_remove(&context->msgs_out, msg); + db__message_remove_from_inflight(&context->msgs_out, msg); }else{ return rc; } @@ -1087,7 +1087,7 @@ static int db__message_write_inflight_out_single(struct mosquitto *context, stru msg->dup = 1; /* Any retry attempts are a duplicate. */ msg->state = mosq_ms_wait_for_pubrec; }else if(rc == MOSQ_ERR_OVERSIZE_PACKET){ - db__message_remove(&context->msgs_out, msg); + db__message_remove_from_inflight(&context->msgs_out, msg); }else{ return rc; } From 7917553eb226d24299f9a6e88110bf4ca1db8226 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 12:29:18 +0100 Subject: [PATCH 63/70] Fix expired messages causing queued messages not to be delivered. Closes #2609. Thanks to JSchy65. --- ChangeLog.txt | 2 ++ src/database.c | 50 +++++++++++++++++++++++++++++++++ src/handle_connect.c | 1 + src/mosquitto_broker_internal.h | 1 + 4 files changed, 54 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index d2e83a7f..f5fccfe8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -31,6 +31,8 @@ Broker: only a single plugin can interact with a unique $CONTROL topic. Using multiple instances of the plugin would produce duplicate entries in the config file. Closes #2601. Closes #2470. +- Fix case where expired messages were causing queued messages not to be + delivered. Closes #2609. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/src/database.c b/src/database.c index 21f9357d..5e77a281 100644 --- a/src/database.c +++ b/src/database.c @@ -356,6 +356,22 @@ static void db__message_remove_from_inflight(struct mosquitto_msg_data *msg_data } +static void db__message_remove_from_queued(struct mosquitto_msg_data *msg_data, struct mosquitto_client_msg *item) +{ + if(!msg_data || !item){ + return; + } + + DL_DELETE(msg_data->queued, item); + if(item->store){ + db__msg_store_ref_dec(&item->store); + } + + mosquitto_property_free_all(&item->properties); + mosquitto__free(item); +} + + void db__message_dequeue_first(struct mosquitto *context, struct mosquitto_msg_data *msg_data) { struct mosquitto_client_msg *msg; @@ -1021,6 +1037,40 @@ int db__message_release_incoming(struct mosquitto *context, uint16_t mid) } } + +void db__expire_all_messages(struct mosquitto *context) +{ + struct mosquitto_client_msg *msg, *tmp; + + DL_FOREACH_SAFE(context->msgs_out.inflight, msg, tmp){ + if(msg->store->message_expiry_time && db.now_real_s > msg->store->message_expiry_time){ + if(msg->qos > 0){ + util__increment_send_quota(context); + } + db__message_remove_from_inflight(&context->msgs_out, msg); + } + } + DL_FOREACH_SAFE(context->msgs_out.queued, msg, tmp){ + if(msg->store->message_expiry_time && db.now_real_s > msg->store->message_expiry_time){ + db__message_remove_from_queued(&context->msgs_out, msg); + } + } + DL_FOREACH_SAFE(context->msgs_in.inflight, msg, tmp){ + if(msg->store->message_expiry_time && db.now_real_s > msg->store->message_expiry_time){ + if(msg->qos > 0){ + util__increment_receive_quota(context); + } + db__message_remove_from_inflight(&context->msgs_in, msg); + } + } + DL_FOREACH_SAFE(context->msgs_in.queued, msg, tmp){ + if(msg->store->message_expiry_time && db.now_real_s > msg->store->message_expiry_time){ + db__message_remove_from_queued(&context->msgs_in, msg); + } + } +} + + static int db__message_write_inflight_out_single(struct mosquitto *context, struct mosquitto_client_msg *msg) { mosquitto_property *cmsg_props = NULL, *store_props = NULL; diff --git a/src/handle_connect.c b/src/handle_connect.c index 790c88a2..21405adf 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -318,6 +318,7 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1 rc = send__connack(context, connect_ack, CONNACK_ACCEPTED, connack_props); mosquitto_property_free_all(&connack_props); if(rc) return rc; + db__expire_all_messages(context); rc = db__message_write_queued_out(context); if(rc) return rc; rc = db__message_write_inflight_out_all(context); diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 8f2ad0b2..c28eaa2a 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -670,6 +670,7 @@ int db__message_write_queued_out(struct mosquitto *context); int db__message_write_queued_in(struct mosquitto *context); void db__msg_add_to_inflight_stats(struct mosquitto_msg_data *msg_data, struct mosquitto_client_msg *msg); void db__msg_add_to_queued_stats(struct mosquitto_msg_data *msg_data, struct mosquitto_client_msg *msg); +void db__expire_all_messages(struct mosquitto *context); /* ============================================================ * Subscription functions From 4d1b587e29bf0476b78305a26932f09949522a75 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 12:53:01 +0100 Subject: [PATCH 64/70] dynsec: Forbid deleting the anon group. --- ChangeLog.txt | 10 +++++++++- plugins/dynamic-security/groups.c | 5 +++++ test/broker/14-dynsec-anon-group.py | 12 ++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index f5fccfe8..26998f6d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,14 @@ -2.0.15 - 2022-xx-xx +2.0.15 - 2022-08-16 =================== +Security: +- Deleting the group configured as the anonymous group in the Dynamic Security + plugin, would leave a dangling pointer that could lead to a single crash. + This is considered a minor issue - only administrative users should have + access to dynsec, the impact on availability is one-off, and there is no + associated loss of data. It is now forbidden to delete the group configured + as the anonymous group. + Broker: - Fix memory leak when a plugin modifies the topic of a message in MOSQ_EVT_MESSAGE. diff --git a/plugins/dynamic-security/groups.c b/plugins/dynamic-security/groups.c index b2a2f485..f26a2ba5 100644 --- a/plugins/dynamic-security/groups.c +++ b/plugins/dynamic-security/groups.c @@ -466,6 +466,11 @@ int dynsec_groups__process_delete(cJSON *j_responses, struct mosquitto *context, group = dynsec_groups__find(groupname); if(group){ + if(group == dynsec_anonymous_group){ + dynsec__command_reply(j_responses, context, "deleteGroup", "Deleting the anonymous group is forbidden", correlation_data); + return MOSQ_ERR_INVAL; + } + /* Enforce any changes */ group__kick_all(group); diff --git a/test/broker/14-dynsec-anon-group.py b/test/broker/14-dynsec-anon-group.py index 259188de..95ea3590 100755 --- a/test/broker/14-dynsec-anon-group.py +++ b/test/broker/14-dynsec-anon-group.py @@ -71,6 +71,15 @@ create_role_apply_response = {'responses': [ ]} +delete_anon_group_command = { "commands": [ + { "command": "deleteGroup", "groupname": "anon-clients", "correlationData": "40" } + ] +} +delete_anon_group_response = {'responses': [ + {'command': 'deleteGroup', "error":'Deleting the anonymous group is forbidden', 'correlationData': '40'} + ]} + + rc = 1 keepalive = 10 @@ -136,6 +145,9 @@ try: csock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=5, port=port) mosq_test.do_send_receive(csock, subscribe_packet, suback_packet_success, "suback 3") + # Try to delete anon group, this should fail + command_check(sock, delete_anon_group_command, delete_anon_group_response) + rc = 0 sock.close() From 966601f6b65766d380ff797c9c9305a402e91647 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 13:03:44 +0100 Subject: [PATCH 65/70] Bump version, new web post --- CMakeLists.txt | 2 +- config.mk | 2 +- include/mosquitto.h | 2 +- installer/mosquitto.nsi | 2 +- installer/mosquitto64.nsi | 2 +- set-version.sh | 2 +- snap/snapcraft.yaml | 2 +- www/posts/2022/08/version-2-0-15-released.md | 100 +++++++++++++++++++ 8 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 www/posts/2022/08/version-2-0-15-released.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 851c4243..b8913c2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.1) cmake_policy(SET CMP0042 NEW) project(mosquitto) -set (VERSION 2.0.14) +set (VERSION 2.0.15) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/") diff --git a/config.mk b/config.mk index 432d54f3..73daefdf 100644 --- a/config.mk +++ b/config.mk @@ -127,7 +127,7 @@ WITH_XTREPORT=no # Also bump lib/mosquitto.h, CMakeLists.txt, # installer/mosquitto.nsi, installer/mosquitto64.nsi -VERSION=2.0.14 +VERSION=2.0.15 # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 diff --git a/include/mosquitto.h b/include/mosquitto.h index 1c860ac8..2d34976c 100644 --- a/include/mosquitto.h +++ b/include/mosquitto.h @@ -66,7 +66,7 @@ extern "C" { #define LIBMOSQUITTO_MAJOR 2 #define LIBMOSQUITTO_MINOR 0 -#define LIBMOSQUITTO_REVISION 14 +#define LIBMOSQUITTO_REVISION 15 /* LIBMOSQUITTO_VERSION_NUMBER looks like 1002001 for e.g. version 1.2.1. */ #define LIBMOSQUITTO_VERSION_NUMBER (LIBMOSQUITTO_MAJOR*1000000+LIBMOSQUITTO_MINOR*1000+LIBMOSQUITTO_REVISION) diff --git a/installer/mosquitto.nsi b/installer/mosquitto.nsi index eb845857..5450fae0 100644 --- a/installer/mosquitto.nsi +++ b/installer/mosquitto.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 2.0.14 +!define VERSION 2.0.15 OutFile "mosquitto-${VERSION}-install-windows-x86.exe" InstallDir "$PROGRAMFILES\mosquitto" diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index d357df4d..71d0aef9 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -9,7 +9,7 @@ !define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' Name "Eclipse Mosquitto" -!define VERSION 2.0.14 +!define VERSION 2.0.15 OutFile "mosquitto-${VERSION}-install-windows-x64.exe" !include "x64.nsh" diff --git a/set-version.sh b/set-version.sh index 5f9ae4df..81d01473 100755 --- a/set-version.sh +++ b/set-version.sh @@ -2,7 +2,7 @@ MAJOR=2 MINOR=0 -REVISION=14 +REVISION=15 sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 22f38047..a330a4e5 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: mosquitto -version: 2.0.14 +version: 2.0.15 summary: Eclipse Mosquitto MQTT broker description: This is a message broker that supports version 5.0, 3.1.1, and 3.1 of the MQTT protocol. diff --git a/www/posts/2022/08/version-2-0-15-released.md b/www/posts/2022/08/version-2-0-15-released.md new file mode 100644 index 00000000..2a770a3a --- /dev/null +++ b/www/posts/2022/08/version-2-0-15-released.md @@ -0,0 +1,100 @@ + + +Versions 2.0.15 of Mosquitto has been released. This is a security +and bugfix release. + +# Security +- Deleting the group configured as the anonymous group in the Dynamic Security + plugin, would leave a dangling pointer that could lead to a single crash. + This is considered a minor issue - only administrative users should have + access to dynsec, the impact on availability is one-off, and there is no + associated loss of data. It is now forbidden to delete the group configured + as the anonymous group. + +# Broker +- Fix memory leak when a plugin modifies the topic of a message in + `MOSQ_EVT_MESSAGE`. +- Fix bridge `restart_timeout` not being honoured. +- Fix potential memory leaks if a plugin modifies the message in the + `MOSQ_EVT_MESSAGE` event. +- Fix unused flags in CONNECT command being forced to be 0, which is not + required for MQTT v3.1. Closes [#2522]. +- Improve documentation of `persistent_client_expiration` option. + Closes [#2404]. +- Add clients to session expiry check list when restarting and reloading from + persistence. Closes [#2546]. +- Fix bridges not sending failure notification messages to the local broker if + the remote bridge connection fails. Closes [#2467]. Closes [#1488]. +- Fix some PUBLISH messages not being counted in $SYS stats. Closes [#2448]. +- Fix incorrect return code being sent in DISCONNECT when a client session is + taken over. Closes [#2607]. +- Fix confusing "out of memory" error when a client is kicked in the dynamic + security plugin. Closes [#2525]. +- Fix confusing error message when dynamic security config file was a + directory. Closes [#2520]. +- Fix bridge queued messages not being persisted when local_cleansession is + set to false and cleansession is set to true. Closes [#2604]. +- Dynamic security: Fix modifyClient and modifyGroup commands to not modify + the client/group if a new group/client being added is not valid. + Closes [#2598]. +- Dynamic security: Fix the plugin being able to be loaded twice. Currently + only a single plugin can interact with a unique $CONTROL topic. Using + multiple instances of the plugin would produce duplicate entries in the + config file. Closes [#2601]. Closes [#2470]. +- Fix case where expired messages were causing queued messages not to be + delivered. Closes [#2609]. + +# Client library +- Fix threads library detection on Windows under cmake. Bumps the minimum + cmake version to 3.1, which is still ancient. +- Fix use of `MOSQ_OPT_TLS_ENGINE` being unable to be used due to the openssl + ctx not being initialised until starting to connect. Closes [#2537]. +- Fix incorrect use of SSL_connect. Closes [#2594]. +- Don't set SIGPIPE to ignore, use MSG_NOSIGNAL instead. Closes [#2564]. +- Add documentation of struct mosquitto_message to header. Closes [#2561]. +- Fix documentation omission around mosquitto_reinitialise. Closes [#2489]. +- Fix use of MOSQ_OPT_SSL_CTX when used in conjunction with + MOSQ_OPT_SSL_CTX_DEFAULTS. Closes [#2463]. +- Fix failure to close thread in some situations. Closes [#2545]. + +# Clients +- Fix mosquitto_pub incorrectly reusing topic aliases when reconnecting. + Closes [#2494]. + +# Apps +- Fix `-o` not working in `mosquitto_ctrl`, and typo in related documentation. + Closes [#2471]. + + +[#1488]: https://github.com/eclipse/mosquitto/issues/1488 +[#2404]: https://github.com/eclipse/mosquitto/issues/2404 +[#2448]: https://github.com/eclipse/mosquitto/issues/2448 +[#2463]: https://github.com/eclipse/mosquitto/issues/2463 +[#2467]: https://github.com/eclipse/mosquitto/issues/2467 +[#2470]: https://github.com/eclipse/mosquitto/issues/2470 +[#2471]: https://github.com/eclipse/mosquitto/issues/2471 +[#2489]: https://github.com/eclipse/mosquitto/issues/2489 +[#2494]: https://github.com/eclipse/mosquitto/issues/2494 +[#2520]: https://github.com/eclipse/mosquitto/issues/2520 +[#2522]: https://github.com/eclipse/mosquitto/issues/2522 +[#2525]: https://github.com/eclipse/mosquitto/issues/2525 +[#2537]: https://github.com/eclipse/mosquitto/issues/2537 +[#2545]: https://github.com/eclipse/mosquitto/issues/2545 +[#2546]: https://github.com/eclipse/mosquitto/issues/2546 +[#2561]: https://github.com/eclipse/mosquitto/issues/2561 +[#2564]: https://github.com/eclipse/mosquitto/issues/2564 +[#2594]: https://github.com/eclipse/mosquitto/issues/2594 +[#2598]: https://github.com/eclipse/mosquitto/issues/2598 +[#2601]: https://github.com/eclipse/mosquitto/issues/2601 +[#2604]: https://github.com/eclipse/mosquitto/issues/2604 +[#2607]: https://github.com/eclipse/mosquitto/issues/2607 +[#2609]: https://github.com/eclipse/mosquitto/issues/2609 From 0eec37af999af0ab1b4a5943d852b512cfa88f3d Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Tue, 16 Aug 2022 13:49:48 +0100 Subject: [PATCH 66/70] Add support for X-Forwarded-For LWS I know you've added this for the next release, but here is a fix for LWS. But just incase there are any more 2.0.x releases. It does leave the incoming port as 0 but as this is pretty meaningless for a proxied connection I think it's probably ok. Signed-off-by: Ben Hardill --- src/websockets.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/websockets.c b/src/websockets.c index 74e36d31..c85760da 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -133,6 +133,7 @@ static int callback_mqtt( uint8_t *buf; int rc; uint8_t byte; + char ip_addr_buff[1024]; switch (reason) { case LWS_CALLBACK_ESTABLISHED: @@ -157,7 +158,12 @@ static int callback_mqtt( }else{ return -1; } - easy_address(lws_get_socket_fd(wsi), mosq); + + if (lws_hdr_copy(wsi, ip_addr_buff, sizeof(ip_addr_buff), WSI_TOKEN_X_FORWARDED_FOR) > 0) { + mosq->address = mosquitto__strdup(ip_addr_buff); + } else { + easy_address(lws_get_socket_fd(wsi), mosq); + } if(!mosq->address){ /* getpeername and inet_ntop failed and not a bridge */ mosquitto__free(mosq); From b0277869d9806f6fab8e1bc11c4a4987c9a79ded Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 14:32:59 +0100 Subject: [PATCH 67/70] Update changelog for last minute fix --- ChangeLog.txt | 1 + www/posts/2022/08/version-2-0-15-released.md | 1 + 2 files changed, 2 insertions(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 26998f6d..ffe19b80 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -41,6 +41,7 @@ Broker: config file. Closes #2601. Closes #2470. - Fix case where expired messages were causing queued messages not to be delivered. Closes #2609. +- Fix websockets not passing on the X-Forwarded-For header. Client library: - Fix threads library detection on Windows under cmake. Bumps the minimum diff --git a/www/posts/2022/08/version-2-0-15-released.md b/www/posts/2022/08/version-2-0-15-released.md index 2a770a3a..2b59abce 100644 --- a/www/posts/2022/08/version-2-0-15-released.md +++ b/www/posts/2022/08/version-2-0-15-released.md @@ -52,6 +52,7 @@ and bugfix release. config file. Closes [#2601]. Closes [#2470]. - Fix case where expired messages were causing queued messages not to be delivered. Closes [#2609]. +- Fix websockets not passing on the X-Forwarded-For header. # Client library - Fix threads library detection on Windows under cmake. Bumps the minimum From 7898f12825c88f0fda4aae5b7d36f3792efc655d Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 15:07:54 +0100 Subject: [PATCH 68/70] Update docker --- docker/1.5-openssl/Dockerfile | 2 +- docker/1.5/Dockerfile | 2 +- docker/1.6-openssl/Dockerfile | 2 +- docker/1.6/Dockerfile | 2 +- docker/2.0-openssl/Dockerfile | 6 +++--- docker/2.0/Dockerfile | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docker/1.5-openssl/Dockerfile b/docker/1.5-openssl/Dockerfile index 2d258cbd..3852feff 100644 --- a/docker/1.5-openssl/Dockerfile +++ b/docker/1.5-openssl/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 45c3c162..1a880591 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/1.6-openssl/Dockerfile b/docker/1.6-openssl/Dockerfile index 025d85f1..5bbea105 100644 --- a/docker/1.6-openssl/Dockerfile +++ b/docker/1.6-openssl/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/1.6/Dockerfile b/docker/1.6/Dockerfile index 75b8cf42..a5a71e32 100644 --- a/docker/1.6/Dockerfile +++ b/docker/1.6/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.14 +FROM alpine:3.16 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/2.0-openssl/Dockerfile b/docker/2.0-openssl/Dockerfile index fc3366de..d0eb1ebb 100644 --- a/docker/2.0-openssl/Dockerfile +++ b/docker/2.0-openssl/Dockerfile @@ -1,10 +1,10 @@ -FROM alpine:3.14 +FROM alpine:3.16 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=2.0.14 \ - DOWNLOAD_SHA256=d0dde8fdb12caf6e2426b4f28081919a2fce3448773bdb8af0d3cd5fe5776925 \ +ENV VERSION=2.0.15 \ + DOWNLOAD_SHA256=4735b1d32e3f91c7a8896741d88a3022e89730a1ee897946decfa0df27039ac6 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=4.2.1 \ LWS_SHA256=842da21f73ccba2be59e680de10a8cce7928313048750eb6ad73b6fa50763c51 diff --git a/docker/2.0/Dockerfile b/docker/2.0/Dockerfile index bf54f81f..a1056a4c 100644 --- a/docker/2.0/Dockerfile +++ b/docker/2.0/Dockerfile @@ -1,10 +1,10 @@ -FROM alpine:3.14 +FROM alpine:3.16 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=2.0.14 \ - DOWNLOAD_SHA256=d0dde8fdb12caf6e2426b4f28081919a2fce3448773bdb8af0d3cd5fe5776925 \ +ENV VERSION=2.0.15 \ + DOWNLOAD_SHA256=4735b1d32e3f91c7a8896741d88a3022e89730a1ee897946decfa0df27039ac6 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=4.2.1 \ LWS_SHA256=842da21f73ccba2be59e680de10a8cce7928313048750eb6ad73b6fa50763c51 From e9b2fddaa5dd05fe80f51e7e7f3314149ce06632 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 16:00:12 +0100 Subject: [PATCH 69/70] Update security page --- www/pages/security.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/pages/security.md b/www/pages/security.md index 657e49ce..2f124cca 100644 --- a/www/pages/security.md +++ b/www/pages/security.md @@ -19,6 +19,9 @@ follow the steps on [Eclipse Security] page to report it. Listed with most recent first. Further information on security related issues can be found in the [security category]. +* August 2022: Deleting the anonymous group in the dynamic security plugin + could lead to a crash. Affecting versions **2.0.0** to **2.0.14** inclusive, + fixed in **2.0.15**. * August 2021: [CVE-2021-34434] Affecting versions **2.0.0** to **2.0.11** inclusive, fixed in **2.0.12**. * April 2021: [CVE-2021-28166] Affecting versions **2.0.0** to **2.0.9** From a8448a9c7b14bdaee6ec80419d43fd6544e789b6 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Tue, 16 Aug 2022 16:05:08 +0100 Subject: [PATCH 70/70] Revert 1.x docker builds to alpine 3.14 due to openssl build errors --- docker/1.5-openssl/Dockerfile | 2 +- docker/1.5/Dockerfile | 2 +- docker/1.6-openssl/Dockerfile | 2 +- docker/1.6/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/1.5-openssl/Dockerfile b/docker/1.5-openssl/Dockerfile index 3852feff..2d258cbd 100644 --- a/docker/1.5-openssl/Dockerfile +++ b/docker/1.5-openssl/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.16 +FROM alpine:3.14 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 1a880591..45c3c162 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.16 +FROM alpine:3.14 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/1.6-openssl/Dockerfile b/docker/1.6-openssl/Dockerfile index 5bbea105..025d85f1 100644 --- a/docker/1.6-openssl/Dockerfile +++ b/docker/1.6-openssl/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.16 +FROM alpine:3.14 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" diff --git a/docker/1.6/Dockerfile b/docker/1.6/Dockerfile index a5a71e32..75b8cf42 100644 --- a/docker/1.6/Dockerfile +++ b/docker/1.6/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.16 +FROM alpine:3.14 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker"