+ 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.
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.
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.
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"