diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 00000000..89a90760 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,21 @@ + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 40040969..efda590b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0042 NEW) project(mosquitto) -set (VERSION 2.0.8) +set (VERSION 2.0.10) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/") diff --git a/ChangeLog.txt b/ChangeLog.txt index 21acaa9f..8e496a67 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -36,15 +36,72 @@ Clients: Closes #2180. -2.0.9 - 2021-03-xx +2.0.10 - 2021-04-03 ================== +Security: +- CVE-2021-23980: If an authenticated client connected with MQTT v5 sent a + malformed CONNACK message to the broker a NULL pointer dereference occurred, + most likely resulting in a segfault. + Affects versions 2.0.0 to 2.0.9 inclusive. + Broker: +- Don't over write new receive-maximum if a v5 client connects and takes over + an old session. Closes #2134. +- Fix CVE-xxxx-xxxx. Closes #2163. + +Clients: +- Set `receive-maximum` to not exceed the `-C` message count in mosquitto_sub + and mosquitto_rr, to avoid potentially lost messages. Closes #2134. +- Fix TLS-PSK mode not working with port 8883. Closes #2152. + +Client library: +- Fix possible socket leak. This would occur if a client was using + `mosquitto_loop_start()`, then if the connection failed due to the remote + server being inaccessible they called `mosquitto_loop_stop(, true)` and + recreated the mosquitto object. + +Build: +- A variety of minor build related fixes, like functions not having previous + declarations. +- Fix CMake cross compile builds not finding opensslconf.h. Closes #2160. +- Fix build on Solaris non-sparc. Closes #2136. + + +2.0.9 - 2021-03-11 +================== + +Security: +- If an empty or invalid CA file was provided to the client library for + verifying the remote broker, then the initial connection would fail but + subsequent connections would succeed without verifying the remote broker + certificate. Closes #2130. +- If an empty or invalid CA file was provided to the broker for verifying the + remote broker for an outgoing bridge connection then the initial connection + would fail but subsequent connections would succeed without verifying the + remote broker certificate. Closes #2130. + +Broker: +- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile` + is empty or invalid. Closes #2130. - Fix `tls_version` behaviour not matching documentation. It was setting the exact TLS version to use, not the minimium TLS version to use. Closes #2110. - Fix messages to `$` prefixed topics being rejected. Closes #2111. - Fix QoS 0 messages not being delivered when max_queued_bytes was configured. Closes #2123. +- Fix bridge increasing backoff calculation. +- Improve handling of invalid combinations of listener address and bind + interface configurations. Closes #2081. +- Fix `max_keepalive` option not applying to clients connecting with keepalive + set to 0. Closes #2117. + +Client library: +- Fix encrypted connections incorrectly connecting when the CA file passed to + `mosquitto_tls_set()` is empty or invalid. Closes #2130. +- Fix connections retrying very rapidly in some situations. + +Build: +- Fix cmake epoll detection. 2.0.8 - 2021-02-25 @@ -1783,6 +1840,8 @@ Client library: - Add support for MQTT v3.1.1. - Don't quit mosquitto_loop_forever() if broker not available on first connect. Closes bug #453293, but requires more work. +- Don't reset queued messages state on CONNACK. Fixes bug with duplicate + messages on connection. 1.3.5 - 20141008 diff --git a/README-windows.txt b/README-windows.txt index 7bf0d954..aee672d6 100644 --- a/README-windows.txt +++ b/README-windows.txt @@ -1,18 +1,16 @@ Mosquitto for Windows ===================== -Mosquitto for Windows comes in 32-bit and 64-bit flavours. - -In both cases, the dependencies are not provided in this installer and must be -installed separately in the case that they are not already available. - +Mosquitto for Windows comes in 64-bit and 32-bit flavours. All dependencies are +provided in the installer. Capabilities ------------ Some versions of Windows have limitations on the number of concurrent -connections, set at approximately 2048 connections depending on the version of -Windows you are using. +connections. In modern versions of Windows, e.g. Windows 10 or Windows Server +2019, this is approximately 8192 connections. In earlier versions of Windows, +this limit is 2048 connections. Websockets @@ -23,7 +21,6 @@ through a statically compiled version of libwebsockets and is being distributed under the Static Linking Exception (Section 2) of the License. As a result, the content is not subject to the LGPL 2.1. -Please note that on Windows, libwebsockets limits connections to a maximum of 64 clients. Library Thread Support ---------------------- @@ -35,16 +32,6 @@ A better solution that the old pthreads-win32 is being looked into, so support will return in the future. If you need thread support, the code still supports it just fine. Support has been dropped to simplify installation. -Dependencies ------------- - -* OpenSSL - Link: http://slproweb.com/products/Win32OpenSSL.html - Install "Win32 OpenSSL 1.1.0* Light" or "Win64 OpenSSL 1.1.0* Light" - Required DLLs: libssl-1_1.dll, libcrypto-1_1.dll or libssl-1_1-x64.dll, libcrypto-1_1-x64.dll - -Please ensure that the required DLLs are on the system path, or are in the same directory as -the mosquitto executable - usually C:\Program Files (x86)\mosquitto or C:\Program Files\mosquitto. Windows Service --------------- diff --git a/apps/db_dump/db_dump.c b/apps/db_dump/db_dump.c index ad6d2f7b..5ae009f2 100644 --- a/apps/db_dump/db_dump.c +++ b/apps/db_dump/db_dump.c @@ -27,6 +27,7 @@ Contributors: #include #include +#include "db_dump.h" #include #include #include diff --git a/apps/db_dump/print.c b/apps/db_dump/print.c index 84ca2ef0..bc4eac3e 100644 --- a/apps/db_dump/print.c +++ b/apps/db_dump/print.c @@ -19,6 +19,7 @@ Contributors: #include #include +#include "db_dump.h" #include #include #include @@ -142,7 +143,7 @@ static void print__properties(mosquitto_property *properties) } -void print__client(struct P_client *chunk, int length) +void print__client(struct P_client *chunk, uint32_t length) { printf("DB_CHUNK_CLIENT:\n"); printf("\tLength: %d\n", length); @@ -159,7 +160,7 @@ void print__client(struct P_client *chunk, int length) } -void print__client_msg(struct P_client_msg *chunk, int length) +void print__client_msg(struct P_client_msg *chunk, uint32_t length) { printf("DB_CHUNK_CLIENT_MSG:\n"); printf("\tLength: %d\n", length); @@ -175,8 +176,10 @@ void print__client_msg(struct P_client_msg *chunk, int length) } -void print__msg_store(struct P_msg_store *chunk, int length) +void print__msg_store(struct P_msg_store *chunk, uint32_t length) { + uint8_t *payload; + printf("DB_CHUNK_MSG_STORE:\n"); printf("\tLength: %d\n", length); printf("\tStore ID: %" PRIu64 "\n", chunk->F.store_id); @@ -190,8 +193,6 @@ void print__msg_store(struct P_msg_store *chunk, int length) printf("\tPayload Length: %d\n", chunk->F.payloadlen); printf("\tExpiry Time: %" PRIu64 "\n", chunk->F.expiry_time); - uint8_t *payload; - payload = chunk->payload; if(chunk->F.payloadlen < 256){ /* Print payloads with UTF-8 data below an arbitrary limit of 256 bytes */ diff --git a/apps/db_dump/stubs.c b/apps/db_dump/stubs.c index af00f706..42a14291 100644 --- a/apps/db_dump/stubs.c +++ b/apps/db_dump/stubs.c @@ -1,8 +1,14 @@ #include #include +#include "misc_mosq.h" #include "mosquitto_broker_internal.h" #include "mosquitto_internal.h" +#include "util_mosq.h" + +#ifndef UNUSED +# define UNUSED(A) (void)(A) +#endif struct mosquitto *context__init(mosq_sock_t sock) { diff --git a/apps/mosquitto_ctrl/Makefile b/apps/mosquitto_ctrl/Makefile index 286eb449..502f0dac 100644 --- a/apps/mosquitto_ctrl/Makefile +++ b/apps/mosquitto_ctrl/Makefile @@ -12,7 +12,7 @@ LIBMOSQ:=../../lib/libmosquitto.a endif endif -LOCAL_CPPFLAGS:=-I../mosquitto_passwd +LOCAL_CPPFLAGS:=-I../mosquitto_passwd -DWITH_CJSON OBJS= mosquitto_ctrl.o \ client.o \ diff --git a/apps/mosquitto_ctrl/dynsec.c b/apps/mosquitto_ctrl/dynsec.c index fae86f43..8e3d7250 100644 --- a/apps/mosquitto_ctrl/dynsec.c +++ b/apps/mosquitto_ctrl/dynsec.c @@ -79,6 +79,8 @@ void dynsec__print_usage(void) printf("acltype: publishClientSend|publishClientReceive\n"); printf(" |subscribeLiteral|subscribePattern\n"); printf(" |unsubscribeLiteral|unsubscribePattern\n"); + printf("\nFor more information see:\n"); + printf(" https://mosquitto.org/documentation/dynamic-security/\n\n"); } cJSON *cJSON_AddIntToObject(cJSON * const object, const char * const name, int number) @@ -689,7 +691,7 @@ static cJSON *init_create(const char *username, const char *password, const char } /* mosquitto_ctrl dynsec init [role-name] */ -int dynsec_init(int argc, char *argv[]) +static int dynsec_init(int argc, char *argv[]) { char *filename; char *admin_user; diff --git a/apps/mosquitto_ctrl/mosquitto_ctrl.c b/apps/mosquitto_ctrl/mosquitto_ctrl.c index bda95902..aa706a61 100644 --- a/apps/mosquitto_ctrl/mosquitto_ctrl.c +++ b/apps/mosquitto_ctrl/mosquitto_ctrl.c @@ -28,7 +28,7 @@ Contributors: #include "mosquitto.h" #include "mosquitto_ctrl.h" -void print_version(void) +static void print_version(void) { int major, minor, revision; @@ -36,14 +36,15 @@ void print_version(void) printf("mosquitto_ctrl version %s running on libmosquitto %d.%d.%d.\n", VERSION, major, minor, revision); } -void print_usage(void) +static void print_usage(void) { printf("mosquitto_ctrl is a tool for administering certain Mosquitto features.\n"); print_version(); printf("\nGeneral usage: mosquitto_ctrl \n"); printf("For module specific help use: mosquitto_ctrl help\n"); printf("\nModules available: dynsec\n"); - printf("\nSee https://mosquitto.org/man/mosquitto_ctrl-1.html for more information.\n\n"); + printf("\nFor more information see:\n"); + printf(" https://mosquitto.org/man/mosquitto_ctrl-1.html\n\n"); } @@ -51,7 +52,7 @@ int main(int argc, char *argv[]) { struct mosq_ctrl ctrl; int rc = MOSQ_ERR_SUCCESS; - FUNC_ctrl_main ctrl_main = NULL; + FUNC_ctrl_main l_ctrl_main = NULL; void *lib = NULL; char lib_name[200]; @@ -76,22 +77,22 @@ int main(int argc, char *argv[]) /* In built modules */ if(!strcasecmp(argv[0], "dynsec")){ - ctrl_main = dynsec__main; + l_ctrl_main = dynsec__main; }else{ /* Attempt external module */ snprintf(lib_name, sizeof(lib_name), "mosquitto_ctrl_%s.so", argv[0]); lib = LIB_LOAD(lib_name); if(lib){ - ctrl_main = (FUNC_ctrl_main)LIB_SYM(lib, "ctrl_main"); + l_ctrl_main = (FUNC_ctrl_main)LIB_SYM(lib, "ctrl_main"); } } - if(ctrl_main == NULL){ + if(l_ctrl_main == NULL){ fprintf(stderr, "Error: Module '%s' not supported.\n", argv[0]); rc = MOSQ_ERR_NOT_SUPPORTED; } - if(ctrl_main){ - rc = ctrl_main(argc-1, &argv[1], &ctrl); + if(l_ctrl_main){ + rc = l_ctrl_main(argc-1, &argv[1], &ctrl); if(rc < 0){ /* Usage print */ rc = 0; diff --git a/apps/mosquitto_passwd/get_password.c b/apps/mosquitto_passwd/get_password.c index a62a76cd..42842536 100644 --- a/apps/mosquitto_passwd/get_password.c +++ b/apps/mosquitto_passwd/get_password.c @@ -35,7 +35,9 @@ Contributors: # include #endif -#define MAX_BUFFER_LEN 65536 +#include "get_password.h" + +#define MAX_BUFFER_LEN 65500 #define SALT_LEN 12 void get_password__reset_term(void) diff --git a/apps/mosquitto_passwd/mosquitto_passwd.c b/apps/mosquitto_passwd/mosquitto_passwd.c index 628bcc71..5a5a04f4 100644 --- a/apps/mosquitto_passwd/mosquitto_passwd.c +++ b/apps/mosquitto_passwd/mosquitto_passwd.c @@ -52,7 +52,7 @@ Contributors: # include #endif -#define MAX_BUFFER_LEN 65536 +#define MAX_BUFFER_LEN 65500 #define SALT_LEN 12 #include "misc_mosq.h" @@ -107,7 +107,7 @@ static FILE *mpw_tmpfile(void) #endif -void print_usage(void) +static void print_usage(void) { printf("mosquitto_passwd is a tool for managing password files for mosquitto.\n\n"); printf("Usage: mosquitto_passwd [-H sha512 | -H sha512-pbkdf2] [-c | -D] passwordfile username\n"); @@ -122,7 +122,7 @@ void print_usage(void) printf("\nSee https://mosquitto.org/ for more information.\n\n"); } -int output_new_password(FILE *fptr, const char *username, const char *password, int iterations) +static int output_new_password(FILE *fptr, const char *username, const char *password, int iterations) { int rc; char *salt64 = NULL, *hash64 = NULL; @@ -255,7 +255,7 @@ static int delete_pwuser_cb(FILE *fptr, FILE *ftmp, const char *username, const return 0; } -int delete_pwuser(FILE *fptr, FILE *ftmp, const char *username) +static int delete_pwuser(FILE *fptr, FILE *ftmp, const char *username) { struct cb_helper helper; int rc; @@ -288,7 +288,7 @@ static int update_file_cb(FILE *fptr, FILE *ftmp, const char *username, const ch } } -int update_file(FILE *fptr, FILE *ftmp) +static int update_file(FILE *fptr, FILE *ftmp) { return pwfile_iterate(fptr, ftmp, update_file_cb, NULL); } @@ -315,7 +315,7 @@ static int update_pwuser_cb(FILE *fptr, FILE *ftmp, const char *username, const return rc; } -int update_pwuser(FILE *fptr, FILE *ftmp, const char *username, const char *password, int iterations) +static int update_pwuser(FILE *fptr, FILE *ftmp, const char *username, const char *password, int iterations) { struct cb_helper helper; int rc; @@ -334,7 +334,7 @@ int update_pwuser(FILE *fptr, FILE *ftmp, const char *username, const char *pass } -int copy_contents(FILE *src, FILE *dest) +static int copy_contents(FILE *src, FILE *dest) { char buf[MAX_BUFFER_LEN]; size_t len; @@ -361,7 +361,7 @@ int copy_contents(FILE *src, FILE *dest) return 0; } -int create_backup(const char *backup_file, FILE *fptr) +static int create_backup(const char *backup_file, FILE *fptr) { FILE *fbackup; @@ -380,7 +380,7 @@ int create_backup(const char *backup_file, FILE *fptr) return 0; } -void handle_sigint(int signal) +static void handle_sigint(int signal) { get_password__reset_term(); diff --git a/client/client_shared.c b/client/client_shared.c index 84817cdf..8fddbbb9 100644 --- a/client/client_shared.c +++ b/client/client_shared.c @@ -183,7 +183,7 @@ static int check_format(const char *str) } -void init_config(struct mosq_config *cfg, int pub_or_sub) +static void init_config(struct mosq_config *cfg, int pub_or_sub) { memset(cfg, 0, sizeof(*cfg)); cfg->port = PORT_UNDEFINED; @@ -519,7 +519,7 @@ int client_config_load(struct mosq_config *cfg, int pub_or_sub, int argc, char * return MOSQ_ERR_SUCCESS; } -int cfg_add_topic(struct mosq_config *cfg, int type, char *topic, const char *arg) +static int cfg_add_topic(struct mosq_config *cfg, int type, char *topic, const char *arg) { if(mosquitto_validate_utf8(topic, (int )strlen(topic))){ fprintf(stderr, "Error: Malformed UTF-8 in %s argument.\n\n", arg); @@ -1293,6 +1293,14 @@ static int client_tls_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) } return 1; } +# ifdef FINAL_WITH_TLS_PSK + }else if(cfg->psk){ + if(mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ + err_printf(cfg, "Error: Problem setting TLS-PSK options.\n"); + mosquitto_lib_cleanup(); + return 1; + } +# endif }else if(cfg->port == 8883){ mosquitto_int_option(mosq, MOSQ_OPT_TLS_USE_OS_CERTS, 1); } @@ -1320,12 +1328,6 @@ static int client_tls_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) err_printf(cfg, "Error: Problem setting TLS ALPN protocol.\n"); return 1; } -# ifdef FINAL_WITH_TLS_PSK - if(cfg->psk && mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ - err_printf(cfg, "Error: Problem setting TLS-PSK options.\n"); - return 1; - } -# endif if((cfg->tls_version || cfg->ciphers) && mosquitto_tls_opts_set(mosq, 1, cfg->tls_version, cfg->ciphers)){ err_printf(cfg, "Error: Problem setting TLS options, check the options are valid.\n"); return 1; @@ -1377,6 +1379,13 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) if(cfg->tcp_nodelay){ mosquitto_int_option(mosq, MOSQ_OPT_TCP_NODELAY, 1); } + + if(cfg->msg_count > 0 && cfg->msg_count < 20){ + /* 20 is the default "receive maximum" + * If we don't set this, then we can receive > msg_count messages + * before we quit.*/ + mosquitto_int_option(mosq, MOSQ_OPT_RECEIVE_MAXIMUM, cfg->msg_count); + } return MOSQ_ERR_SUCCESS; } diff --git a/client/client_shared.h b/client/client_shared.h index 39e090d8..0ead8065 100644 --- a/client/client_shared.h +++ b/client/client_shared.h @@ -27,6 +27,10 @@ Contributors: # include #endif +#ifndef __GNUC__ +#define __attribute__(attrib) +#endif + /* pub_client.c modes */ #define MSGMODE_NONE 0 #define MSGMODE_CMD 1 @@ -138,6 +142,5 @@ int client_connect(struct mosquitto *mosq, struct mosq_config *cfg); int cfg_parse_property(struct mosq_config *cfg, int argc, char *argv[], int *idx); -void err_printf(const struct mosq_config *cfg, const char *fmt, ...); - +void err_printf(const struct mosq_config *cfg, const char *fmt, ...) __attribute__((format(printf, 2, 3))); #endif diff --git a/client/pub_client.c b/client/pub_client.c index 63a9ee55..242328ba 100644 --- a/client/pub_client.c +++ b/client/pub_client.c @@ -232,7 +232,7 @@ int pub_shared_init(void) } -int pub_stdin_line_loop(struct mosquitto *mosq) +static int pub_stdin_line_loop(struct mosquitto *mosq) { char *buf2; int buf_len_actual = 0; @@ -334,7 +334,7 @@ int pub_stdin_line_loop(struct mosquitto *mosq) } -int pub_other_loop(struct mosquitto *mosq) +static int pub_other_loop(struct mosquitto *mosq) { int rc; int loop_delay = 1000; @@ -387,7 +387,7 @@ void pub_shared_cleanup(void) } -void print_version(void) +static void print_version(void) { int major, minor, revision; @@ -395,7 +395,7 @@ void print_version(void) printf("mosquitto_pub version %s running on libmosquitto %d.%d.%d.\n", VERSION, major, minor, revision); } -void print_usage(void) +static void print_usage(void) { int major, minor, revision; diff --git a/client/rr_client.c b/client/rr_client.c index a4a52e99..080f08de 100644 --- a/client/rr_client.c +++ b/client/rr_client.c @@ -50,8 +50,6 @@ enum rr__state { static enum rr__state client_state = rr_s_new; -extern struct mosq_config cfg; - bool process_messages = true; int msg_count = 0; struct mosquitto *g_mosq = NULL; @@ -59,7 +57,7 @@ static bool timed_out = false; static int connack_result = 0; #ifndef WIN32 -void my_signal_handler(int signum) +static void my_signal_handler(int signum) { if(signum == SIGALRM){ process_messages = false; @@ -80,7 +78,7 @@ int my_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadl } -void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) +static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) { UNUSED(mosq); UNUSED(obj); @@ -151,7 +149,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag } -void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) +static void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { UNUSED(obj); UNUSED(mid); @@ -179,7 +177,7 @@ void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_ } -void print_version(void) +static void print_version(void) { int major, minor, revision; @@ -187,7 +185,7 @@ void print_version(void) printf("mosquitto_rr version %s running on libmosquitto %d.%d.%d.\n", VERSION, major, minor, revision); } -void print_usage(void) +static void print_usage(void) { int major, minor, revision; diff --git a/client/sub_client.c b/client/sub_client.c index ef9b1e8c..85260d7c 100644 --- a/client/sub_client.c +++ b/client/sub_client.c @@ -48,7 +48,7 @@ static int connack_result = 0; bool connack_received = false; #ifndef WIN32 -void my_signal_handler(int signum) +static void my_signal_handler(int signum) { if(signum == SIGALRM || signum == SIGTERM || signum == SIGINT){ if(connack_received){ @@ -65,19 +65,7 @@ void my_signal_handler(int signum) #endif -void my_publish_callback(struct mosquitto *mosq, void *obj, int mid, int reason_code, const mosquitto_property *properties) -{ - UNUSED(obj); - UNUSED(reason_code); - UNUSED(properties); - - if(process_messages == false && (mid == last_mid || last_mid == 0)){ - mosquitto_disconnect_v5(mosq, 0, cfg.disconnect_props); - } -} - - -void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) +static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *properties) { int i; bool res; @@ -120,7 +108,7 @@ void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquit } } -void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties) +static void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flags, const mosquitto_property *properties) { int i; @@ -153,7 +141,7 @@ void my_connect_callback(struct mosquitto *mosq, void *obj, int result, int flag } } -void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) +static void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos) { int i; bool some_sub_allowed = (granted_qos[0] < 128); @@ -177,7 +165,7 @@ void my_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_c } } -void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) +static void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *str) { UNUSED(mosq); UNUSED(obj); @@ -186,7 +174,7 @@ void my_log_callback(struct mosquitto *mosq, void *obj, int level, const char *s printf("%s\n", str); } -void print_version(void) +static void print_version(void) { int major, minor, revision; @@ -194,7 +182,7 @@ void print_version(void) printf("mosquitto_sub version %s running on libmosquitto %d.%d.%d.\n", VERSION, major, minor, revision); } -void print_usage(void) +static void print_usage(void) { int major, minor, revision; diff --git a/config.mk b/config.mk index 73e5cc39..fe6a822a 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.8 +VERSION=2.0.10 # Client library SO version. Bump if incompatible API/ABI changes are made. SOVERSION=1 @@ -140,6 +140,7 @@ DB_HTML_XSL=man/html.xsl #MANCOUNTRIES=en_GB UNAME:=$(shell uname -s) +ARCH:=$(shell uname -p) ifeq ($(UNAME),SunOS) ifeq ($(CC),cc) @@ -148,7 +149,7 @@ ifeq ($(UNAME),SunOS) CFLAGS?=-Wall -ggdb -O2 endif else - CFLAGS?=-Wall -ggdb -O2 -Wconversion + CFLAGS?=-Wall -ggdb -O2 -Wconversion -Wextra endif STATIC_LIB_DEPS:= @@ -199,9 +200,15 @@ ifeq ($(WITH_SHARED_LIBRARIES),yes) endif ifeq ($(UNAME),SunOS) - ifeq ($(CC),cc) - LIB_CFLAGS:=$(LIB_CFLAGS) -xc99 -KPIC - else + SEDINPLACE:= + ifeq ($(ARCH),sparc) + ifeq ($(CC),cc) + LIB_CFLAGS:=$(LIB_CFLAGS) -xc99 -KPIC + else + LIB_CFLAGS:=$(LIB_CFLAGS) -fPIC + endif + endif + ifeq ($(ARCH),i386) LIB_CFLAGS:=$(LIB_CFLAGS) -fPIC endif diff --git a/docker/1.5-openssl/Dockerfile b/docker/1.5-openssl/Dockerfile index 728c145e..996e69e4 100644 --- a/docker/1.5-openssl/Dockerfile +++ b/docker/1.5-openssl/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.12 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=1.5.10 \ - DOWNLOAD_SHA256=00d9688dffef0e2c26f3fb1486931ed5d89042d81f6d4c1dd455d63080149c20 \ +ENV VERSION=1.5.11 \ + DOWNLOAD_SHA256=4a3b8a8f5505d27a7a966dd68bfd76f1e69feb51796d1b46b7271d1bb5a1a299 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile index 742bbaab..612bd2cc 100644 --- a/docker/1.5/Dockerfile +++ b/docker/1.5/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.12 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=1.5.10 \ - DOWNLOAD_SHA256=00d9688dffef0e2c26f3fb1486931ed5d89042d81f6d4c1dd455d63080149c20 \ +ENV VERSION=1.5.11 \ + DOWNLOAD_SHA256=4a3b8a8f5505d27a7a966dd68bfd76f1e69feb51796d1b46b7271d1bb5a1a299 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 \ LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 diff --git a/docker/1.6-openssl/Dockerfile b/docker/1.6-openssl/Dockerfile index c26c07e6..3c09a74d 100644 --- a/docker/1.6-openssl/Dockerfile +++ b/docker/1.6-openssl/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.12 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=1.6.13 \ - DOWNLOAD_SHA256=ce205248dd323e4e562ff83e9e84d0f9a16f4bda87183c367c66a7163c0fc287 \ +ENV VERSION=1.6.14 \ + DOWNLOAD_SHA256=5ea7e342bfbd212a0addb915036be168040dea945e5de5fe739c43c5ff3823e4 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 \ LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 diff --git a/docker/1.6/Dockerfile b/docker/1.6/Dockerfile index f8fa4fd9..86304cb8 100644 --- a/docker/1.6/Dockerfile +++ b/docker/1.6/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.12 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=1.6.13 \ - DOWNLOAD_SHA256=ce205248dd323e4e562ff83e9e84d0f9a16f4bda87183c367c66a7163c0fc287 \ +ENV VERSION=1.6.14 \ + DOWNLOAD_SHA256=5ea7e342bfbd212a0addb915036be168040dea945e5de5fe739c43c5ff3823e4 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 \ LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 diff --git a/docker/2.0-openssl/Dockerfile b/docker/2.0-openssl/Dockerfile index 85e0ee2c..96875b04 100644 --- a/docker/2.0-openssl/Dockerfile +++ b/docker/2.0-openssl/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.12 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=2.0.8 \ - DOWNLOAD_SHA256=b15da8fc4edcb91d554e1259e220ea0173ef639ceaa4b465e06feb7e125b84bf \ +ENV VERSION=2.0.10 \ + DOWNLOAD_SHA256=0188f7b21b91d6d80e992b8d6116ba851468b3bd154030e8a003ed28fb6f4a44 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 \ LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 \ diff --git a/docker/2.0/Dockerfile b/docker/2.0/Dockerfile index 1111687b..7a322dde 100644 --- a/docker/2.0/Dockerfile +++ b/docker/2.0/Dockerfile @@ -3,8 +3,8 @@ FROM alpine:3.12 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=2.0.8 \ - DOWNLOAD_SHA256=b15da8fc4edcb91d554e1259e220ea0173ef639ceaa4b465e06feb7e125b84bf \ +ENV VERSION=2.0.10 \ + DOWNLOAD_SHA256=0188f7b21b91d6d80e992b8d6116ba851468b3bd154030e8a003ed28fb6f4a44 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=2.4.2 \ LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 \ diff --git a/docker/generic/Dockerfile b/docker/generic/Dockerfile index bdda597b..5a7e8e42 100644 --- a/docker/generic/Dockerfile +++ b/docker/generic/Dockerfile @@ -1,74 +1,114 @@ -FROM alpine:edge AS build +FROM alpine:3.12 + +LABEL maintainer="Roger Light " \ + description="Eclipse Mosquitto MQTT Broker" -# A released dist version, like "1.2.3" ARG VERSION RUN test -n "${VERSION}" -RUN apk --no-cache add \ - build-base \ - c-ares-dev \ - ca-certificates \ - cjson-dev \ - curl \ - libwebsockets-dev \ - libxslt \ - openssl-dev \ - python2 \ - util-linux-dev +ENV \ + GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ + LWS_VERSION=2.4.2 \ + LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 \ + CJSON_VERSION=1.7.14 \ + CJSON_SHA256=fb50a663eefdc76bafa80c82bc045af13b1363e8f45cec8b442007aef6a41343 -# This build procedure is based on: -# https://github.com/alpinelinux/aports/blob/master/main/mosquitto/APKBUILD -# -# If this step fails, double check the version build-arg and make sure its -# a valid published tarball at https://mosquitto.org/files/source/ -RUN mkdir -p /build /install && \ - curl -SL https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz \ - | tar --strip=1 -xzC /build && \ - make -C /build \ - WITH_MEMORY_TRACKING=no \ - WITH_WEBSOCKETS=yes \ - WITH_SRV=yes \ - WITH_TLS_PSK=no \ - WITH_ADNS=no \ - prefix=/usr \ - binary && \ - make -C /build \ - prefix=/usr \ - DESTDIR="/install" \ - install && \ - mv /install/etc/mosquitto/mosquitto.conf.example /install/etc/mosquitto/mosquitto.conf && \ - sed -i -e 's/#log_dest stderr/log_dest syslog/' /install/etc/mosquitto/mosquitto.conf - - -# Single-layer image for the mosquitto distribution -FROM alpine:latest -LABEL maintainer="Jonathan Hanson " \ - description="Eclipse Mosquitto MQTT Broker" - -# Install the run-time dependencies -RUN apk --no-cache add \ - busybox \ - ca-certificates \ - cjson \ - openssl \ - libuuid \ - libwebsockets \ - musl - -# Copy over the built install from the earlier image layer -COPY --from=build /install / - -# Set up the mosquitto directories and the mosquitto user -RUN addgroup -S mosquitto 2>/dev/null && \ - adduser -S -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ +RUN set -x && \ + apk --no-cache add --virtual build-deps \ + build-base \ + cmake \ + gnupg \ + openssl-dev \ + util-linux-dev && \ + wget https://github.com/warmcat/libwebsockets/archive/v${LWS_VERSION}.tar.gz -O /tmp/lws.tar.gz && \ + echo "$LWS_SHA256 /tmp/lws.tar.gz" | sha256sum -c - && \ + mkdir -p /build/lws && \ + tar --strip=1 -xf /tmp/lws.tar.gz -C /build/lws && \ + rm /tmp/lws.tar.gz && \ + cd /build/lws && \ + cmake . \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DLWS_IPV6=ON \ + -DLWS_WITHOUT_BUILTIN_GETIFADDRS=ON \ + -DLWS_WITHOUT_CLIENT=ON \ + -DLWS_WITHOUT_EXTENSIONS=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_ZIP_FOPS=OFF \ + -DLWS_WITH_ZLIB=OFF && \ + make -j "$(nproc)" && \ + rm -rf /root/.cmake && \ + wget https://github.com/DaveGamble/cJSON/archive/v${CJSON_VERSION}.tar.gz -O /tmp/cjson.tar.gz && \ + echo "$CJSON_SHA256 /tmp/cjson.tar.gz" | sha256sum -c - && \ + mkdir -p /build/cjson && \ + tar --strip=1 -xf /tmp/cjson.tar.gz -C /build/cjson && \ + rm /tmp/cjson.tar.gz && \ + cd /build/cjson && \ + cmake . \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DBUILD_SHARED_AND_STATIC_LIBS=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DCJSON_BUILD_SHARED_LIBS=OFF \ + -DCJSON_OVERRIDE_BUILD_SHARED_LIBS=OFF \ + -DCMAKE_INSTALL_PREFIX=/usr && \ + make -j "$(nproc)" && \ + rm -rf /root/.cmake && \ + wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz -O /tmp/mosq.tar.gz && \ + wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz.asc -O /tmp/mosq.tar.gz.asc && \ + export GNUPGHOME="$(mktemp -d)" && \ + found=''; \ + for server in \ + ha.pool.sks-keyservers.net \ + hkp://keyserver.ubuntu.com:80 \ + hkp://p80.pool.sks-keyservers.net:80 \ + pgp.mit.edu \ + ; do \ + echo "Fetching GPG key $GPG_KEYS from $server"; \ + gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; \ + done; \ + test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; \ + gpg --batch --verify /tmp/mosq.tar.gz.asc /tmp/mosq.tar.gz && \ + gpgconf --kill all && \ + rm -rf "$GNUPGHOME" /tmp/mosq.tar.gz.asc && \ + mkdir -p /build/mosq && \ + tar --strip=1 -xf /tmp/mosq.tar.gz -C /build/mosq && \ + rm /tmp/mosq.tar.gz && \ + make -C /build/mosq -j "$(nproc)" \ + CFLAGS="-Wall -O2 -I/build/lws/include -I/build" \ + LDFLAGS="-L/build/lws/lib -L/build/cjson" \ + WITH_ADNS=no \ + WITH_DOCS=no \ + WITH_SHARED_LIBRARIES=yes \ + WITH_SRV=no \ + WITH_STRIP=yes \ + WITH_TLS_PSK=no \ + WITH_WEBSOCKETS=yes \ + prefix=/usr \ + binary && \ + addgroup -S -g 1883 mosquitto 2>/dev/null && \ + adduser -S -u 1883 -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \ - cp /etc/mosquitto/mosquitto.conf /mosquitto/config && \ - chown -R mosquitto:mosquitto /mosquitto + install -d /usr/sbin/ && \ + install -s -m755 /build/mosq/client/mosquitto_pub /usr/bin/mosquitto_pub && \ + install -s -m755 /build/mosq/client/mosquitto_rr /usr/bin/mosquitto_rr && \ + install -s -m755 /build/mosq/client/mosquitto_sub /usr/bin/mosquitto_sub && \ + install -s -m644 /build/mosq/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1 && \ + install -s -m755 /build/mosq/src/mosquitto /usr/sbin/mosquitto && \ + install -s -m755 /build/mosq/apps/mosquitto_ctrl/mosquitto_ctrl /usr/bin/mosquitto_ctrl && \ + install -s -m755 /build/mosq/apps/mosquitto_passwd/mosquitto_passwd /usr/bin/mosquitto_passwd && \ + install -s -m755 /build/mosq/plugins/dynamic-security/mosquitto_dynamic_security.so /usr/lib/mosquitto_dynamic_security.so && \ + install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \ + chown -R mosquitto:mosquitto /mosquitto && \ + apk --no-cache add \ + ca-certificates && \ + apk del build-deps && \ + rm -rf /build -VOLUME ["/mosquitto/config", "/mosquitto/data", "/mosquitto/log"] +VOLUME ["/mosquitto/data", "/mosquitto/log"] # Set up the entry point script and default command -COPY docker-entrypoint.sh / +COPY docker-entrypoint.sh mosquitto-no-auth.conf / EXPOSE 1883 ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"] diff --git a/docker/generic/README.md b/docker/generic/README.md index 4e0279c7..d2c20643 100644 --- a/docker/generic/README.md +++ b/docker/generic/README.md @@ -9,6 +9,19 @@ Three docker volumes have been created in the image to be used for configuration /mosquitto/log ``` +## Running without a configuration file +Mosquitto 2.0 requires you to configure listeners and authentication before it +will allow connections from anything other than the loopback interface. In the +context of a container, this means you would normally need to provide a +configuration file with your settings. + +If you wish to run mosquitto without any authentication, and without setting +any other configuration options, you can do so by using a configuration +provided in the container for this purpose: +``` +docker run -it -p 1883:1883 eclipse-mosquitto: mosquitto -c /mosquitto-no-auth.conf +``` + ## Configuration When creating a container from the image, the default configuration values are used. To use a custom configuration file, mount a **local** configuration file to `/mosquitto/config/mosquitto.conf` diff --git a/docker/generic/mosquitto-no-auth.conf b/docker/generic/mosquitto-no-auth.conf new file mode 100644 index 00000000..40dd92b9 --- /dev/null +++ b/docker/generic/mosquitto-no-auth.conf @@ -0,0 +1,5 @@ +# This is a Mosquitto configuration file that creates a listener on port 1883 +# that allows unauthenticated access. + +listener 1883 +allow_anonymous true diff --git a/include/mosquitto.h b/include/mosquitto.h index 0dcb28eb..03557639 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 8 +#define LIBMOSQUITTO_REVISION 10 /* 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 e34c7847..437bf95f 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.8 +!define VERSION 2.0.10 OutFile "mosquitto-${VERSION}-install-windows-x86.exe" InstallDir "$PROGRAMFILES\mosquitto" diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index 4bd80f54..aeb8548b 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.8 +!define VERSION 2.0.10 OutFile "mosquitto-${VERSION}-install-windows-x64.exe" !include "x64.nsh" diff --git a/lib/connect.c b/lib/connect.c index 85225dc4..af4743cf 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -190,7 +190,7 @@ static int mosquitto__reconnect(struct mosquitto *mosq, bool blocking) packet__cleanup_all(mosq); - message__reconnect_reset(mosq); + message__reconnect_reset(mosq, false); if(mosq->sock != INVALID_SOCKET){ net__socket_close(mosq); //close socket diff --git a/lib/handle_auth.c b/lib/handle_auth.c index e33d085d..61f3bb4f 100644 --- a/lib/handle_auth.c +++ b/lib/handle_auth.c @@ -26,6 +26,7 @@ Contributors: #include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "read_handle.h" int handle__auth(struct mosquitto *mosq) diff --git a/lib/handle_connack.c b/lib/handle_connack.c index a7825ab7..cd0c8049 100644 --- a/lib/handle_connack.c +++ b/lib/handle_connack.c @@ -82,7 +82,7 @@ int handle__connack(struct mosquitto *mosq) mosquitto_property_read_int32(properties, MQTT_PROP_MAXIMUM_PACKET_SIZE, &mosq->maximum_packet_size, false); mosq->msgs_out.inflight_quota = mosq->msgs_out.inflight_maximum; - message__reconnect_reset(mosq); + message__reconnect_reset(mosq, true); log__printf(mosq, MOSQ_LOG_DEBUG, "Client %s received CONNACK (%d)", mosq->id, reason_code); if(reason_code == MQTT_RC_SUCCESS){ diff --git a/lib/handle_disconnect.c b/lib/handle_disconnect.c index a0a638db..28c51845 100644 --- a/lib/handle_disconnect.c +++ b/lib/handle_disconnect.c @@ -27,6 +27,7 @@ Contributors: #include "net_mosq.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "read_handle.h" #include "send_mosq.h" #include "util_mosq.h" diff --git a/lib/handle_publish.c b/lib/handle_publish.c index ae2d1281..c7ce2c54 100644 --- a/lib/handle_publish.c +++ b/lib/handle_publish.c @@ -31,6 +31,7 @@ Contributors: #include "messages_mosq.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "read_handle.h" #include "send_mosq.h" #include "time_mosq.h" #include "util_mosq.h" diff --git a/lib/handle_suback.c b/lib/handle_suback.c index c711cbfa..a930d28e 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -32,6 +32,7 @@ Contributors: #include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "read_handle.h" #include "util_mosq.h" diff --git a/lib/logging_mosq.c b/lib/logging_mosq.c index 16e9e949..24d56867 100644 --- a/lib/logging_mosq.c +++ b/lib/logging_mosq.c @@ -23,11 +23,12 @@ Contributors: #include #include +#include "logging_mosq.h" #include "mosquitto_internal.h" #include "mosquitto.h" #include "memory_mosq.h" -int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...) +int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt, ...) { va_list va; char *s; @@ -50,7 +51,7 @@ int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...) va_end(va); s[len-1] = '\0'; /* Ensure string is null terminated. */ - mosq->on_log(mosq, mosq->userdata, priority, s); + mosq->on_log(mosq, mosq->userdata, (int)priority, s); mosquitto__free(s); } diff --git a/lib/logging_mosq.h b/lib/logging_mosq.h index 580edb8b..bc94f5f5 100644 --- a/lib/logging_mosq.h +++ b/lib/logging_mosq.h @@ -20,6 +20,10 @@ Contributors: #include "mosquitto.h" -int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt, ...); +#ifndef __GNUC__ +#define __attribute__(attrib) +#endif + +int log__printf(struct mosquitto *mosq, unsigned int level, const char *fmt, ...) __attribute__((format(printf, 3, 4))); #endif diff --git a/lib/loop.c b/lib/loop.c index 9eba6429..05c46234 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -204,6 +204,12 @@ static int interruptible_sleep(struct mosquitto *mosq, time_t reconnect_delay) char pairbuf; int maxfd = 0; +#ifndef WIN32 + while(read(mosq->sockpairR, &pairbuf, 1) > 0); +#else + while(recv(mosq->sockpairR, &pairbuf, 1, 0) > 0); +#endif + local_timeout.tv_sec = reconnect_delay; #ifdef HAVE_PSELECT local_timeout.tv_nsec = 0; diff --git a/lib/messages_mosq.c b/lib/messages_mosq.c index 9d0510e3..4e17d047 100644 --- a/lib/messages_mosq.c +++ b/lib/messages_mosq.c @@ -137,7 +137,7 @@ int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message return message__release_to_inflight(mosq, dir); } -void message__reconnect_reset(struct mosquitto *mosq) +void message__reconnect_reset(struct mosquitto *mosq, bool update_quota_only) { struct mosquitto_message_all *message, *tmp; assert(mosq); @@ -167,15 +167,17 @@ void message__reconnect_reset(struct mosquitto *mosq) if(mosq->msgs_out.inflight_quota != 0){ util__decrement_send_quota(mosq); - if(message->msg.qos == 1){ - message->state = mosq_ms_publish_qos1; - }else if(message->msg.qos == 2){ - if(message->state == mosq_ms_wait_for_pubrec){ - message->state = mosq_ms_publish_qos2; - }else if(message->state == mosq_ms_wait_for_pubcomp){ - message->state = mosq_ms_resend_pubrel; + if (update_quota_only == false){ + if(message->msg.qos == 1){ + message->state = mosq_ms_publish_qos1; + }else if(message->msg.qos == 2){ + if(message->state == mosq_ms_wait_for_pubrec){ + message->state = mosq_ms_publish_qos2; + }else if(message->state == mosq_ms_wait_for_pubcomp){ + message->state = mosq_ms_resend_pubrel; + } + /* Should be able to preserve state. */ } - /* Should be able to preserve state. */ } }else{ message->state = mosq_ms_invalid; diff --git a/lib/messages_mosq.h b/lib/messages_mosq.h index 5689b49e..ee5ba5cd 100644 --- a/lib/messages_mosq.h +++ b/lib/messages_mosq.h @@ -25,7 +25,7 @@ void message__cleanup_all(struct mosquitto *mosq); void message__cleanup(struct mosquitto_message_all **message); int message__delete(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, int qos); int message__queue(struct mosquitto *mosq, struct mosquitto_message_all *message, enum mosquitto_msg_direction dir); -void message__reconnect_reset(struct mosquitto *mosq); +void message__reconnect_reset(struct mosquitto *mosq, bool update_quota_only); int message__release_to_inflight(struct mosquitto *mosq, enum mosquitto_msg_direction dir); int message__remove(struct mosquitto *mosq, uint16_t mid, enum mosquitto_msg_direction dir, struct mosquitto_message_all **message, int qos); void message__retry_check(struct mosquitto *mosq); diff --git a/lib/misc_mosq.c b/lib/misc_mosq.c index e7bf0784..8f2f2d2a 100644 --- a/lib/misc_mosq.c +++ b/lib/misc_mosq.c @@ -36,6 +36,8 @@ Contributors: # include #endif +#include "misc_mosq.h" + FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read) { diff --git a/lib/misc_mosq.h b/lib/misc_mosq.h index 233071e6..f86f5d76 100644 --- a/lib/misc_mosq.h +++ b/lib/misc_mosq.h @@ -19,6 +19,7 @@ Contributors: #define MISC_MOSQ_H #include +#include FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read); char *misc__trimblanks(char *str); diff --git a/lib/mosquitto.c b/lib/mosquitto.c index 34a69488..1b69102c 100644 --- a/lib/mosquitto.c +++ b/lib/mosquitto.c @@ -195,6 +195,7 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st #ifdef WITH_TLS mosq->ssl = NULL; mosq->ssl_ctx = NULL; + mosq->ssl_ctx_defaults = true; mosq->tls_cert_reqs = SSL_VERIFY_PEER; mosq->tls_insecure = false; mosq->want_write = false; diff --git a/lib/net_mosq.c b/lib/net_mosq.c index d42d83a7..16d0e8c9 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -917,16 +917,13 @@ int net__socket_connect_step3(struct mosquitto *mosq, const char *host) /* Create a socket and connect it to 'ip' on port 'port'. */ int net__socket_connect(struct mosquitto *mosq, const char *host, uint16_t port, const char *bind_address, bool blocking) { - mosq_sock_t sock = INVALID_SOCKET; int rc, rc2; if(!mosq || !host) return MOSQ_ERR_INVAL; - rc = net__try_connect(host, port, &sock, bind_address, blocking); + rc = net__try_connect(host, port, &mosq->sock, bind_address, blocking); if(rc > 0) return rc; - mosq->sock = sock; - if(mosq->tcp_nodelay){ int flag = 1; if(setsockopt(mosq->sock, IPPROTO_TCP, TCP_NODELAY, (const void*)&flag, sizeof(int)) != 0){ diff --git a/lib/net_mosq_ocsp.c b/lib/net_mosq_ocsp.c index 84b818c8..8c762373 100644 --- a/lib/net_mosq_ocsp.c +++ b/lib/net_mosq_ocsp.c @@ -64,10 +64,11 @@ int mosquitto__verify_ocsp_status_cb(SSL * ssl, void *arg) OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; + long len; UNUSED(ssl); - long len = SSL_get_tlsext_status_ocsp_resp(mosq->ssl, &p); + len = SSL_get_tlsext_status_ocsp_resp(mosq->ssl, &p); log__printf(mosq, MOSQ_LOG_DEBUG, "OCSP: SSL_get_tlsext_status_ocsp_resp returned %ld bytes", len); /* the following functions expect a const pointer */ diff --git a/lib/property_mosq.c b/lib/property_mosq.c index 8a77dbe6..0cfc9f9c 100644 --- a/lib/property_mosq.c +++ b/lib/property_mosq.c @@ -33,7 +33,7 @@ Contributors: #include "property_mosq.h" -int property__read(struct mosquitto__packet *packet, uint32_t *len, mosquitto_property *property) +static int property__read(struct mosquitto__packet *packet, uint32_t *len, mosquitto_property *property) { int rc; uint32_t property_identifier; @@ -355,7 +355,7 @@ unsigned int property__get_remaining_length(const mosquitto_property *props) } -int property__write(struct mosquitto__packet *packet, const mosquitto_property *property) +static int property__write(struct mosquitto__packet *packet, const mosquitto_property *property) { int rc; @@ -975,7 +975,7 @@ int mosquitto_property_check_all(int command, const mosquitto_property *properti return MOSQ_ERR_SUCCESS; } -const mosquitto_property *property__get_property(const mosquitto_property *proplist, int identifier, bool skip_first) +static const mosquitto_property *property__get_property(const mosquitto_property *proplist, int identifier, bool skip_first) { const mosquitto_property *p; bool is_first = true; diff --git a/lib/send_connect.c b/lib/send_connect.c index d35cd80e..d9a3257c 100644 --- a/lib/send_connect.c +++ b/lib/send_connect.c @@ -32,6 +32,7 @@ Contributors: #include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "send_mosq.h" int send__connect(struct mosquitto *mosq, uint16_t keepalive, bool clean_session, const mosquitto_property *properties) { diff --git a/lib/send_subscribe.c b/lib/send_subscribe.c index a8e77545..9217dc5b 100644 --- a/lib/send_subscribe.c +++ b/lib/send_subscribe.c @@ -32,10 +32,11 @@ Contributors: #include "mqtt_protocol.h" #include "packet_mosq.h" #include "property_mosq.h" +#include "send_mosq.h" #include "util_mosq.h" -int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, const char **topic, int topic_qos, const mosquitto_property *properties) +int send__subscribe(struct mosquitto *mosq, int *mid, int topic_count, char *const *const topic, int topic_qos, const mosquitto_property *properties) { struct mosquitto__packet *packet = NULL; uint32_t packetlen; diff --git a/lib/socks_mosq.c b/lib/socks_mosq.c index a360d64b..ed8fe128 100644 --- a/lib/socks_mosq.c +++ b/lib/socks_mosq.c @@ -23,7 +23,7 @@ Contributors: #include #ifdef WIN32 # include -#elif __QNX__ +#elif defined(__QNX__) # include # include # include @@ -40,6 +40,7 @@ Contributors: #include "net_mosq.h" #include "packet_mosq.h" #include "send_mosq.h" +#include "socks_mosq.h" #include "util_mosq.h" #define SOCKS_AUTH_NONE 0x00U diff --git a/lib/tls_mosq.c b/lib/tls_mosq.c index bddf2ec0..13d9aa22 100644 --- a/lib/tls_mosq.c +++ b/lib/tls_mosq.c @@ -84,7 +84,7 @@ int mosquitto__server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx) } } -int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname) +static int mosquitto__cmp_hostname_wildcard(char *certname, const char *hostname) { size_t i; size_t len; diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index e261776b..0c008839 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -42,7 +42,8 @@ Authentication The authentication options described below allow a wide range of possibilities in conjunction with the listener options. This - section aims to clarify the possibilities. + section aims to clarify the possibilities. An overview is also available at + The simplest option is to have no authentication at all. This is the default if no other options are given. Unauthenticated encrypted support is provided by using the certificate based @@ -54,6 +55,11 @@ vulnerable to interception. Use the to control whether passwords are required globally or on a per-listener basis. + Mosquitto provides the Dynamic Security plugin which handles + username/password authentication and access control in a much + more flexible way than a password file. See + + When using certificate based encryption there are three options that affect authentication. The first is require_certificate, which may be set to true or false. If false, the SSL/TLS component of the @@ -164,6 +170,9 @@ Reloaded on reload signal. The currently loaded ACLs will be freed and reloaded. Existing subscriptions will be affected after the reload. + See also + + @@ -267,6 +276,9 @@ alongsize , the plugin checks will run after the built in checks. Not currently reloaded on reload signal. + See also + + @@ -753,7 +765,9 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S Clients that are already connected will not be affected. See also - mosquitto_passwd1. + mosquitto_passwd1 and + + diff --git a/man/mosquitto_ctrl.1.xml b/man/mosquitto_ctrl.1.xml index 1f1f29f2..e86180d9 100644 --- a/man/mosquitto_ctrl.1.xml +++ b/man/mosquitto_ctrl.1.xml @@ -17,7 +17,7 @@ mosquitto_ctrl - connection-options + connection-options | -o config-file module-name module-command command-options @@ -132,7 +132,11 @@ The options below may be given on the command line, but may also be placed in a config file located at or - with one pair of + . + The config file may be specified manually with the + + option. + The config file should have one pair of per line. The values in the config file will be used as defaults and can be overridden by using the command line. The exceptions to @@ -320,6 +324,20 @@ being sent than would normally be necessary. + + config-file + + Provide a path to a config file to load options from. The config file should have one pair of + + per line. The values in the config file will be used as defaults + and can be overridden by using the command line. The exceptions to + this are the message type options, of which only one can be + specified. Note also that currently some options cannot be negated, + e.g. . Config file lines that have a + as the first character are treated as comments + and not processed any further. + + diff --git a/man/mosquitto_rr.1.xml b/man/mosquitto_rr.1.xml index b71bf080..f59aac01 100644 --- a/man/mosquitto_rr.1.xml +++ b/man/mosquitto_rr.1.xml @@ -676,7 +676,7 @@ , or the more verbose , , or . - Defaults to . + Defaults to . diff --git a/plugins/dynamic-security/Makefile b/plugins/dynamic-security/Makefile index 9ef728b1..7ef77b7b 100644 --- a/plugins/dynamic-security/Makefile +++ b/plugins/dynamic-security/Makefile @@ -3,7 +3,7 @@ include ../../config.mk .PHONY : all binary check clean reallyclean test install uninstall PLUGIN_NAME=mosquitto_dynamic_security -LOCAL_CPPFLAGS=-I../../src/ +LOCAL_CPPFLAGS=-I../../src/ -DWITH_CJSON OBJS= \ acl.o \ diff --git a/plugins/dynamic-security/json_help.c b/plugins/dynamic-security/json_help.c index e0c8178b..5331d3f9 100644 --- a/plugins/dynamic-security/json_help.c +++ b/plugins/dynamic-security/json_help.c @@ -23,6 +23,7 @@ Contributors: #include #include +#include "json_help.h" #include "mosquitto.h" diff --git a/plugins/dynamic-security/plugin.c b/plugins/dynamic-security/plugin.c index d5a8cf06..27c3904d 100644 --- a/plugins/dynamic-security/plugin.c +++ b/plugins/dynamic-security/plugin.c @@ -131,7 +131,7 @@ static int dynsec_control_callback(int event, void *event_data, void *userdata) return MOSQ_ERR_SUCCESS; } -int dynsec__process_set_default_acl_access(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) +static int dynsec__process_set_default_acl_access(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { cJSON *j_actions, *j_action, *j_acltype, *j_allow; bool allow; @@ -174,7 +174,7 @@ int dynsec__process_set_default_acl_access(cJSON *j_responses, struct mosquitto } -int dynsec__process_get_default_acl_access(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) +static int dynsec__process_get_default_acl_access(cJSON *j_responses, struct mosquitto *context, cJSON *command, char *correlation_data) { cJSON *tree, *jtmp, *j_data, *j_acls, *j_acl; const char *admin_clientid, *admin_username; diff --git a/plugins/dynamic-security/rolelist.c b/plugins/dynamic-security/rolelist.c index a8c93a96..2bc1f163 100644 --- a/plugins/dynamic-security/rolelist.c +++ b/plugins/dynamic-security/rolelist.c @@ -51,7 +51,7 @@ static int rolelist_cmp(void *a, void *b) } -void dynsec_rolelist__free_item(struct dynsec__rolelist **base_rolelist, struct dynsec__rolelist *rolelist) +static void dynsec_rolelist__free_item(struct dynsec__rolelist **base_rolelist, struct dynsec__rolelist *rolelist) { HASH_DELETE(hh, *base_rolelist, rolelist); mosquitto_free(rolelist->rolename); @@ -67,7 +67,7 @@ void dynsec_rolelist__cleanup(struct dynsec__rolelist **base_rolelist) } } -int dynsec_rolelist__remove_role(struct dynsec__rolelist **base_rolelist, const struct dynsec__role *role) +static int dynsec_rolelist__remove_role(struct dynsec__rolelist **base_rolelist, const struct dynsec__role *role) { struct dynsec__rolelist *found_rolelist; diff --git a/plugins/dynamic-security/roles.c b/plugins/dynamic-security/roles.c index fb116770..4d5accfc 100644 --- a/plugins/dynamic-security/roles.c +++ b/plugins/dynamic-security/roles.c @@ -209,7 +209,7 @@ static int insert_acl_cmp(struct dynsec__acl *a, struct dynsec__acl *b) } -int dynsec_roles__acl_load(cJSON *j_acls, const char *key, struct dynsec__acl **acllist) +static int dynsec_roles__acl_load(cJSON *j_acls, const char *key, struct dynsec__acl **acllist) { cJSON *j_acl, *j_type, *jtmp; struct dynsec__acl *acl; diff --git a/plugins/dynamic-security/sub_matches_sub.c b/plugins/dynamic-security/sub_matches_sub.c index fb913902..5f5d55a6 100644 --- a/plugins/dynamic-security/sub_matches_sub.c +++ b/plugins/dynamic-security/sub_matches_sub.c @@ -21,6 +21,8 @@ Contributors: #include #include +#include "dynamic_security.h" + static char *strtok_hier(char *str, char **saveptr) { char *c; diff --git a/plugins/examples/auth-by-ip/CMakeLists.txt b/plugins/examples/auth-by-ip/CMakeLists.txt index ce856715..45260bd5 100644 --- a/plugins/examples/auth-by-ip/CMakeLists.txt +++ b/plugins/examples/auth-by-ip/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/include - ${STDBOOL_H_PATH} ${STDINT_H_PATH}) + ${OPENSSL_INCLUDE_DIR} ${STDBOOL_H_PATH} ${STDINT_H_PATH}) add_library(mosquitto_auth_by_ip SHARED mosquitto_auth_by_ip.c) set_target_properties(mosquitto_auth_by_ip PROPERTIES diff --git a/plugins/examples/auth-by-ip/mosquitto_auth_by_ip.c b/plugins/examples/auth-by-ip/mosquitto_auth_by_ip.c index 6a6f6289..49cc0178 100644 --- a/plugins/examples/auth-by-ip/mosquitto_auth_by_ip.c +++ b/plugins/examples/auth-by-ip/mosquitto_auth_by_ip.c @@ -32,7 +32,7 @@ Contributors: * * Note that this only works on Mosquitto 2.0 or later. */ - +#include "config.h" #include #include @@ -49,6 +49,9 @@ static int basic_auth_callback(int event, void *event_data, void *userdata) struct mosquitto_evt_basic_auth *ed = event_data; const char *ip_address; + UNUSED(event); + UNUSED(userdata); + ip_address = mosquitto_client_address(ed->client); if(!strcmp(ip_address, "127.0.0.1")){ /* Only allow connections from localhost */ @@ -72,11 +75,19 @@ int mosquitto_plugin_version(int supported_version_count, const int *supported_v int mosquitto_plugin_init(mosquitto_plugin_id_t *identifier, void **user_data, struct mosquitto_opt *opts, int opt_count) { + UNUSED(user_data); + UNUSED(opts); + UNUSED(opt_count); + mosq_pid = identifier; return mosquitto_callback_register(mosq_pid, MOSQ_EVT_BASIC_AUTH, basic_auth_callback, NULL, NULL); } int mosquitto_plugin_cleanup(void *user_data, struct mosquitto_opt *opts, int opt_count) { + UNUSED(user_data); + UNUSED(opts); + UNUSED(opt_count); + return mosquitto_callback_unregister(mosq_pid, MOSQ_EVT_BASIC_AUTH, basic_auth_callback, NULL); } diff --git a/plugins/examples/message-timestamp/CMakeLists.txt b/plugins/examples/message-timestamp/CMakeLists.txt index 5949a75f..e53a4bc0 100644 --- a/plugins/examples/message-timestamp/CMakeLists.txt +++ b/plugins/examples/message-timestamp/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/include - ${STDBOOL_H_PATH} ${STDINT_H_PATH}) + ${OPENSSL_INCLUDE_DIR} ${STDBOOL_H_PATH} ${STDINT_H_PATH}) add_library(mosquitto_message_timestamp SHARED mosquitto_message_timestamp.c) set_target_properties(mosquitto_message_timestamp PROPERTIES diff --git a/plugins/examples/payload-modification/CMakeLists.txt b/plugins/examples/payload-modification/CMakeLists.txt index 39878efc..a4492911 100644 --- a/plugins/examples/payload-modification/CMakeLists.txt +++ b/plugins/examples/payload-modification/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/include - ${STDBOOL_H_PATH} ${STDINT_H_PATH}) + ${OPENSSL_INCLUDE_DIR} ${STDBOOL_H_PATH} ${STDINT_H_PATH}) link_directories(${mosquitto_SOURCE_DIR}) add_library(mosquitto_payload_modification SHARED mosquitto_payload_modification.c) diff --git a/set-version.sh b/set-version.sh index a96b6a77..af1fc52d 100755 --- a/set-version.sh +++ b/set-version.sh @@ -2,7 +2,7 @@ MAJOR=2 MINOR=0 -REVISION=8 +REVISION=10 sed -i "s/^VERSION=.*/VERSION=${MAJOR}.${MINOR}.${REVISION}/" config.mk diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 0099409a..1ca29c0f 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: mosquitto -version: 2.0.8 +version: 2.0.10 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/src/CMakeLists.txt b/src/CMakeLists.txt index 29b07d28..cbb2f631 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,11 @@ if (WITH_BUNDLED_DEPS) include_directories(${mosquitto_SOURCE_DIR} ${mosquitto_SOURCE_DIR}/deps) endif (WITH_BUNDLED_DEPS) +find_path(HAVE_SYS_EPOLL_H sys/epoll.h) +if (HAVE_SYS_EPOLL_H) + add_definitions("-DWITH_EPOLL") +endif() + option(INC_BRIDGE_SUPPORT "Include bridge support for connecting to other brokers?" ON) if (INC_BRIDGE_SUPPORT) diff --git a/src/bridge.c b/src/bridge.c index 079479e2..4825850a 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -101,6 +101,7 @@ static struct mosquitto *bridge__new(struct mosquitto__bridge *bridge) new_context->tls_alpn = bridge->tls_alpn; new_context->tls_engine = db.config->default_listener.tls_engine; new_context->tls_keyform = db.config->default_listener.tls_keyform; + new_context->ssl_ctx_defaults = true; #ifdef FINAL_WITH_TLS_PSK new_context->tls_psk_identity = bridge->tls_psk_identity; new_context->tls_psk = bridge->tls_psk; @@ -372,10 +373,8 @@ int bridge__connect_step3(struct mosquitto *context) rc = send__connect(context, context->keepalive, context->clean_start, topic_alias_max_prop); if(rc == MOSQ_ERR_SUCCESS){ - bridge__backoff_reset(context); return MOSQ_ERR_SUCCESS; }else if(rc == MOSQ_ERR_ERRNO && errno == ENOTCONN){ - bridge__backoff_reset(context); return MOSQ_ERR_SUCCESS; }else{ if(rc == MOSQ_ERR_TLS){ @@ -524,10 +523,8 @@ int bridge__connect(struct mosquitto *context) rc2 = send__connect(context, context->keepalive, context->clean_start, topic_alias_max_prop); if(rc2 == MOSQ_ERR_SUCCESS){ - bridge__backoff_reset(context); return rc; }else if(rc2 == MOSQ_ERR_ERRNO && errno == ENOTCONN){ - bridge__backoff_reset(context); return MOSQ_ERR_SUCCESS; }else{ if(rc2 == MOSQ_ERR_TLS){ @@ -632,6 +629,8 @@ int bridge__on_connect(struct mosquitto *context) } } + bridge__backoff_reset(context); + return MOSQ_ERR_SUCCESS; } @@ -791,11 +790,11 @@ void bridge__packet_cleanup(struct mosquitto *context) packet__cleanup(&(context->in_packet)); } -static int rand_between(int base, int cap) +static int rand_between(int low, int high) { int r; util__random_bytes(&r, sizeof(int)); - return (r % (cap - base)) + base; + return (abs(r) % (high - low)) + low; } static void bridge__backoff_step(struct mosquitto *context) @@ -830,6 +829,33 @@ static void bridge__backoff_reset(struct mosquitto *context) } } + +static void bridge_check_pending(struct mosquitto *context) +{ + int err; + socklen_t len; + + if(context->state == mosq_cs_connect_pending){ + len = sizeof(int); + if(!getsockopt(context->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &len)){ + if(err == 0){ + mosquitto__set_state(context, mosq_cs_new); +#if defined(WITH_ADNS) && defined(WITH_BRIDGE) + if(context->bridge){ + bridge__connect_step3(context); + } +#endif + }else if(err == ECONNREFUSED){ + do_disconnect(context, MOSQ_ERR_CONN_LOST); + return; + } + }else{ + do_disconnect(context, MOSQ_ERR_CONN_LOST); + return; + } + } +} + static bool reload_if_needed(struct mosquitto *context) { int i; @@ -864,6 +890,7 @@ void bridge_check(void) if(context->sock != INVALID_SOCKET){ mosquitto__check_keepalive(context); + bridge_check_pending(context); /* Check for bridges that are not round robin and not currently * connected to their primary broker. */ diff --git a/src/conf.c b/src/conf.c index 8b8190da..b3cb1494 100644 --- a/src/conf.c +++ b/src/conf.c @@ -539,7 +539,7 @@ int config__parse_args(struct mosquitto__config *config, int argc, char *argv[]) return config__check(config); } -void config__copy(struct mosquitto__config *src, struct mosquitto__config *dest) +static void config__copy(struct mosquitto__config *src, struct mosquitto__config *dest) { int i; @@ -748,7 +748,7 @@ int config__read(struct mosquitto__config *config, bool reload) } -int config__read_file_core(struct mosquitto__config *config, bool reload, struct config_recurse *cr, int level, int *lineno, FILE *fptr, char **buf, int *buflen) +static int config__read_file_core(struct mosquitto__config *config, bool reload, struct config_recurse *cr, int level, int *lineno, FILE *fptr, char **buf, int *buflen) { int rc; char *token; diff --git a/src/conf_includedir.c b/src/conf_includedir.c index 5dda0a1e..9673ca5f 100644 --- a/src/conf_includedir.c +++ b/src/conf_includedir.c @@ -50,7 +50,7 @@ Contributors: #include "mqtt_protocol.h" -int scmp_p(const void *p1, const void *p2) +static int scmp_p(const void *p1, const void *p2) { const char *s1 = *(const char **)p1; const char *s2 = *(const char **)p2; diff --git a/src/database.c b/src/database.c index 6947987a..9ac0ac63 100644 --- a/src/database.c +++ b/src/database.c @@ -582,7 +582,7 @@ int db__message_update_outgoing(struct mosquitto *context, uint16_t mid, enum mo } -void db__messages_delete_list(struct mosquitto_client_msg **head) +static void db__messages_delete_list(struct mosquitto_client_msg **head) { struct mosquitto_client_msg *tail, *tmp; @@ -626,7 +626,7 @@ int db__messages_delete(struct mosquitto *context, bool force_free) int db__messages_easy_queue(struct mosquitto *context, const char *topic, uint8_t qos, uint32_t payloadlen, const void *payload, int retain, uint32_t message_expiry_interval, mosquitto_property **properties) { struct mosquitto_msg_store *stored; - char *source_id; + const char *source_id; enum mosquitto_msg_origin origin; if(!topic) return MOSQ_ERR_INVAL; @@ -754,7 +754,7 @@ int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosqu /* Called on reconnect to set outgoing messages to a sensible state and force a * retry, and to set incoming messages to expect an appropriate retry. */ -int db__message_reconnect_reset_outgoing(struct mosquitto *context) +static int db__message_reconnect_reset_outgoing(struct mosquitto *context) { struct mosquitto_client_msg *msg, *tmp; @@ -823,7 +823,7 @@ int db__message_reconnect_reset_outgoing(struct mosquitto *context) /* Called on reconnect to set incoming messages to expect an appropriate retry. */ -int db__message_reconnect_reset_incoming(struct mosquitto *context) +static int db__message_reconnect_reset_incoming(struct mosquitto *context) { struct mosquitto_client_msg *msg, *tmp; @@ -895,6 +895,26 @@ int db__message_reconnect_reset(struct mosquitto *context) } +int db__message_remove_incoming(struct mosquitto* context, uint16_t mid) +{ + struct mosquitto_client_msg *tail, *tmp; + + if(!context) return MOSQ_ERR_INVAL; + + DL_FOREACH_SAFE(context->msgs_in.inflight, tail, tmp){ + if(tail->mid == mid) { + if(tail->store->qos != 2){ + return MOSQ_ERR_PROTOCOL; + } + db__message_remove(&context->msgs_in, tail); + return MOSQ_ERR_SUCCESS; + } + } + + return MOSQ_ERR_NOT_FOUND; +} + + int db__message_release_incoming(struct mosquitto *context, uint16_t mid) { struct mosquitto_client_msg *tail, *tmp; @@ -957,63 +977,6 @@ int db__message_release_incoming(struct mosquitto *context, uint16_t mid) } } -int db__message_write_inflight_in(struct mosquitto *context) -{ - struct mosquitto_client_msg *tail, *tmp; - int rc; - - if(context->state != mosq_cs_active){ - return MOSQ_ERR_SUCCESS; - } - - DL_FOREACH_SAFE(context->msgs_in.inflight, tail, tmp){ - if(tail->store->message_expiry_time){ - if(db.now_real_s > tail->store->message_expiry_time){ - /* Message is expired, must not send. */ - db__message_remove(&context->msgs_in, tail); - if(tail->qos > 0){ - util__increment_receive_quota(context); - } - continue; - } - } - - switch(tail->state){ - case mosq_ms_send_pubrec: - rc = send__pubrec(context, tail->mid, 0, NULL); - if(!rc){ - tail->state = mosq_ms_wait_for_pubrel; - }else{ - return rc; - } - break; - - case mosq_ms_resend_pubcomp: - rc = send__pubcomp(context, tail->mid, NULL); - if(!rc){ - tail->state = mosq_ms_wait_for_pubrel; - }else{ - return rc; - } - break; - - case mosq_ms_invalid: - case mosq_ms_publish_qos0: - case mosq_ms_publish_qos1: - case mosq_ms_publish_qos2: - case mosq_ms_resend_pubrel: - case mosq_ms_wait_for_puback: - case mosq_ms_wait_for_pubrec: - case mosq_ms_wait_for_pubrel: - case mosq_ms_wait_for_pubcomp: - case mosq_ms_queued: - break; - } - } - return MOSQ_ERR_SUCCESS; -} - - 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_connack.c b/src/handle_connack.c index a3e59145..27c55bc1 100644 --- a/src/handle_connack.c +++ b/src/handle_connack.c @@ -40,7 +40,7 @@ int handle__connack(struct mosquitto *context) uint8_t retain_available; uint8_t max_qos = 255; - if(!context){ + if(context == NULL || context->bridge == NULL){ return MOSQ_ERR_INVAL; } log__printf(NULL, MOSQ_LOG_DEBUG, "Received CONNACK on connection %s.", context->id); diff --git a/src/handle_connect.c b/src/handle_connect.c index 041f5a2e..28c6f399 100644 --- a/src/handle_connect.c +++ b/src/handle_connect.c @@ -83,7 +83,7 @@ static char *client_id_gen(uint16_t *idlen, const char *auto_id_prefix, uint16_t /* Remove any queued messages that are no longer allowed through ACL, * assuming a possible change of username. */ -void connection_check_acl(struct mosquitto *context, struct mosquitto_client_msg **head) +static void connection_check_acl(struct mosquitto *context, struct mosquitto_client_msg **head) { struct mosquitto_client_msg *msg_tail, *tmp; @@ -111,6 +111,8 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1 uint8_t connect_ack = 0; int i; int rc; + int in_quota, out_quota; + uint16_t in_maximum, out_maximum; /* Find if this client already has an entry. This must be done *after* any security checks. */ HASH_FIND(hh_id, db.contexts_by_id, context->id, strlen(context->id), found_context); @@ -135,12 +137,22 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1 if(found_context->msgs_in.inflight || found_context->msgs_in.queued || found_context->msgs_out.inflight || found_context->msgs_out.queued){ + in_quota = context->msgs_in.inflight_quota; + out_quota = context->msgs_out.inflight_quota; + in_maximum = context->msgs_in.inflight_maximum; + out_maximum = context->msgs_out.inflight_maximum; + memcpy(&context->msgs_in, &found_context->msgs_in, sizeof(struct mosquitto_msg_data)); memcpy(&context->msgs_out, &found_context->msgs_out, sizeof(struct mosquitto_msg_data)); memset(&found_context->msgs_in, 0, sizeof(struct mosquitto_msg_data)); memset(&found_context->msgs_out, 0, sizeof(struct mosquitto_msg_data)); + context->msgs_in.inflight_quota = in_quota; + context->msgs_out.inflight_quota = out_quota; + context->msgs_in.inflight_maximum = in_maximum; + context->msgs_out.inflight_maximum = out_maximum; + db__message_reconnect_reset(context); } context->subs = found_context->subs; @@ -244,7 +256,9 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1 goto error; } } - if(context->keepalive > db.config->max_keepalive){ + if(db.config->max_keepalive && + (context->keepalive > db.config->max_keepalive || context->keepalive == 0)){ + context->keepalive = db.config->max_keepalive; if(mosquitto_property_add_int16(&connack_props, MQTT_PROP_SERVER_KEEP_ALIVE, context->keepalive)){ rc = MOSQ_ERR_NOMEM; diff --git a/src/handle_publish.c b/src/handle_publish.c index a19e3c63..2b1b948c 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -285,6 +285,18 @@ int handle__publish(struct mosquitto *context) if(msg->qos > 0){ db__message_store_find(context, msg->source_mid, &stored); } + + if(stored && msg->source_mid != 0 && + (stored->qos != msg->qos + || stored->payloadlen != msg->payloadlen + || strcmp(stored->topic, msg->topic) + || memcmp(stored->payload, msg->payload, msg->payloadlen) )){ + + log__printf(NULL, MOSQ_LOG_WARNING, "Reused message ID %u from %s detected. Clearing from storage.", msg->source_mid, context->id); + db__message_remove_incoming(context, msg->source_mid); + stored = NULL; + } + if(!stored){ if(msg->qos > 0 && context->msgs_in.inflight_quota == 0){ /* Client isn't allowed any more incoming messages, so fail early */ diff --git a/src/listeners.c b/src/listeners.c index 7d3d214f..3ea1d299 100644 --- a/src/listeners.c +++ b/src/listeners.c @@ -56,7 +56,7 @@ void listeners__reload_all_certificates(void) } -int listeners__start_single_mqtt(struct mosquitto__listener *listener) +static int listeners__start_single_mqtt(struct mosquitto__listener *listener) { int i; struct mosquitto__listener_sock *listensock_new; @@ -124,7 +124,7 @@ void listeners__add_websockets(struct lws_context *ws_context, mosq_sock_t fd) #endif -int listeners__add_local(const char *host, uint16_t port) +static int listeners__add_local(const char *host, uint16_t port) { struct mosquitto__listener *listeners; listeners = db.config->listeners; @@ -146,7 +146,7 @@ int listeners__add_local(const char *host, uint16_t port) } -int listeners__start_local_only(void) +static int listeners__start_local_only(void) { /* Attempt to open listeners bound to 127.0.0.1 and ::1 only */ int i; @@ -163,6 +163,7 @@ int listeners__start_local_only(void) log__printf(NULL, MOSQ_LOG_WARNING, "Starting in local only mode. Connections will only be possible from clients running on this machine."); log__printf(NULL, MOSQ_LOG_WARNING, "Create a configuration file which defines a listener to allow remote access."); + log__printf(NULL, MOSQ_LOG_WARNING, "For more details see https://mosquitto.org/documentation/authentication-methods/"); if(db.config->cmd_port_count == 0){ rc = listeners__add_local("127.0.0.1", 1883); if(rc == MOSQ_ERR_NOMEM) return MOSQ_ERR_NOMEM; diff --git a/src/logging.c b/src/logging.c index ff1a5b4d..cfac6a20 100644 --- a/src/logging.c +++ b/src/logging.c @@ -34,6 +34,7 @@ Contributors: #include #endif +#include "logging_mosq.h" #include "mosquitto_broker_internal.h" #include "memory_mosq.h" #include "misc_mosq.h" @@ -186,7 +187,7 @@ DltLogLevelType get_dlt_level(unsigned int priority) } #endif -int log__vprintf(unsigned int priority, const char *fmt, va_list va) +static int log__vprintf(unsigned int priority, const char *fmt, va_list va) { const char *topic; int syslog_priority; diff --git a/src/loop.c b/src/loop.c index daee31c2..3b80df2e 100644 --- a/src/loop.c +++ b/src/loop.c @@ -133,7 +133,7 @@ static void read_message_expiry_interval(mosquitto_property **proplist, uint32_t } } -void queue_plugin_msgs(void) +static void queue_plugin_msgs(void) { struct mosquitto_message_v5 *msg, *tmp; struct mosquitto *context; @@ -282,7 +282,7 @@ int mosquitto_main_loop(struct mosquitto__listener_sock *listensock, int listens void do_disconnect(struct mosquitto *context, int reason) { - char *id; + const char *id; #ifdef WITH_WEBSOCKETS bool is_duplicate = false; #endif diff --git a/src/mosquitto.c b/src/mosquitto.c index a2a9a50e..5955a232 100644 --- a/src/mosquitto.c +++ b/src/mosquitto.c @@ -73,13 +73,6 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_INFO; #endif -void handle_sigint(int signal); -void handle_sigusr1(int signal); -void handle_sigusr2(int signal); -#ifdef SIGHUP -void handle_sighup(int signal); -#endif - /* mosquitto shouldn't run as root. * This function will attempt to change to an unprivileged user and group if * running as root. The user is given in config->user. @@ -145,7 +138,7 @@ int drop_privileges(struct mosquitto__config *config) return MOSQ_ERR_SUCCESS; } -void mosquitto__daemonise(void) +static void mosquitto__daemonise(void) { #ifndef WIN32 char *err; @@ -193,7 +186,7 @@ void signal__setup(void) } -int pid__write(void) +static int pid__write(void) { FILE *pid; diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 6a68088e..c572af38 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -34,6 +34,7 @@ Contributors: #include "mosquitto_broker.h" #include "mosquitto_plugin.h" #include "mosquitto.h" +#include "logging_mosq.h" #include "password_mosq.h" #include "tls_mosq.h" #include "uthash.h" @@ -660,6 +661,7 @@ int persist__restore(void); int db__message_count(int *count); int db__message_delete_outgoing(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_state expect_state, int qos); int db__message_insert(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_direction dir, uint8_t qos, bool retain, struct mosquitto_msg_store *stored, mosquitto_property *properties, bool update); +int db__message_remove_incoming(struct mosquitto* context, uint16_t mid); int db__message_release_incoming(struct mosquitto *context, uint16_t mid); int db__message_update_outgoing(struct mosquitto *context, uint16_t mid, enum mosquitto_msg_state state, int qos); void db__message_dequeue_first(struct mosquitto *context, struct mosquitto_msg_data *msg_data); @@ -726,7 +728,6 @@ int control__unregister_callback(struct mosquitto__security_options *opts, MOSQ_ * ============================================================ */ int log__init(struct mosquitto__config *config); int log__close(struct mosquitto__config *config); -int log__printf(struct mosquitto *mosq, unsigned int level, const char *fmt, ...) __attribute__((format(printf, 3, 4))); void log__internal(const char *fmt, ...) __attribute__((format(printf, 1, 2))); /* ============================================================ @@ -772,10 +773,7 @@ void listeners__reload_all_certificates(void); #ifdef WITH_WEBSOCKETS void listeners__add_websockets(struct lws_context *ws_context, mosq_sock_t fd); #endif -int listeners__add_local(const char *host, uint16_t port); int listeners__start(void); -int listeners__start_local_only(void); -int listeners__start_single_mqtt(struct mosquitto__listener *listener); void listeners__stop(void); /* ============================================================ @@ -845,6 +843,16 @@ void session_expiry__remove_all(void); void session_expiry__check(void); void session_expiry__send_all(void); +/* ============================================================ + * Signals + * ============================================================ */ +void handle_sigint(int signal); +void handle_sigusr1(int signal); +void handle_sigusr2(int signal); +#ifdef SIGHUP +void handle_sighup(int signal); +#endif + /* ============================================================ * Window service and signal related functions * ============================================================ */ diff --git a/src/mux_epoll.c b/src/mux_epoll.c index b87aec38..0d7ce4d0 100644 --- a/src/mux_epoll.c +++ b/src/mux_epoll.c @@ -72,12 +72,6 @@ int mux_epoll__init(struct mosquitto__listener_sock *listensock, int listensock_ return MOSQ_ERR_SUCCESS; } -int mux_epoll__loop_setup(void) -{ - return MOSQ_ERR_SUCCESS; -} - - int mux_epoll__add_out(struct mosquitto *context) { struct epoll_event ev; diff --git a/src/net.c b/src/net.c index 2c7b0cf8..74fdebae 100644 --- a/src/net.c +++ b/src/net.c @@ -427,7 +427,7 @@ int net__tls_server_ctx(struct mosquitto__listener *listener) #endif -int net__load_crl_file(struct mosquitto__listener *listener) +static int net__load_crl_file(struct mosquitto__listener *listener) { #ifdef WITH_TLS X509_STORE *store; @@ -624,23 +624,44 @@ static int net__bind_interface(struct mosquitto__listener *listener, struct addr && ifa->ifa_addr->sa_family == rp->ai_addr->sa_family){ if(rp->ai_addr->sa_family == AF_INET){ - memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr, - &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, - sizeof(struct in_addr)); + if(listener->host && + memcmp(&((struct sockaddr_in *)rp->ai_addr)->sin_addr, + &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, + sizeof(struct in_addr))){ - freeifaddrs(ifaddr); - return MOSQ_ERR_SUCCESS; + log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface address for %s does not match specified listener address (%s).", + listener->bind_interface, listener->host); + return MOSQ_ERR_INVAL; + }else{ + memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr, + &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, + sizeof(struct in_addr)); + + freeifaddrs(ifaddr); + return MOSQ_ERR_SUCCESS; + } }else if(rp->ai_addr->sa_family == AF_INET6){ - memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, - &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, - sizeof(struct in6_addr)); - freeifaddrs(ifaddr); - return MOSQ_ERR_SUCCESS; + if(listener->host && + memcmp(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, + &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, + sizeof(struct in6_addr))){ + + log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface address for %s does not match specified listener address (%s).", + listener->bind_interface, listener->host); + return MOSQ_ERR_INVAL; + }else{ + memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, + &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, + sizeof(struct in6_addr)); + freeifaddrs(ifaddr); + return MOSQ_ERR_SUCCESS; + } } } } freeifaddrs(ifaddr); - log__printf(NULL, MOSQ_LOG_ERR, "Error: Interface %s not found.", listener->bind_interface); + log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Interface %s does not support %s configuration.", + listener->bind_interface, rp->ai_addr->sa_family == AF_INET ? "IPv4" : "IPv6"); return MOSQ_ERR_NOT_FOUND; } #endif @@ -654,6 +675,9 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener) char service[10]; int rc; int ss_opt = 1; +#ifndef WIN32 + bool interface_bound = false; +#endif if(!listener) return MOSQ_ERR_INVAL; @@ -718,16 +742,24 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener) #ifndef WIN32 if(listener->bind_interface){ + /* It might be possible that an interface does not support all relevant sa_families. + * We should successfully find at least one. */ if(net__bind_interface(listener, rp)){ COMPAT_CLOSE(sock); - freeaddrinfo(ainfo); - mosquitto__free(listener->socks); - return 1; + listener->sock_count--; + continue; } + interface_bound = true; } #endif if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){ +#if defined(__linux__) + if(errno == EACCES){ + log__printf(NULL, MOSQ_LOG_ERR, "If you are trying to bind to a privileged port (<1024), try using setcap and do not start the broker as root:"); + log__printf(NULL, MOSQ_LOG_ERR, " sudo setcap 'CAP_NET_BIND_SERVICE=+ep /usr/sbin/mosquitto'"); + } +#endif net__print_error(MOSQ_LOG_ERR, "Error: %s"); COMPAT_CLOSE(sock); freeaddrinfo(ainfo); @@ -745,6 +777,13 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener) } freeaddrinfo(ainfo); +#ifndef WIN32 + if(listener->bind_interface && !interface_bound){ + mosquitto__free(listener->socks); + return 1; + } +#endif + return 0; } diff --git a/src/persist.h b/src/persist.h index 21c0e679..35081770 100644 --- a/src/persist.h +++ b/src/persist.h @@ -19,6 +19,8 @@ Contributors: #ifndef PERSIST_H #define PERSIST_H +#include "mosquitto_broker_internal.h" + #define MOSQ_DB_VERSION 6 /* DB read/write */ diff --git a/src/security.c b/src/security.c index 839ec31e..98b4d962 100644 --- a/src/security.c +++ b/src/security.c @@ -47,7 +47,7 @@ void LIB_ERROR(void) } -int security__load_v2(struct mosquitto__auth_plugin *plugin, struct mosquitto_auth_opt *auth_options, int auth_option_count, void *lib) +static int security__load_v2(struct mosquitto__auth_plugin *plugin, struct mosquitto_auth_opt *auth_options, int auth_option_count, void *lib) { int rc; @@ -121,7 +121,7 @@ int security__load_v2(struct mosquitto__auth_plugin *plugin, struct mosquitto_au } -int security__load_v3(struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *auth_options, int auth_option_count, void *lib) +static int security__load_v3(struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *auth_options, int auth_option_count, void *lib) { int rc; @@ -194,7 +194,7 @@ int security__load_v3(struct mosquitto__auth_plugin *plugin, struct mosquitto_op } -int security__load_v4(struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *auth_options, int auth_option_count, void *lib) +static int security__load_v4(struct mosquitto__auth_plugin *plugin, struct mosquitto_opt *auth_options, int auth_option_count, void *lib) { int rc; diff --git a/src/security_default.c b/src/security_default.c index ec96e319..e659e7bf 100644 --- a/src/security_default.c +++ b/src/security_default.c @@ -202,7 +202,7 @@ int mosquitto_security_cleanup_default(bool reload) } -int add__acl(struct mosquitto__security_options *security_opts, const char *user, const char *topic, int access) +static int add__acl(struct mosquitto__security_options *security_opts, const char *user, const char *topic, int access) { struct mosquitto__acl_user *acl_user=NULL, *user_tail; struct mosquitto__acl *acl, *acl_tail; @@ -298,7 +298,7 @@ int add__acl(struct mosquitto__security_options *security_opts, const char *user return MOSQ_ERR_SUCCESS; } -int add__acl_pattern(struct mosquitto__security_options *security_opts, const char *topic, int access) +static int add__acl_pattern(struct mosquitto__security_options *security_opts, const char *topic, int access) { struct mosquitto__acl *acl, *acl_tail; char *local_topic; diff --git a/src/signals.c b/src/signals.c index 9938996f..82d911be 100644 --- a/src/signals.c +++ b/src/signals.c @@ -29,6 +29,8 @@ Contributors: #include #include +#include "mosquitto_broker_internal.h" + #ifdef WITH_PERSISTENCE extern bool flag_db_backup; #endif diff --git a/test/broker/01-connect-connack-2163.py b/test/broker/01-connect-connack-2163.py new file mode 100755 index 00000000..8f0297f1 --- /dev/null +++ b/test/broker/01-connect-connack-2163.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +# Test https://github.com/eclipse/mosquitto/issues/2163 +# Does the broker cope with a malformed CONNACK sent to it after a valid CONNECT? + +from mosq_test_helper import * + +def do_test(proto_ver): + rc = 1 + keepalive = 10 + connect_packet = mosq_test.gen_connect("connect-connack-2163", keepalive=keepalive, proto_ver=proto_ver) + connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver) + connack_malformed = struct.pack("BBBBB", 0x02, 0x00, 0x01, 0xE0, 0x00) + connack_malformed = struct.pack("BBBB", 0x29, 0x02, 0x00, 0x01) + pingreq_packet = mosq_test.gen_pingreq() + + port = mosq_test.get_port() + broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) + + try: + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + sock.send(connack_malformed) + try: + mosq_test.do_send_receive(sock, pingreq_packet, b"", "pingreq") + except ConnectionResetError: + pass + sock.close() + + # Does the broker still exist? + sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) + mosq_test.do_ping(sock) + sock.close() + + rc = 0 + except mosq_test.TestError: + pass + finally: + broker.terminate() + broker.wait() + (stdo, stde) = broker.communicate() + if rc: + print(stde.decode('utf-8')) + print("proto_ver=%d" % (proto_ver)) + exit(rc) + + +do_test(proto_ver=3) +do_test(proto_ver=4) +do_test(proto_ver=5) +exit(0) diff --git a/test/broker/Makefile b/test/broker/Makefile index 9eeb2d70..fad0f00b 100644 --- a/test/broker/Makefile +++ b/test/broker/Makefile @@ -22,6 +22,7 @@ test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 13 14 01 : ./01-connect-allow-anonymous.py ./01-connect-bad-packet.py + ./01-connect-connack-2163.py ./01-connect-disconnect-v5.py ./01-connect-duplicate.py ./01-connect-invalid-id-0.py diff --git a/test/broker/test.py b/test/broker/test.py index d2ccf4f1..a535d2f3 100755 --- a/test/broker/test.py +++ b/test/broker/test.py @@ -7,6 +7,7 @@ tests = [ #(ports required, 'path'), (1, './01-connect-allow-anonymous.py'), (1, './01-connect-bad-packet.py'), + (1, './01-connect-connack-2163.py'), (1, './01-connect-disconnect-v5.py'), (1, './01-connect-duplicate.py'), (1, './01-connect-invalid-id-0.py'), diff --git a/www/pages/documentation/dynamic-security.md b/www/pages/documentation/dynamic-security.md index 922c38d5..331c2dbf 100644 --- a/www/pages/documentation/dynamic-security.md +++ b/www/pages/documentation/dynamic-security.md @@ -343,7 +343,9 @@ application. The initial configuration is the only time that `mosquitto_ctrl` does not connect to a broker to carry out the configuration. All other commands require a connection to a broker, and hence a username, password, and whatever else is -required for that particular connection. +required for that particular connection. It is strongly recommended that your +broker connection uses encryption so that your configuration, including new +passwords, is not transmitted in plain text. The connection options must be given before the `dynsec` part of the command line: @@ -357,10 +359,118 @@ For example: mosquitto_ctrl -u admin -h localhost dynsec ... ``` -It is possible to provide the admin password on the command line, but this is -not recommended. +It is possible to provide the admin password on the command line using `-P +password`, but this is not recommended. If you do not provide a password, +mosquitto_ctrl will ask you to enter the password when it is needed. + +### Using an options file + +For convenience, mosquitto_ctrl can load an options file which contains a list +of options it should use. This means you can set the encryption options, host, +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`. + +You may override this behaviour by manually specifying an options file with +`-o `. + +The options file should contain a list of options, one per line, exactly as +they would be provided on the command line. For example: + +``` +--cafile /path/to/my/CA.crt +--certfile /path/to/my/client.crt +--keyfile /path/to/my/client.key +-u admin +-h mosquitto.example.com + +``` + +### mosquitto_ctrl options + +* `-A address` : Bind the outgoing connection to a local ip address/hostname. + Use this argument if you need to restrict network communication to a + particular interface. +* `--cafile path-to-ca.crt` : Define the path to a file containing PEM encoded + CA certificates that are trusted. Used to enable SSL communication. See also + `--capath` +* `--capath` : Define the path to a directory containing PEM encoded CA + certificates that are trusted. Used to enable SSL communication. For + `--capath` to work correctly, the certificate files must have ".crt" as the + file ending and you must run `openssl rehash ` each time you + add/remove a certificate. See also `--cafile`. +* `--cert path-to-client.crt` : Define the path to a file containing a PEM + encoded certificate for this client, if required by the server. See also + `--key`. +* `--ciphers` : An openssl compatible list of TLS ciphers to support in the + client. See ciphers(1) for more information. +* `-d` : Enable debug messages. +* `--help` : Display usage information. +* `-h hostname` : Specify the host to connect to. Defaults to localhost. +* `-i client-id` : The id to use for this client. If not given, a client id + will be generated depending on the MQTT version being used. For v3.1.1/v3.1, + the client generates a client id in the format mosq-XXXXXXXXXXXXXXXXXX, where + the X are replaced with random alphanumeric characters. For v5.0, the client + sends a zero length client id, and the server will generate a client id for + the client. +* `--insecure` : When using certificate based encryption, this option disables + verification of the server hostname in the server certificate. This can be + useful when testing initial server configurations but makes it possible for a + malicious third party to impersonate your server through DNS spoofing, for + example. Use this option in testing only. If you need to resort to using this + option in a production environment, your setup is at fault and there is no + point using encryption. +* `--key path-to-client.key` : Define the path to a file containing a PEM + encoded private key for this client, if required by the server. See also + `--cert`. +* `-L url` : Specify specify user, password, hostname, port and topic at once + as a URL. The URL must be in the form: + `mqtt(s)://[username[:password]@]host[:port]`. If the scheme is mqtt:// then + the port defaults to 1883. If the scheme is mqtts:// then the port defaults + to 8883. +* `--nodelay` : Disable Nagle's algorithm for the socket. This means that + latency of sent messages is reduced, which is particularly noticable for + small, reasonably infrequent messages. Using this option may result in more + packets being sent than would normally be necessary. +* `-p port` : Connect to the port specified. If not given, the default of 1883 + for plain MQTT or 8883 for MQTT over TLS will be used. +* `-P password` : Provide a password to be used for authenticating with the + broker. Using this argument without also specifying a username is invalid + when using MQTT v3.1 or v3.1.1. See also the `-u` option. +* `--proxy proxy-url` : Specify a SOCKS5 proxy to connect through. "None" and + "username" authentication types are supported. The socks-url must be of the + form `socks5h://[username[:password]@]host[:port]`. The protocol prefix + socks5h means that hostnames are resolved by the proxy. The symbols %25, %3A + and %40 are URL decoded into %, : and @ respectively, if present in the + username or password. If username is not given, then no authentication is + attempted. If the port is not given, then the default of 1080 is used. +* `--psk key` : Provide the hexadecimal (no leading 0x) pre-shared-key matching + the one used on the broker to use TLS-PSK encryption support. + `--psk-identity` must also be provided to enable TLS-PSK. +* `--psk-identity identify` : The client identity to use with TLS-PSK support. + This may be used instead of a username if the broker is configured to do so. +* `-q qos` : Specify the quality of service to use for messages, from 0, 1 and + 2. Defaults to 1. +* `--quiet` : If this argument is given, no runtime errors will be printed. + This excludes any error messages given in case of invalid user input (e.g. + using `-p` without a port). +* `--tls-version version` : Choose which TLS protocol version to use when + communicating with the broker. Valid options are tlsv1.3, tlsv1.2 and + tlsv1.1. The default value is tlsv1.2. Must match the protocol version used + by the broker. +* `-u username` : Provide a username to be used for authenticating with the + broker. See also the `-P` argument. +* `--unix path` : Connect to a broker through a local unix domain socket + instead of a TCP socket. This is a replacement for `-h` and `-L`. For + example: `mosquitto_ctrl --unix /tmp/mosquitto.sock ...`. +* `-V protocol-version` : Specify which version of the MQTT protocol should be + used when connecting to the remote broker. Can be `5`, `311`, `31`, or the + more verbose `mqttv5`, `mqttv311`, or `mqttv31`. Defaults to `311`. -See **FIXME** for the full list of options available for `mosquitto_ctrl`. ## Configuring default access diff --git a/www/pages/download.md b/www/pages/download.md index 0d16e248..974476d3 100644 --- a/www/pages/download.md +++ b/www/pages/download.md @@ -1,7 +1,7 @@ + +Versions 2.0.9, 1.6.14, and 1.5.11 of Mosquitto have been released. These are +bugfix releases and include a minor security fix. + +# 2.0.9 + +## Security +- If an empty or invalid CA file was provided to the client library for + verifying the remote broker, then the initial connection would fail but + subsequent connections would succeed without verifying the remote broker + certificate. Closes [#2130]. +- If an empty or invalid CA file was provided to the broker for verifying the + remote broker for an outgoing bridge connection then the initial connection + would fail but subsequent connections would succeed without verifying the + remote broker certificate. Closes [#2130]. + +## Broker +- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile` + is empty or invalid. Closes [#2130]. +- Fix `tls_version` behaviour not matching documentation. It was setting the + exact TLS version to use, not the minimium TLS version to use. Closes [#2110]. +- Fix messages to `$` prefixed topics being rejected. Closes [#2111]. +- Fix QoS 0 messages not being delivered when max_queued_bytes was configured. + Closes [#2123]. +- Fix bridge increasing backoff calculation. +- Improve handling of invalid combinations of listener address and bind + interface configurations. Closes [#2081]. +- Fix `max_keepalive` option not applying to clients connecting with keepalive + set to 0. Closes [#2117]. + +## Client library +- Fix encrypted connections incorrectly connecting when the CA file passed to + `mosquitto_tls_set()` is empty or invalid. Closes [#2130]. +- Fix connections retrying very rapidly in some situations. + +## Build +- Fix cmake epoll detection. + +# 1.6.14 + +## Security +- If an empty or invalid CA file was provided to the client library for + verifying the remote broker, then the initial connection would fail but + subsequent connections would succeed without verifying the remote broker + certificate. Closes [#2130]. +- If an empty or invalid CA file was provided to the broker for verifying the + remote broker for an outgoing bridge connection then the initial connection + would fail but subsequent connections would succeed without verifying the + remote broker certificate. Closes [#2130]. + +## Broker +- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile` + is empty or invalid. Closes [#2130]. + +## Client library +- Fix encrypted connections incorrectly connecting when the CA file passed to + `mosquitto_tls_set()` is empty or invalid. Closes [#2130]. +- Fix connections retrying very rapidly in some situations. + +## Clients +- Fix possible loss of data in `mosquitto_pub -l` when sending multiple long + lines. Closes [#2078]. + +# 1.5.11 + +## Security +- If an empty or invalid CA file was provided to the client library for + verifying the remote broker, then the initial connection would fail but + subsequent connections would succeed without verifying the remote broker + certificate. Closes [#2130]. +- If an empty or invalid CA file was provided to the broker for verifying the + remote broker for an outgoing bridge connection then the initial connection + would fail but subsequent connections would succeed without verifying the + remote broker certificate. Closes [#2130]. + +## Broker +- Fix encrypted bridge connections incorrectly connecting when `bridge_cafile` + is empty or invalid. Closes [#2130]. + +## Client library +- Fix encrypted connections incorrectly connecting when the CA file passed to + `mosquitto_tls_set()` is empty or invalid. Closes [#2130]. + +[#2040]: https://github.com/eclipse/mosquitto/issues/2040 +[#2078]: https://github.com/eclipse/mosquitto/issues/2078 +[#2081]: https://github.com/eclipse/mosquitto/issues/2081 +[#2110]: https://github.com/eclipse/mosquitto/issues/2110 +[#2111]: https://github.com/eclipse/mosquitto/issues/2111 +[#2117]: https://github.com/eclipse/mosquitto/issues/2117 +[#2123]: https://github.com/eclipse/mosquitto/issues/2123 +[#2130]: https://github.com/eclipse/mosquitto/issues/2130 diff --git a/www/posts/2021/04/version-2-0-10-released.md b/www/posts/2021/04/version-2-0-10-released.md new file mode 100644 index 00000000..096dc7ab --- /dev/null +++ b/www/posts/2021/04/version-2-0-10-released.md @@ -0,0 +1,49 @@ + + +Versions 2.0.10 of Mosquitto has been released. This is a security and bugfix +release. + +# Security +- [CVE-2021-23980]: If an authenticated client connected with MQTT v5 sent a + malformed CONNACK message to the broker a NULL pointer dereference occurred, + most likely resulting in a segfault. This will be updated with the CVE + number when it is assigned. + Affects versions 2.0.0 to 2.0.9 inclusive. + +# Broker +- Don't overwrite new receive-maximum if a v5 client connects and takes over + an old session. Closes [#2134]. +- Fix CVE-xxxx-xxxx. Closes [#2163]. + +# Clients +- Set `receive-maximum` to not exceed the `-C` message count in mosquitto_sub + and mosquitto_rr, to avoid potentially lost messages. Closes [#2134]. +- Fix TLS-PSK mode not working with port 8883. Closes [#2152]. + +# Client library +- Fix possible socket leak. This would occur if a client was using + `mosquitto_loop_start()`, then if the connection failed due to the remote + server being inaccessible they called `mosquitto_loop_stop(, true)` and + recreated the mosquitto object. + +# Build +- A variety of minor build related fixes, like functions not having previous + declarations. +- Fix CMake cross compile builds not finding opensslconf.h. Closes [#2160]. +- Fix build on Solaris non-sparc. Closes [#2136]. + +[CVE-2021-23980]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-28166 +[#2134]: https://github.com/eclipse/mosquitto/issues/2134 +[#2136]: https://github.com/eclipse/mosquitto/issues/2136 +[#2152]: https://github.com/eclipse/mosquitto/issues/2152 +[#2160]: https://github.com/eclipse/mosquitto/issues/2160 +[#2163]: https://github.com/eclipse/mosquitto/issues/2163